Browse Source

Add missing files

Panagiotis Christopoulos Charitos 3 years ago
parent
commit
923f6e200c
100 changed files with 11488 additions and 0 deletions
  1. 10 0
      ThirdParty/Glslang/External/spirv-tools/docker-compose.yml
  2. 9 0
      ThirdParty/Glslang/External/spirv-tools/external/spirv-headers/SPIRV-Headers.pc.in
  3. 171 0
      ThirdParty/Glslang/External/spirv-tools/external/spirv-headers/include/spirv/unified1/NonSemanticShaderDebugInfo100.h
  4. 713 0
      ThirdParty/Glslang/External/spirv-tools/external/spirv-headers/include/spirv/unified1/extinst.nonsemantic.shader.debuginfo.100.grammar.json
  5. 48 0
      ThirdParty/Glslang/External/spirv-tools/include/spirv-tools/linter.hpp
  6. 24 0
      ThirdParty/Glslang/External/spirv-tools/kokoro/linux-clang-ubsan/build.sh
  7. 16 0
      ThirdParty/Glslang/External/spirv-tools/kokoro/linux-clang-ubsan/continuous.cfg
  8. 16 0
      ThirdParty/Glslang/External/spirv-tools/kokoro/linux-clang-ubsan/presubmit.cfg
  9. 64 0
      ThirdParty/Glslang/External/spirv-tools/source/common_debug_info.h
  10. 191 0
      ThirdParty/Glslang/External/spirv-tools/source/fuzz/available_instructions.cpp
  11. 111 0
      ThirdParty/Glslang/External/spirv-tools/source/fuzz/available_instructions.h
  12. 75 0
      ThirdParty/Glslang/External/spirv-tools/source/fuzz/fuzzer_pass_permute_function_variables.cpp
  13. 38 0
      ThirdParty/Glslang/External/spirv-tools/source/fuzz/fuzzer_pass_permute_function_variables.h
  14. 53 0
      ThirdParty/Glslang/External/spirv-tools/source/fuzz/fuzzer_pass_swap_functions.cpp
  15. 38 0
      ThirdParty/Glslang/External/spirv-tools/source/fuzz/fuzzer_pass_swap_functions.h
  16. 144 0
      ThirdParty/Glslang/External/spirv-tools/source/fuzz/fuzzer_pass_wrap_vector_synonym.cpp
  17. 38 0
      ThirdParty/Glslang/External/spirv-tools/source/fuzz/fuzzer_pass_wrap_vector_synonym.h
  18. 93 0
      ThirdParty/Glslang/External/spirv-tools/source/fuzz/transformation_swap_function_variables.cpp
  19. 57 0
      ThirdParty/Glslang/External/spirv-tools/source/fuzz/transformation_swap_function_variables.h
  20. 72 0
      ThirdParty/Glslang/External/spirv-tools/source/fuzz/transformation_swap_two_functions.cpp
  21. 56 0
      ThirdParty/Glslang/External/spirv-tools/source/fuzz/transformation_swap_two_functions.h
  22. 200 0
      ThirdParty/Glslang/External/spirv-tools/source/fuzz/transformation_wrap_vector_synonym.cpp
  23. 80 0
      ThirdParty/Glslang/External/spirv-tools/source/fuzz/transformation_wrap_vector_synonym.h
  24. 61 0
      ThirdParty/Glslang/External/spirv-tools/source/lint/CMakeLists.txt
  25. 245 0
      ThirdParty/Glslang/External/spirv-tools/source/lint/divergence_analysis.cpp
  26. 163 0
      ThirdParty/Glslang/External/spirv-tools/source/lint/divergence_analysis.h
  27. 169 0
      ThirdParty/Glslang/External/spirv-tools/source/lint/lint_divergent_derivatives.cpp
  28. 60 0
      ThirdParty/Glslang/External/spirv-tools/source/lint/linter.cpp
  29. 34 0
      ThirdParty/Glslang/External/spirv-tools/source/lint/lints.h
  30. 156 0
      ThirdParty/Glslang/External/spirv-tools/source/opt/control_dependence.cpp
  31. 197 0
      ThirdParty/Glslang/External/spirv-tools/source/opt/control_dependence.h
  32. 437 0
      ThirdParty/Glslang/External/spirv-tools/source/opt/convert_to_sampled_image_pass.cpp
  33. 207 0
      ThirdParty/Glslang/External/spirv-tools/source/opt/convert_to_sampled_image_pass.h
  34. 91 0
      ThirdParty/Glslang/External/spirv-tools/source/opt/dataflow.cpp
  35. 148 0
      ThirdParty/Glslang/External/spirv-tools/source/opt/dataflow.h
  36. 117 0
      ThirdParty/Glslang/External/spirv-tools/source/opt/desc_sroa_util.cpp
  37. 54 0
      ThirdParty/Glslang/External/spirv-tools/source/opt/desc_sroa_util.h
  38. 146 0
      ThirdParty/Glslang/External/spirv-tools/source/opt/eliminate_dead_input_components_pass.cpp
  39. 59 0
      ThirdParty/Glslang/External/spirv-tools/source/opt/eliminate_dead_input_components_pass.h
  40. 124 0
      ThirdParty/Glslang/External/spirv-tools/source/opt/interp_fixup_pass.cpp
  41. 54 0
      ThirdParty/Glslang/External/spirv-tools/source/opt/interp_fixup_pass.h
  42. 49 0
      ThirdParty/Glslang/External/spirv-tools/source/opt/remove_dontinline_pass.cpp
  43. 42 0
      ThirdParty/Glslang/External/spirv-tools/source/opt/remove_dontinline_pass.h
  44. 93 0
      ThirdParty/Glslang/External/spirv-tools/source/opt/remove_unused_interface_variables_pass.cpp
  45. 26 0
      ThirdParty/Glslang/External/spirv-tools/source/opt/remove_unused_interface_variables_pass.h
  46. 427 0
      ThirdParty/Glslang/External/spirv-tools/source/opt/replace_desc_array_access_using_var_index.cpp
  47. 204 0
      ThirdParty/Glslang/External/spirv-tools/source/opt/replace_desc_array_access_using_var_index.h
  48. 314 0
      ThirdParty/Glslang/External/spirv-tools/source/opt/spread_volatile_semantics.cpp
  49. 110 0
      ThirdParty/Glslang/External/spirv-tools/source/opt/spread_volatile_semantics.h
  50. 115 0
      ThirdParty/Glslang/External/spirv-tools/source/opt/strip_nonsemantic_info_pass.cpp
  51. 44 0
      ThirdParty/Glslang/External/spirv-tools/source/opt/strip_nonsemantic_info_pass.h
  52. 67 0
      ThirdParty/Glslang/External/spirv-tools/source/reduce/structured_construct_to_block_reduction_opportunity.cpp
  53. 49 0
      ThirdParty/Glslang/External/spirv-tools/source/reduce/structured_construct_to_block_reduction_opportunity.h
  54. 185 0
      ThirdParty/Glslang/External/spirv-tools/source/reduce/structured_construct_to_block_reduction_opportunity_finder.cpp
  55. 57 0
      ThirdParty/Glslang/External/spirv-tools/source/reduce/structured_construct_to_block_reduction_opportunity_finder.h
  56. 53 0
      ThirdParty/Glslang/External/spirv-tools/source/util/hash_combine.h
  57. 236 0
      ThirdParty/Glslang/External/spirv-tools/source/util/pooled_linked_list.h
  58. 43 0
      ThirdParty/Glslang/External/spirv-tools/source/wasm/README.md
  59. 78 0
      ThirdParty/Glslang/External/spirv-tools/source/wasm/build.sh
  60. 17 0
      ThirdParty/Glslang/External/spirv-tools/source/wasm/package.json
  61. 94 0
      ThirdParty/Glslang/External/spirv-tools/source/wasm/spirv-tools.cpp
  62. 57 0
      ThirdParty/Glslang/External/spirv-tools/source/wasm/spirv-tools.d.ts
  63. 328 0
      ThirdParty/Glslang/External/spirv-tools/test/fuzz/available_instructions_test.cpp
  64. 1807 0
      ThirdParty/Glslang/External/spirv-tools/test/fuzz/fuzzerutil_test.cpp
  65. 288 0
      ThirdParty/Glslang/External/spirv-tools/test/fuzz/transformation_swap_function_variables_test.cpp
  66. 257 0
      ThirdParty/Glslang/External/spirv-tools/test/fuzz/transformation_swap_two_functions_test.cpp
  67. 1553 0
      ThirdParty/Glslang/External/spirv-tools/test/fuzz/transformation_wrap_vector_synonym_test.cpp
  68. 56 0
      ThirdParty/Glslang/External/spirv-tools/test/fuzzers/CMakeLists.txt
  69. BIN
      ThirdParty/Glslang/External/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_000.spv
  70. BIN
      ThirdParty/Glslang/External/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_001.spv
  71. BIN
      ThirdParty/Glslang/External/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_002.spv
  72. BIN
      ThirdParty/Glslang/External/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_003.spv
  73. BIN
      ThirdParty/Glslang/External/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_004.spv
  74. BIN
      ThirdParty/Glslang/External/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_005.spv
  75. BIN
      ThirdParty/Glslang/External/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_006.spv
  76. BIN
      ThirdParty/Glslang/External/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_007.spv
  77. BIN
      ThirdParty/Glslang/External/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_008.spv
  78. BIN
      ThirdParty/Glslang/External/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_009.spv
  79. BIN
      ThirdParty/Glslang/External/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_010.spv
  80. BIN
      ThirdParty/Glslang/External/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_011.spv
  81. BIN
      ThirdParty/Glslang/External/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_012.spv
  82. BIN
      ThirdParty/Glslang/External/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_013.spv
  83. BIN
      ThirdParty/Glslang/External/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_014.spv
  84. BIN
      ThirdParty/Glslang/External/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_015.spv
  85. BIN
      ThirdParty/Glslang/External/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_016.spv
  86. BIN
      ThirdParty/Glslang/External/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_017.spv
  87. BIN
      ThirdParty/Glslang/External/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_018.spv
  88. BIN
      ThirdParty/Glslang/External/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_019.spv
  89. BIN
      ThirdParty/Glslang/External/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_020.spv
  90. BIN
      ThirdParty/Glslang/External/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_021.spv
  91. BIN
      ThirdParty/Glslang/External/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_022.spv
  92. BIN
      ThirdParty/Glslang/External/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_023.spv
  93. BIN
      ThirdParty/Glslang/External/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_024.spv
  94. BIN
      ThirdParty/Glslang/External/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_025.spv
  95. BIN
      ThirdParty/Glslang/External/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_026.spv
  96. BIN
      ThirdParty/Glslang/External/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_027.spv
  97. BIN
      ThirdParty/Glslang/External/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_028.spv
  98. BIN
      ThirdParty/Glslang/External/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_029.spv
  99. BIN
      ThirdParty/Glslang/External/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_030.spv
  100. BIN
      ThirdParty/Glslang/External/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_031.spv

+ 10 - 0
ThirdParty/Glslang/External/spirv-tools/docker-compose.yml

@@ -0,0 +1,10 @@
+version: "3"
+services:
+  build:
+    image: emscripten/emsdk:2.0.2
+    environment:
+      GITHUB_RUN_NUMBER: ${GITHUB_RUN_NUMBER:-}
+    working_dir: /app
+    command: ./source/wasm/build.sh
+    volumes:
+      - ./:/app

+ 9 - 0
ThirdParty/Glslang/External/spirv-tools/external/spirv-headers/SPIRV-Headers.pc.in

@@ -0,0 +1,9 @@
+prefix=@CMAKE_INSTALL_PREFIX@
+includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@
+
+Name: SPIRV-Headers
+Description: Header files from the SPIR-V registry
+Version: @CMAKE_PROJECT_VERSION@
+Requires:
+Libs:
+Cflags: -I${includedir}

+ 171 - 0
ThirdParty/Glslang/External/spirv-tools/external/spirv-headers/include/spirv/unified1/NonSemanticShaderDebugInfo100.h

@@ -0,0 +1,171 @@
+// Copyright (c) 2018 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"),
+// to deal in the Materials without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Materials, and to permit persons to whom the
+// Materials are furnished to do so, subject to the following conditions:
+// 
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Materials.
+// 
+// MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS KHRONOS
+// STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS SPECIFICATIONS AND
+// HEADER INFORMATION ARE LOCATED AT https://www.khronos.org/registry/ 
+// 
+// THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM,OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE USE OR OTHER DEALINGS
+// IN THE MATERIALS.
+
+#ifndef SPIRV_UNIFIED1_NonSemanticShaderDebugInfo100_H_
+#define SPIRV_UNIFIED1_NonSemanticShaderDebugInfo100_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum {
+    NonSemanticShaderDebugInfo100Version = 100,
+    NonSemanticShaderDebugInfo100Version_BitWidthPadding = 0x7fffffff
+};
+enum {
+    NonSemanticShaderDebugInfo100Revision = 6,
+    NonSemanticShaderDebugInfo100Revision_BitWidthPadding = 0x7fffffff
+};
+
+enum NonSemanticShaderDebugInfo100Instructions {
+    NonSemanticShaderDebugInfo100DebugInfoNone = 0,
+    NonSemanticShaderDebugInfo100DebugCompilationUnit = 1,
+    NonSemanticShaderDebugInfo100DebugTypeBasic = 2,
+    NonSemanticShaderDebugInfo100DebugTypePointer = 3,
+    NonSemanticShaderDebugInfo100DebugTypeQualifier = 4,
+    NonSemanticShaderDebugInfo100DebugTypeArray = 5,
+    NonSemanticShaderDebugInfo100DebugTypeVector = 6,
+    NonSemanticShaderDebugInfo100DebugTypedef = 7,
+    NonSemanticShaderDebugInfo100DebugTypeFunction = 8,
+    NonSemanticShaderDebugInfo100DebugTypeEnum = 9,
+    NonSemanticShaderDebugInfo100DebugTypeComposite = 10,
+    NonSemanticShaderDebugInfo100DebugTypeMember = 11,
+    NonSemanticShaderDebugInfo100DebugTypeInheritance = 12,
+    NonSemanticShaderDebugInfo100DebugTypePtrToMember = 13,
+    NonSemanticShaderDebugInfo100DebugTypeTemplate = 14,
+    NonSemanticShaderDebugInfo100DebugTypeTemplateParameter = 15,
+    NonSemanticShaderDebugInfo100DebugTypeTemplateTemplateParameter = 16,
+    NonSemanticShaderDebugInfo100DebugTypeTemplateParameterPack = 17,
+    NonSemanticShaderDebugInfo100DebugGlobalVariable = 18,
+    NonSemanticShaderDebugInfo100DebugFunctionDeclaration = 19,
+    NonSemanticShaderDebugInfo100DebugFunction = 20,
+    NonSemanticShaderDebugInfo100DebugLexicalBlock = 21,
+    NonSemanticShaderDebugInfo100DebugLexicalBlockDiscriminator = 22,
+    NonSemanticShaderDebugInfo100DebugScope = 23,
+    NonSemanticShaderDebugInfo100DebugNoScope = 24,
+    NonSemanticShaderDebugInfo100DebugInlinedAt = 25,
+    NonSemanticShaderDebugInfo100DebugLocalVariable = 26,
+    NonSemanticShaderDebugInfo100DebugInlinedVariable = 27,
+    NonSemanticShaderDebugInfo100DebugDeclare = 28,
+    NonSemanticShaderDebugInfo100DebugValue = 29,
+    NonSemanticShaderDebugInfo100DebugOperation = 30,
+    NonSemanticShaderDebugInfo100DebugExpression = 31,
+    NonSemanticShaderDebugInfo100DebugMacroDef = 32,
+    NonSemanticShaderDebugInfo100DebugMacroUndef = 33,
+    NonSemanticShaderDebugInfo100DebugImportedEntity = 34,
+    NonSemanticShaderDebugInfo100DebugSource = 35,
+    NonSemanticShaderDebugInfo100DebugFunctionDefinition = 101,
+    NonSemanticShaderDebugInfo100DebugSourceContinued = 102,
+    NonSemanticShaderDebugInfo100DebugLine = 103,
+    NonSemanticShaderDebugInfo100DebugNoLine = 104,
+    NonSemanticShaderDebugInfo100DebugBuildIdentifier = 105,
+    NonSemanticShaderDebugInfo100DebugStoragePath = 106,
+    NonSemanticShaderDebugInfo100DebugEntryPoint = 107,
+    NonSemanticShaderDebugInfo100DebugTypeMatrix = 108,
+    NonSemanticShaderDebugInfo100InstructionsMax = 0x7fffffff
+};
+
+
+enum NonSemanticShaderDebugInfo100DebugInfoFlags {
+    NonSemanticShaderDebugInfo100None = 0x0000,
+    NonSemanticShaderDebugInfo100FlagIsProtected = 0x01,
+    NonSemanticShaderDebugInfo100FlagIsPrivate = 0x02,
+    NonSemanticShaderDebugInfo100FlagIsPublic = 0x03,
+    NonSemanticShaderDebugInfo100FlagIsLocal = 0x04,
+    NonSemanticShaderDebugInfo100FlagIsDefinition = 0x08,
+    NonSemanticShaderDebugInfo100FlagFwdDecl = 0x10,
+    NonSemanticShaderDebugInfo100FlagArtificial = 0x20,
+    NonSemanticShaderDebugInfo100FlagExplicit = 0x40,
+    NonSemanticShaderDebugInfo100FlagPrototyped = 0x80,
+    NonSemanticShaderDebugInfo100FlagObjectPointer = 0x100,
+    NonSemanticShaderDebugInfo100FlagStaticMember = 0x200,
+    NonSemanticShaderDebugInfo100FlagIndirectVariable = 0x400,
+    NonSemanticShaderDebugInfo100FlagLValueReference = 0x800,
+    NonSemanticShaderDebugInfo100FlagRValueReference = 0x1000,
+    NonSemanticShaderDebugInfo100FlagIsOptimized = 0x2000,
+    NonSemanticShaderDebugInfo100FlagIsEnumClass = 0x4000,
+    NonSemanticShaderDebugInfo100FlagTypePassByValue = 0x8000,
+    NonSemanticShaderDebugInfo100FlagTypePassByReference = 0x10000,
+    NonSemanticShaderDebugInfo100FlagUnknownPhysicalLayout = 0x20000,
+    NonSemanticShaderDebugInfo100DebugInfoFlagsMax = 0x7fffffff
+};
+
+enum NonSemanticShaderDebugInfo100BuildIdentifierFlags {
+    NonSemanticShaderDebugInfo100IdentifierPossibleDuplicates = 0x01,
+    NonSemanticShaderDebugInfo100BuildIdentifierFlagsMax = 0x7fffffff
+};
+
+enum NonSemanticShaderDebugInfo100DebugBaseTypeAttributeEncoding {
+    NonSemanticShaderDebugInfo100Unspecified = 0,
+    NonSemanticShaderDebugInfo100Address = 1,
+    NonSemanticShaderDebugInfo100Boolean = 2,
+    NonSemanticShaderDebugInfo100Float = 3,
+    NonSemanticShaderDebugInfo100Signed = 4,
+    NonSemanticShaderDebugInfo100SignedChar = 5,
+    NonSemanticShaderDebugInfo100Unsigned = 6,
+    NonSemanticShaderDebugInfo100UnsignedChar = 7,
+    NonSemanticShaderDebugInfo100DebugBaseTypeAttributeEncodingMax = 0x7fffffff
+};
+
+enum NonSemanticShaderDebugInfo100DebugCompositeType {
+    NonSemanticShaderDebugInfo100Class = 0,
+    NonSemanticShaderDebugInfo100Structure = 1,
+    NonSemanticShaderDebugInfo100Union = 2,
+    NonSemanticShaderDebugInfo100DebugCompositeTypeMax = 0x7fffffff
+};
+
+enum NonSemanticShaderDebugInfo100DebugTypeQualifier {
+    NonSemanticShaderDebugInfo100ConstType = 0,
+    NonSemanticShaderDebugInfo100VolatileType = 1,
+    NonSemanticShaderDebugInfo100RestrictType = 2,
+    NonSemanticShaderDebugInfo100AtomicType = 3,
+    NonSemanticShaderDebugInfo100DebugTypeQualifierMax = 0x7fffffff
+};
+
+enum NonSemanticShaderDebugInfo100DebugOperation {
+    NonSemanticShaderDebugInfo100Deref = 0,
+    NonSemanticShaderDebugInfo100Plus = 1,
+    NonSemanticShaderDebugInfo100Minus = 2,
+    NonSemanticShaderDebugInfo100PlusUconst = 3,
+    NonSemanticShaderDebugInfo100BitPiece = 4,
+    NonSemanticShaderDebugInfo100Swap = 5,
+    NonSemanticShaderDebugInfo100Xderef = 6,
+    NonSemanticShaderDebugInfo100StackValue = 7,
+    NonSemanticShaderDebugInfo100Constu = 8,
+    NonSemanticShaderDebugInfo100Fragment = 9,
+    NonSemanticShaderDebugInfo100DebugOperationMax = 0x7fffffff
+};
+
+enum NonSemanticShaderDebugInfo100DebugImportedEntity {
+    NonSemanticShaderDebugInfo100ImportedModule = 0,
+    NonSemanticShaderDebugInfo100ImportedDeclaration = 1,
+    NonSemanticShaderDebugInfo100DebugImportedEntityMax = 0x7fffffff
+};
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // SPIRV_UNIFIED1_NonSemanticShaderDebugInfo100_H_

+ 713 - 0
ThirdParty/Glslang/External/spirv-tools/external/spirv-headers/include/spirv/unified1/extinst.nonsemantic.shader.debuginfo.100.grammar.json

@@ -0,0 +1,713 @@
+{
+  "copyright" : [
+    "Copyright (c) 2018 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\"),",
+    "to deal in the Materials without restriction, including without limitation",
+    "the rights to use, copy, modify, merge, publish, distribute, sublicense,",
+    "and/or sell copies of the Materials, and to permit persons to whom the",
+    "Materials are furnished to do so, subject to the following conditions:",
+    "",
+    "The above copyright notice and this permission notice shall be included in",
+    "all copies or substantial portions of the Materials.",
+    "",
+    "MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS KHRONOS",
+    "STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS SPECIFICATIONS AND",
+    "HEADER INFORMATION ARE LOCATED AT https://www.khronos.org/registry/ ",
+    "",
+    "THE MATERIALS ARE PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS",
+    "OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,",
+    "FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL",
+    "THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER",
+    "LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING",
+    "FROM,OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE USE OR OTHER DEALINGS",
+    "IN THE MATERIALS."
+  ],
+  "version" : 100,
+  "revision" : 6,
+  "instructions" : [
+    {
+      "opname" : "DebugInfoNone",
+      "opcode" : 0
+    },
+    {
+      "opname" : "DebugCompilationUnit",
+      "opcode" : 1,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'Version'" },
+        { "kind" : "IdRef", "name" : "'DWARF Version'" },
+        { "kind" : "IdRef", "name" : "'Source'" },
+        { "kind" : "IdRef", "name" : "'Language'" }
+      ]
+    },
+    {
+      "opname" : "DebugTypeBasic",
+      "opcode" : 2,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'Name'" },
+        { "kind" : "IdRef", "name" : "'Size'" },
+        { "kind" : "IdRef", "name" : "'Encoding'" },
+        { "kind" : "IdRef", "name" : "'Flags'" }
+      ]
+    },
+    {
+      "opname" : "DebugTypePointer",
+      "opcode" : 3,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'Base Type'" },
+        { "kind" : "IdRef", "name" : "'Storage Class'" },
+        { "kind" : "IdRef", "name" : "'Flags'" }
+      ]
+    },
+    {
+      "opname" : "DebugTypeQualifier",
+      "opcode" : 4,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'Base Type'" },
+        { "kind" : "IdRef", "name" : "'Type Qualifier'" }
+      ]
+    },
+    {
+      "opname" : "DebugTypeArray",
+      "opcode" : 5,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'Base Type'" },
+        { "kind" : "IdRef", "name" : "'Component Counts'", "quantifier" : "*" }
+      ]
+    },
+    {
+      "opname" : "DebugTypeVector",
+      "opcode" : 6,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'Base Type'" },
+        { "kind" : "IdRef", "name" : "'Component Count'" }
+      ]
+    },
+    {
+      "opname" : "DebugTypedef",
+      "opcode" : 7,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'Name'" },
+        { "kind" : "IdRef", "name" : "'Base Type'" },
+        { "kind" : "IdRef", "name" : "'Source'" },
+        { "kind" : "IdRef", "name" : "'Line'" },
+        { "kind" : "IdRef", "name" : "'Column'" },
+        { "kind" : "IdRef", "name" : "'Parent'" }
+      ]
+    },
+    {
+      "opname" : "DebugTypeFunction",
+      "opcode" : 8,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'Flags'" },
+        { "kind" : "IdRef", "name" : "'Return Type'" },
+        { "kind" : "IdRef", "name" : "'Parameter Types'", "quantifier" : "*" }
+      ]
+    },
+    {
+      "opname" : "DebugTypeEnum",
+      "opcode" : 9,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'Name'" },
+        { "kind" : "IdRef", "name" : "'Underlying Type'" },
+        { "kind" : "IdRef", "name" : "'Source'" },
+        { "kind" : "IdRef", "name" : "'Line'" },
+        { "kind" : "IdRef", "name" : "'Column'" },
+        { "kind" : "IdRef", "name" : "'Parent'" },
+        { "kind" : "IdRef", "name" : "'Size'" },
+        { "kind" : "IdRef", "name" : "'Flags'" },
+        { "kind" : "PairIdRefIdRef", "name" : "'Value, Name, Value, Name, ...'", "quantifier" : "*" }
+      ]
+    },
+    {
+      "opname" : "DebugTypeComposite",
+      "opcode" : 10,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'Name'" },
+        { "kind" : "IdRef", "name" : "'Tag'" },
+        { "kind" : "IdRef", "name" : "'Source'" },
+        { "kind" : "IdRef", "name" : "'Line'" },
+        { "kind" : "IdRef", "name" : "'Column'" },
+        { "kind" : "IdRef", "name" : "'Parent'" },
+        { "kind" : "IdRef", "name" : "'Linkage Name'" },
+        { "kind" : "IdRef", "name" : "'Size'" },
+        { "kind" : "IdRef", "name" : "'Flags'" },
+        { "kind" : "IdRef", "name" : "'Members'", "quantifier" : "*" }
+      ]
+    },
+    {
+      "opname" : "DebugTypeMember",
+      "opcode" : 11,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'Name'" },
+        { "kind" : "IdRef", "name" : "'Type'" },
+        { "kind" : "IdRef", "name" : "'Source'" },
+        { "kind" : "IdRef", "name" : "'Line'" },
+        { "kind" : "IdRef", "name" : "'Column'" },
+        { "kind" : "IdRef", "name" : "'Offset'" },
+        { "kind" : "IdRef", "name" : "'Size'" },
+        { "kind" : "IdRef", "name" : "'Flags'" },
+        { "kind" : "IdRef", "name" : "'Value'", "quantifier" : "?" }
+      ]
+    },
+    {
+      "opname" : "DebugTypeInheritance",
+      "opcode" : 12,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'Parent'" },
+        { "kind" : "IdRef", "name" : "'Offset'" },
+        { "kind" : "IdRef", "name" : "'Size'" },
+        { "kind" : "IdRef", "name" : "'Flags'" }
+      ]
+    },
+    {
+      "opname" : "DebugTypePtrToMember",
+      "opcode" : 13,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'Member Type'" },
+        { "kind" : "IdRef", "name" : "'Parent'" }
+      ]
+    },
+    {
+      "opname" : "DebugTypeTemplate",
+      "opcode" : 14,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'Target'" },
+        { "kind" : "IdRef", "name" : "'Parameters'", "quantifier" : "*" }
+      ]
+    },
+    {
+      "opname" : "DebugTypeTemplateParameter",
+      "opcode" : 15,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'Name'" },
+        { "kind" : "IdRef", "name" : "'Actual Type'" },
+        { "kind" : "IdRef", "name" : "'Value'" },
+        { "kind" : "IdRef", "name" : "'Source'" },
+        { "kind" : "IdRef", "name" : "'Line'" },
+        { "kind" : "IdRef", "name" : "'Column'" }
+      ]
+    },
+    {
+      "opname" : "DebugTypeTemplateTemplateParameter",
+      "opcode" : 16,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'Name'" },
+        { "kind" : "IdRef", "name" : "'Template Name'" },
+        { "kind" : "IdRef", "name" : "'Source'" },
+        { "kind" : "IdRef", "name" : "'Line'" },
+        { "kind" : "IdRef", "name" : "'Column'" }
+      ]
+    },
+    {
+      "opname" : "DebugTypeTemplateParameterPack",
+      "opcode" : 17,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'Name'" },
+        { "kind" : "IdRef", "name" : "'Source'" },
+        { "kind" : "IdRef", "name" : "'Line'" },
+        { "kind" : "IdRef", "name" : "'Column'" },
+        { "kind" : "IdRef", "name" : "'Template Parameters'", "quantifier" : "*" }
+      ]
+    },
+    {
+      "opname" : "DebugGlobalVariable",
+      "opcode" : 18,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'Name'" },
+        { "kind" : "IdRef", "name" : "'Type'" },
+        { "kind" : "IdRef", "name" : "'Source'" },
+        { "kind" : "IdRef", "name" : "'Line'" },
+        { "kind" : "IdRef", "name" : "'Column'" },
+        { "kind" : "IdRef", "name" : "'Parent'" },
+        { "kind" : "IdRef", "name" : "'Linkage Name'" },
+        { "kind" : "IdRef", "name" : "'Variable'" },
+        { "kind" : "IdRef", "name" : "'Flags'" },
+        { "kind" : "IdRef", "name" : "'Static Member Declaration'", "quantifier" : "?" }
+      ]
+    },
+    {
+      "opname" : "DebugFunctionDeclaration",
+      "opcode" : 19,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'Name'" },
+        { "kind" : "IdRef", "name" : "'Type'" },
+        { "kind" : "IdRef", "name" : "'Source'" },
+        { "kind" : "IdRef", "name" : "'Line'" },
+        { "kind" : "IdRef", "name" : "'Column'" },
+        { "kind" : "IdRef", "name" : "'Parent'" },
+        { "kind" : "IdRef", "name" : "'Linkage Name'" },
+        { "kind" : "IdRef", "name" : "'Flags'" }
+      ]
+    },
+    {
+      "opname" : "DebugFunction",
+      "opcode" : 20,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'Name'" },
+        { "kind" : "IdRef", "name" : "'Type'" },
+        { "kind" : "IdRef", "name" : "'Source'" },
+        { "kind" : "IdRef", "name" : "'Line'" },
+        { "kind" : "IdRef", "name" : "'Column'" },
+        { "kind" : "IdRef", "name" : "'Parent'" },
+        { "kind" : "IdRef", "name" : "'Linkage Name'" },
+        { "kind" : "IdRef", "name" : "'Flags'" },
+        { "kind" : "IdRef", "name" : "'Scope Line'" },
+        { "kind" : "IdRef", "name" : "'Declaration'", "quantifier" : "?" }
+      ]
+    },
+    {
+      "opname" : "DebugLexicalBlock",
+      "opcode" : 21,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'Source'" },
+        { "kind" : "IdRef", "name" : "'Line'" },
+        { "kind" : "IdRef", "name" : "'Column'" },
+        { "kind" : "IdRef", "name" : "'Parent'" },
+        { "kind" : "IdRef", "name" : "'Name'", "quantifier" : "?" }
+      ]
+    },
+    {
+      "opname" : "DebugLexicalBlockDiscriminator",
+      "opcode" : 22,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'Source'" },
+        { "kind" : "IdRef", "name" : "'Discriminator'" },
+        { "kind" : "IdRef", "name" : "'Parent'" }
+      ]
+    },
+    {
+      "opname" : "DebugScope",
+      "opcode" : 23,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'Scope'" },
+        { "kind" : "IdRef", "name" : "'Inlined At'", "quantifier" : "?" }
+      ]
+    },
+    {
+      "opname" : "DebugNoScope",
+      "opcode" : 24
+    },
+    {
+      "opname" : "DebugInlinedAt",
+      "opcode" : 25,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'Line'" },
+        { "kind" : "IdRef", "name" : "'Scope'" },
+        { "kind" : "IdRef", "name" : "'Inlined'", "quantifier" : "?" }
+      ]
+    },
+    {
+      "opname" : "DebugLocalVariable",
+      "opcode" : 26,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'Name'" },
+        { "kind" : "IdRef", "name" : "'Type'" },
+        { "kind" : "IdRef", "name" : "'Source'" },
+        { "kind" : "IdRef", "name" : "'Line'" },
+        { "kind" : "IdRef", "name" : "'Column'" },
+        { "kind" : "IdRef", "name" : "'Parent'" },
+        { "kind" : "IdRef", "name" : "'Flags'" },
+        { "kind" : "IdRef", "name" : "'Arg Number'", "quantifier" : "?" }
+      ]
+    },
+    {
+      "opname" : "DebugInlinedVariable",
+      "opcode" : 27,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'Variable'" },
+        { "kind" : "IdRef", "name" : "'Inlined'" }
+      ]
+    },
+    {
+      "opname" : "DebugDeclare",
+      "opcode" : 28,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'Local Variable'" },
+        { "kind" : "IdRef", "name" : "'Variable'" },
+        { "kind" : "IdRef", "name" : "'Expression'" },
+        { "kind" : "IdRef", "name" : "'Indexes'", "quantifier" : "*" }
+      ]
+    },
+    {
+      "opname" : "DebugValue",
+      "opcode" : 29,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'Local Variable'" },
+        { "kind" : "IdRef", "name" : "'Value'" },
+        { "kind" : "IdRef", "name" : "'Expression'" },
+        { "kind" : "IdRef", "name" : "'Indexes'", "quantifier" : "*" }
+      ]
+    },
+    {
+      "opname" : "DebugOperation",
+      "opcode" : 30,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'OpCode'" },
+        { "kind" : "IdRef", "name" : "'Operands ...'", "quantifier" : "*" }
+      ]
+    },
+    {
+      "opname" : "DebugExpression",
+      "opcode" : 31,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'Operands ...'", "quantifier" : "*" }
+      ]
+    },
+    {
+      "opname" : "DebugMacroDef",
+      "opcode" : 32,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'Source'" },
+        { "kind" : "IdRef", "name" : "'Line'" },
+        { "kind" : "IdRef", "name" : "'Name'" },
+        { "kind" : "IdRef", "name" : "'Value'", "quantifier" : "?" }
+      ]
+    },
+    {
+      "opname" : "DebugMacroUndef",
+      "opcode" : 33,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'Source'" },
+        { "kind" : "IdRef", "name" : "'Line'" },
+        { "kind" : "IdRef", "name" : "'Macro'" }
+      ]
+    },
+    {
+      "opname" : "DebugImportedEntity",
+      "opcode" : 34,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'Name'" },
+        { "kind" : "IdRef", "name" : "'Tag'" },
+        { "kind" : "IdRef", "name" : "'Source'" },
+        { "kind" : "IdRef", "name" : "'Entity'" },
+        { "kind" : "IdRef", "name" : "'Line'" },
+        { "kind" : "IdRef", "name" : "'Column'" },
+        { "kind" : "IdRef", "name" : "'Parent'" }
+      ]
+    },
+    {
+      "opname" : "DebugSource",
+      "opcode" : 35,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'File'" },
+        { "kind" : "IdRef", "name" : "'Text'", "quantifier" : "?" }
+      ]
+    },
+    {
+      "opname" : "DebugFunctionDefinition",
+      "opcode" : 101,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'Function'" },
+        { "kind" : "IdRef", "name" : "'Definition'" }
+      ]
+    },
+    {
+      "opname" : "DebugSourceContinued",
+      "opcode" : 102,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'Text'" }
+      ]
+    },
+    {
+      "opname" : "DebugLine",
+      "opcode" : 103,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'Source'" },
+        { "kind" : "IdRef", "name" : "'Line Start'" },
+        { "kind" : "IdRef", "name" : "'Line End'" },
+        { "kind" : "IdRef", "name" : "'Column Start'" },
+        { "kind" : "IdRef", "name" : "'Column End'" }
+      ]
+    },
+    {
+      "opname" : "DebugNoLine",
+      "opcode" : 104
+    },
+    {
+      "opname" : "DebugBuildIdentifier",
+      "opcode" : 105,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'Identifier'" },
+        { "kind" : "IdRef", "name" : "'Flags'" }
+      ]
+    },
+    {
+      "opname" : "DebugStoragePath",
+      "opcode" : 106,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'Path'" }
+      ]
+    },
+    {
+      "opname" : "DebugEntryPoint",
+      "opcode" : 107,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'Entry Point'" },
+        { "kind" : "IdRef", "name" : "'Compilation Unit'" },
+        { "kind" : "IdRef", "name" : "'Compiler Signature'" },
+        { "kind" : "IdRef", "name" : "'Command-line Arguments'" }
+      ]
+    },
+    {
+      "opname" : "DebugTypeMatrix",
+      "opcode" : 108,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'Vector Type'" },
+        { "kind" : "IdRef", "name" : "'Vector Count'" },
+        { "kind" : "IdRef", "name" : "'Column Major'" }
+      ]
+    }
+  ],
+  "operand_kinds" : [
+    {
+      "category" : "BitEnum",
+      "kind" : "DebugInfoFlags",
+      "enumerants" : [
+        {
+          "enumerant" : "None",
+          "value" : "0x0000"
+        },
+        {
+          "enumerant" : "FlagIsProtected",
+          "value" : "0x01"
+        },
+        {
+          "enumerant" : "FlagIsPrivate",
+          "value" : "0x02"
+        },
+        {
+          "enumerant" : "FlagIsPublic",
+          "value" : "0x03"
+        },
+        {
+          "enumerant" : "FlagIsLocal",
+          "value" : "0x04"
+        },
+        {
+          "enumerant" : "FlagIsDefinition",
+          "value" : "0x08"
+        },
+        {
+          "enumerant" : "FlagFwdDecl",
+          "value" : "0x10"
+        },
+        {
+          "enumerant" : "FlagArtificial",
+          "value" : "0x20"
+        },
+        {
+          "enumerant" : "FlagExplicit",
+          "value" : "0x40"
+        },
+        {
+          "enumerant" : "FlagPrototyped",
+          "value" : "0x80"
+        },
+        {
+          "enumerant" : "FlagObjectPointer",
+          "value" : "0x100"
+        },
+        {
+          "enumerant" : "FlagStaticMember",
+          "value" : "0x200"
+        },
+        {
+          "enumerant" : "FlagIndirectVariable",
+          "value" : "0x400"
+        },
+        {
+          "enumerant" : "FlagLValueReference",
+          "value" : "0x800"
+        },
+        {
+          "enumerant" : "FlagRValueReference",
+          "value" : "0x1000"
+        },
+        {
+          "enumerant" : "FlagIsOptimized",
+          "value" : "0x2000"
+        },
+        {
+          "enumerant" : "FlagIsEnumClass",
+          "value" : "0x4000"
+        },
+        {
+          "enumerant" : "FlagTypePassByValue",
+          "value" : "0x8000"
+        },
+        {
+          "enumerant" : "FlagTypePassByReference",
+          "value" : "0x10000"
+        },
+        {
+          "enumerant" : "FlagUnknownPhysicalLayout",
+          "value" : "0x20000"
+        }
+      ]
+    },
+    {
+      "category" : "BitEnum",
+      "kind" : "BuildIdentifierFlags",
+      "enumerants" : [
+        {
+          "enumerant" : "IdentifierPossibleDuplicates",
+          "value" : "0x01"
+        }
+      ]
+    },
+    {
+      "category" : "ValueEnum",
+      "kind" : "DebugBaseTypeAttributeEncoding",
+      "enumerants" : [
+        {
+          "enumerant" : "Unspecified",
+          "value" : "0"
+        },
+        {
+          "enumerant" : "Address",
+          "value" : "1"
+        },
+        {
+          "enumerant" : "Boolean",
+          "value" : "2"
+        },
+        {
+          "enumerant" : "Float",
+          "value" : "3"
+        },
+        {
+          "enumerant" : "Signed",
+          "value" : "4"
+        },
+        {
+          "enumerant" : "SignedChar",
+          "value" : "5"
+        },
+        {
+          "enumerant" : "Unsigned",
+          "value" : "6"
+        },
+        {
+          "enumerant" : "UnsignedChar",
+          "value" : "7"
+        }
+      ]
+    },
+    {
+      "category" : "ValueEnum",
+      "kind" : "DebugCompositeType",
+      "enumerants" : [
+        {
+          "enumerant" : "Class",
+          "value" : "0"
+        },
+        {
+          "enumerant" : "Structure",
+          "value" : "1"
+        },
+        {
+          "enumerant" : "Union",
+          "value" : "2"
+        }
+      ]
+    },
+    {
+      "category" : "ValueEnum",
+      "kind" : "DebugTypeQualifier",
+      "enumerants" : [
+        {
+          "enumerant" : "ConstType",
+          "value" : "0"
+        },
+        {
+          "enumerant" : "VolatileType",
+          "value" : "1"
+        },
+        {
+          "enumerant" : "RestrictType",
+          "value" : "2"
+        },
+        {
+          "enumerant" : "AtomicType",
+          "value" : "3"
+        }
+      ]
+    },
+    {
+      "category" : "ValueEnum",
+      "kind" : "DebugOperation",
+      "enumerants" : [
+        {
+          "enumerant" : "Deref",
+          "value" : "0"
+        },
+        {
+          "enumerant" : "Plus",
+          "value" : "1"
+        },
+        {
+          "enumerant" : "Minus",
+          "value" : "2"
+        },
+        {
+          "enumerant" : "PlusUconst",
+          "value" : "3",
+          "parameters" : [
+             { "kind" : "IdRef" }
+          ]
+        },
+        {
+          "enumerant" : "BitPiece",
+          "value" : "4",
+          "parameters" : [
+             { "kind" : "IdRef" },
+             { "kind" : "IdRef" }
+          ]
+        },
+        {
+          "enumerant" : "Swap",
+          "value" : "5"
+        },
+        {
+          "enumerant" : "Xderef",
+          "value" : "6"
+        },
+        {
+          "enumerant" : "StackValue",
+          "value" : "7"
+        },
+        {
+          "enumerant" : "Constu",
+          "value" : "8",
+          "parameters" : [
+             { "kind" : "IdRef" }
+          ]
+        },
+        {
+          "enumerant" : "Fragment",
+          "value" : "9",
+          "parameters" : [
+             { "kind" : "IdRef" },
+             { "kind" : "IdRef" }
+          ]
+        }
+      ]
+    },
+    {
+      "category" : "ValueEnum",
+      "kind" : "DebugImportedEntity",
+      "enumerants" : [
+        {
+          "enumerant" : "ImportedModule",
+          "value" : "0"
+        },
+        {
+          "enumerant" : "ImportedDeclaration",
+          "value" : "1"
+        }
+      ]
+    }
+  ]
+}

+ 48 - 0
ThirdParty/Glslang/External/spirv-tools/include/spirv-tools/linter.hpp

@@ -0,0 +1,48 @@
+// Copyright (c) 2021 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 INCLUDE_SPIRV_TOOLS_LINTER_HPP_
+#define INCLUDE_SPIRV_TOOLS_LINTER_HPP_
+
+#include "libspirv.hpp"
+
+namespace spvtools {
+
+// C++ interface for SPIR-V linting functionalities. It wraps the context
+// (including target environment and the corresponding SPIR-V grammar) and
+// provides a method for linting.
+//
+// Instances of this class provides basic thread-safety guarantee.
+class Linter {
+ public:
+  explicit Linter(spv_target_env env);
+
+  ~Linter();
+
+  // Sets the message consumer to the given |consumer|. The |consumer| will be
+  // invoked once for each message communicated from the library.
+  void SetMessageConsumer(MessageConsumer consumer);
+
+  // Returns a reference to the registered message consumer.
+  const MessageConsumer& Consumer() const;
+
+  bool Run(const uint32_t* binary, size_t binary_size);
+
+ private:
+  struct Impl;
+  std::unique_ptr<Impl> impl_;
+};
+}  // namespace spvtools
+
+#endif  // INCLUDE_SPIRV_TOOLS_LINTER_HPP_

+ 24 - 0
ThirdParty/Glslang/External/spirv-tools/kokoro/linux-clang-ubsan/build.sh

@@ -0,0 +1,24 @@
+#!/bin/bash
+# Copyright (c) 2021 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.
+#
+# Linux Build Script.
+
+# Fail on any error.
+set -e
+# Display commands being run.
+set -x
+
+SCRIPT_DIR=`dirname "$BASH_SOURCE"`
+source $SCRIPT_DIR/../scripts/linux/build.sh UBSAN clang cmake

+ 16 - 0
ThirdParty/Glslang/External/spirv-tools/kokoro/linux-clang-ubsan/continuous.cfg

@@ -0,0 +1,16 @@
+# Copyright (c) 2021 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.
+
+# Continuous build configuration.
+build_file: "SPIRV-Tools/kokoro/linux-clang-ubsan/build.sh"

+ 16 - 0
ThirdParty/Glslang/External/spirv-tools/kokoro/linux-clang-ubsan/presubmit.cfg

@@ -0,0 +1,16 @@
+# Copyright (c) 2021 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.
+
+# Presubmit build configuration.
+build_file: "SPIRV-Tools/kokoro/linux-clang-ubsan/build.sh"

+ 64 - 0
ThirdParty/Glslang/External/spirv-tools/source/common_debug_info.h

@@ -0,0 +1,64 @@
+// Copyright (c) 2021 The Khronos Group Inc.
+// Copyright (c) 2021 Valve Corporation
+// Copyright (c) 2021 LunarG Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SOURCE_COMMON_DEBUG_INFO_HEADER_H_
+#define SOURCE_COMMON_DEBUG_INFO_HEADER_H_
+
+// This enum defines the known common set of instructions that are the same
+// between OpenCL.DebugInfo.100 and NonSemantic.Shader.DebugInfo.100.
+// Note that NonSemantic.Shader.* instructions can still have slightly
+// different encoding, as it does not use literals anywhere and only constants.
+enum CommonDebugInfoInstructions {
+  CommonDebugInfoDebugInfoNone = 0,
+  CommonDebugInfoDebugCompilationUnit = 1,
+  CommonDebugInfoDebugTypeBasic = 2,
+  CommonDebugInfoDebugTypePointer = 3,
+  CommonDebugInfoDebugTypeQualifier = 4,
+  CommonDebugInfoDebugTypeArray = 5,
+  CommonDebugInfoDebugTypeVector = 6,
+  CommonDebugInfoDebugTypedef = 7,
+  CommonDebugInfoDebugTypeFunction = 8,
+  CommonDebugInfoDebugTypeEnum = 9,
+  CommonDebugInfoDebugTypeComposite = 10,
+  CommonDebugInfoDebugTypeMember = 11,
+  CommonDebugInfoDebugTypeInheritance = 12,
+  CommonDebugInfoDebugTypePtrToMember = 13,
+  CommonDebugInfoDebugTypeTemplate = 14,
+  CommonDebugInfoDebugTypeTemplateParameter = 15,
+  CommonDebugInfoDebugTypeTemplateTemplateParameter = 16,
+  CommonDebugInfoDebugTypeTemplateParameterPack = 17,
+  CommonDebugInfoDebugGlobalVariable = 18,
+  CommonDebugInfoDebugFunctionDeclaration = 19,
+  CommonDebugInfoDebugFunction = 20,
+  CommonDebugInfoDebugLexicalBlock = 21,
+  CommonDebugInfoDebugLexicalBlockDiscriminator = 22,
+  CommonDebugInfoDebugScope = 23,
+  CommonDebugInfoDebugNoScope = 24,
+  CommonDebugInfoDebugInlinedAt = 25,
+  CommonDebugInfoDebugLocalVariable = 26,
+  CommonDebugInfoDebugInlinedVariable = 27,
+  CommonDebugInfoDebugDeclare = 28,
+  CommonDebugInfoDebugValue = 29,
+  CommonDebugInfoDebugOperation = 30,
+  CommonDebugInfoDebugExpression = 31,
+  CommonDebugInfoDebugMacroDef = 32,
+  CommonDebugInfoDebugMacroUndef = 33,
+  CommonDebugInfoDebugImportedEntity = 34,
+  CommonDebugInfoDebugSource = 35,
+  CommonDebugInfoInstructionsMax = 0x7ffffff
+};
+
+#endif  // SOURCE_COMMON_DEBUG_INFO_HEADER_H_

+ 191 - 0
ThirdParty/Glslang/External/spirv-tools/source/fuzz/available_instructions.cpp

@@ -0,0 +1,191 @@
+// Copyright (c) 2021 Alastair F. Donaldson
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "source/fuzz/available_instructions.h"
+#include "source/fuzz/fuzzer_util.h"
+
+namespace spvtools {
+namespace fuzz {
+
+AvailableInstructions::AvailableInstructions(
+    opt::IRContext* ir_context,
+    const std::function<bool(opt::IRContext*, opt::Instruction*)>& predicate)
+    : ir_context_(ir_context) {
+  // Consider all global declarations
+  for (auto& global : ir_context->module()->types_values()) {
+    if (predicate(ir_context, &global)) {
+      available_globals_.push_back(&global);
+    }
+  }
+
+  // Consider every function
+  for (auto& function : *ir_context->module()) {
+    // Identify those function parameters that satisfy the predicate.
+    std::vector<opt::Instruction*> available_params_for_function;
+    function.ForEachParam(
+        [&predicate, ir_context,
+         &available_params_for_function](opt::Instruction* param) {
+          if (predicate(ir_context, param)) {
+            available_params_for_function.push_back(param);
+          }
+        });
+
+    // Consider every reachable block in the function.
+    auto dominator_analysis = ir_context->GetDominatorAnalysis(&function);
+    for (auto& block : function) {
+      if (!ir_context->IsReachable(block)) {
+        // The block is not reachable.
+        continue;
+      }
+      if (&block == &*function.begin()) {
+        // The function entry block is special: only the relevant globals and
+        // function parameters are available at its entry point.
+        num_available_at_block_entry_.insert(
+            {&block,
+             static_cast<uint32_t>(available_params_for_function.size() +
+                                   available_globals_.size())});
+      } else {
+        // |block| is not the entry block and is reachable, so it must have an
+        // immediate dominator. The number of instructions available on entry to
+        // |block| is thus the number of instructions available on entry to the
+        // immediate dominator + the number of instructions generated_by_block
+        // by the immediate dominator.
+        auto immediate_dominator =
+            dominator_analysis->ImmediateDominator(&block);
+        assert(immediate_dominator != nullptr &&
+               "The block is reachable so should have an immediate dominator.");
+        assert(generated_by_block_.count(immediate_dominator) != 0 &&
+               "Immediate dominator should have already been processed.");
+        assert(num_available_at_block_entry_.count(immediate_dominator) != 0 &&
+               "Immediate dominator should have already been processed.");
+        num_available_at_block_entry_.insert(
+            {&block,
+             static_cast<uint32_t>(
+                 generated_by_block_.at(immediate_dominator).size()) +
+                 num_available_at_block_entry_.at(immediate_dominator)});
+      }
+      // Now consider each instruction in the block.
+      std::vector<opt::Instruction*> generated_by_block;
+      for (auto& inst : block) {
+        assert(num_available_at_block_entry_.count(&block) != 0 &&
+               "Block should have already been processed.");
+        // The number of available instructions before |inst| is the number
+        // available at the start of the block + the number of relevant
+        // instructions generated by the block so far.
+        num_available_before_instruction_.insert(
+            {&inst, num_available_at_block_entry_.at(&block) +
+                        static_cast<uint32_t>(generated_by_block.size())});
+        if (predicate(ir_context, &inst)) {
+          // This instruction satisfies the predicate, so note that it is
+          // generated by |block|.
+          generated_by_block.push_back(&inst);
+        }
+      }
+      generated_by_block_.emplace(&block, std::move(generated_by_block));
+    }
+    available_params_.emplace(&function,
+                              std::move(available_params_for_function));
+  }
+}
+
+AvailableInstructions::AvailableBeforeInstruction
+AvailableInstructions::GetAvailableBeforeInstruction(
+    opt::Instruction* inst) const {
+  assert(num_available_before_instruction_.count(inst) != 0 &&
+         "Availability can only be queried for reachable instructions.");
+  return {*this, inst};
+}
+
+AvailableInstructions::AvailableBeforeInstruction::AvailableBeforeInstruction(
+    const AvailableInstructions& available_instructions, opt::Instruction* inst)
+    : available_instructions_(available_instructions), inst_(inst) {}
+
+uint32_t AvailableInstructions::AvailableBeforeInstruction::size() const {
+  return available_instructions_.num_available_before_instruction_.at(inst_);
+}
+
+bool AvailableInstructions::AvailableBeforeInstruction::empty() const {
+  return size() == 0;
+}
+
+opt::Instruction* AvailableInstructions::AvailableBeforeInstruction::operator[](
+    uint32_t index) const {
+  assert(index < size() && "Index out of bounds.");
+
+  // First, check the cache to see whether we can return the available
+  // instruction in constant time.
+  auto cached_result = index_cache.find(index);
+  if (cached_result != index_cache.end()) {
+    return cached_result->second;
+  }
+
+  // Next check whether the index falls into the global region.
+  if (index < available_instructions_.available_globals_.size()) {
+    auto result = available_instructions_.available_globals_[index];
+    index_cache.insert({index, result});
+    return result;
+  }
+
+  auto block = available_instructions_.ir_context_->get_instr_block(inst_);
+  auto function = block->GetParent();
+
+  // Next check whether the index falls into the available instructions that
+  // correspond to function parameters.
+  if (index <
+      available_instructions_.available_globals_.size() +
+          available_instructions_.available_params_.at(function).size()) {
+    auto result = available_instructions_.available_params_.at(
+        function)[index - available_instructions_.available_globals_.size()];
+    index_cache.insert({index, result});
+    return result;
+  }
+
+  auto dominator_analysis =
+      available_instructions_.ir_context_->GetDominatorAnalysis(function);
+
+  // Now the expensive part (which is why we have the cache): walk the dominator
+  // tree backwards starting from the block containing |inst_| until we get to
+  // the block in which the instruction corresponding to |index| exists.
+  for (auto* ancestor = block; true;
+       ancestor = dominator_analysis->ImmediateDominator(ancestor)) {
+    uint32_t num_available_at_ancestor_entry =
+        available_instructions_.num_available_at_block_entry_.at(ancestor);
+    if (index_cache.count(num_available_at_ancestor_entry) == 0) {
+      // This is the first time we have traversed this block, so we populate the
+      // cache with the index of each instruction, so that if a future index
+      // query relates to indices associated with this block we can return the
+      // result in constant time.
+      auto& generated_by_ancestor =
+          available_instructions_.generated_by_block_.at(ancestor);
+      for (uint32_t local_index = 0; local_index < generated_by_ancestor.size();
+           local_index++) {
+        index_cache.insert({num_available_at_ancestor_entry + local_index,
+                            generated_by_ancestor[local_index]});
+      }
+    }
+    if (index >= num_available_at_ancestor_entry) {
+      // This block contains the instruction we want, so by now it will be in
+      // the cache.
+      return index_cache.at(index);
+    }
+    assert(ancestor != &*function->begin() &&
+           "By construction we should find a block associated with the index.");
+  }
+
+  assert(false && "Unreachable.");
+  return nullptr;
+}
+
+}  // namespace fuzz
+}  // namespace spvtools

+ 111 - 0
ThirdParty/Glslang/External/spirv-tools/source/fuzz/available_instructions.h

@@ -0,0 +1,111 @@
+// Copyright (c) 2021 Alastair F. Donaldson
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SOURCE_FUZZ_AVAILABLE_INSTRUCTIONS_H_
+#define SOURCE_FUZZ_AVAILABLE_INSTRUCTIONS_H_
+
+#include <unordered_map>
+#include <vector>
+
+#include "source/opt/instruction.h"
+#include "source/opt/ir_context.h"
+
+namespace spvtools {
+namespace fuzz {
+
+// A class for allowing efficient querying of the instruction that satisfy a
+// particular predicate that are available before a given instruction.
+// Availability information is only computed for instructions in *reachable*
+// basic blocks.
+class AvailableInstructions {
+ public:
+  // The outer class captures availability information for a whole module, and
+  // each instance of this inner class captures availability for a particular
+  // instruction.
+  class AvailableBeforeInstruction {
+   public:
+    AvailableBeforeInstruction(
+        const AvailableInstructions& available_instructions,
+        opt::Instruction* inst);
+
+    // Returns the number of instructions that are available before the
+    // instruction associated with this class.
+    uint32_t size() const;
+
+    // Returns true if and only if |size()| is 0.
+    bool empty() const;
+
+    // Requires |index| < |size()|. Returns the ith available instruction.
+    opt::Instruction* operator[](uint32_t index) const;
+
+   private:
+    // A references to an instance of the outer class.
+    const AvailableInstructions& available_instructions_;
+
+    // The instruction for which availability information is captured.
+    opt::Instruction* inst_;
+
+    // A cache to improve the efficiency of the [] operator. The [] operator
+    // requires walking the instruction's dominator tree to find an instruction
+    // at a particular index, which is a linear time operation. By inserting all
+    // instructions that are traversed during this search into a cache, future
+    // lookups will take constant time unless they require traversing the
+    // dominator tree more deeply.
+    mutable std::unordered_map<uint32_t, opt::Instruction*> index_cache;
+  };
+
+  // Constructs availability instructions for |ir_context|, where instructions
+  // are only available if they satisfy |predicate|.
+  AvailableInstructions(
+      opt::IRContext* ir_context,
+      const std::function<bool(opt::IRContext*, opt::Instruction*)>& predicate);
+
+  // Yields instruction availability for |inst|.
+  AvailableBeforeInstruction GetAvailableBeforeInstruction(
+      opt::Instruction* inst) const;
+
+ private:
+  // The module in which all instructions are contained.
+  opt::IRContext* ir_context_;
+
+  // The global instructions that satisfy the predicate.
+  std::vector<opt::Instruction*> available_globals_;
+
+  // Per function, the parameters that satisfy the predicate.
+  std::unordered_map<opt::Function*, std::vector<opt::Instruction*>>
+      available_params_;
+
+  // The number of instructions that satisfy the predicate and that are
+  // available at the entry to a block. For the entry block of a function this
+  // is the number of available globals + the number of available function
+  // parameters. For any other block it is the number of available instructions
+  // for the blocks immediate dominator + the number of instructions generated
+  // by the immediate dominator.
+  std::unordered_map<opt::BasicBlock*, uint32_t> num_available_at_block_entry_;
+
+  // For each block this records those instructions in the block that satisfy
+  // the predicate.
+  std::unordered_map<opt::BasicBlock*, std::vector<opt::Instruction*>>
+      generated_by_block_;
+
+  // For each instruction this records how many instructions satisfying the
+  // predicate are available before the instruction.
+  std::unordered_map<opt::Instruction*, uint32_t>
+      num_available_before_instruction_;
+};
+
+}  // namespace fuzz
+}  // namespace spvtools
+
+#endif  // SOURCE_FUZZ_AVAILABLE_INSTRUCTIONS_H_

+ 75 - 0
ThirdParty/Glslang/External/spirv-tools/source/fuzz/fuzzer_pass_permute_function_variables.cpp

@@ -0,0 +1,75 @@
+// Copyright (c) 2021 Mostafa Ashraf
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "source/fuzz/fuzzer_pass_permute_function_variables.h"
+
+#include <algorithm>
+#include <numeric>
+#include <vector>
+
+#include "source/fuzz/fuzzer_context.h"
+#include "source/fuzz/fuzzer_util.h"
+#include "source/fuzz/instruction_descriptor.h"
+#include "source/fuzz/transformation_swap_function_variables.h"
+
+namespace spvtools {
+namespace fuzz {
+
+FuzzerPassPermuteFunctionVariables::FuzzerPassPermuteFunctionVariables(
+    opt::IRContext* ir_context, TransformationContext* transformation_context,
+    FuzzerContext* fuzzer_context,
+    protobufs::TransformationSequence* transformations,
+    bool ignore_inapplicable_transformations)
+    : FuzzerPass(ir_context, transformation_context, fuzzer_context,
+                 transformations, ignore_inapplicable_transformations) {
+}  // Here we call parent constructor.
+
+void FuzzerPassPermuteFunctionVariables::Apply() {
+  // Permuting OpVariable instructions in each function.
+  for (auto& function : *GetIRContext()->module()) {
+    if (!GetFuzzerContext()->ChoosePercentage(
+            GetFuzzerContext()->GetChanceOfPermutingFunctionVariables())) {
+      continue;
+    }
+
+    auto first_block = function.entry().get();
+
+    std::vector<opt::Instruction*> variables;
+    for (auto& instruction : *first_block) {
+      if (instruction.opcode() == SpvOpVariable) {
+        variables.push_back(&instruction);
+      }
+    }
+    if (variables.size() <= 1) {
+      continue;
+    }
+    do {
+      uint32_t instruction_1_index = GetFuzzerContext()->RandomIndex(variables);
+      uint32_t instruction_2_index = GetFuzzerContext()->RandomIndex(variables);
+
+      if (instruction_1_index != instruction_2_index) {
+        ApplyTransformation(TransformationSwapFunctionVariables(
+            variables[instruction_1_index]->result_id(),
+            variables[instruction_2_index]->result_id()));
+      }
+
+    } while (GetFuzzerContext()->ChoosePercentage(
+                 GetFuzzerContext()
+                     ->GetChanceOfSwappingAnotherPairOfFunctionVariables()) &&
+             variables.size() > 2);
+  }
+}
+
+}  // namespace fuzz
+}  // namespace spvtools

+ 38 - 0
ThirdParty/Glslang/External/spirv-tools/source/fuzz/fuzzer_pass_permute_function_variables.h

@@ -0,0 +1,38 @@
+// Copyright (c) 2021 Mostafa Ashraf
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SOURCE_FUZZ_FUZZER_PASS_PERMUTE_FUNCTION_VARIABLES_H_
+#define SOURCE_FUZZ_FUZZER_PASS_PERMUTE_FUNCTION_VARIABLES_H_
+
+#include "source/fuzz/fuzzer_pass.h"
+
+namespace spvtools {
+namespace fuzz {
+
+// This fuzzer pass permutes variables in functions in the module.
+class FuzzerPassPermuteFunctionVariables : public FuzzerPass {
+ public:
+  FuzzerPassPermuteFunctionVariables(
+      opt::IRContext* ir_context, TransformationContext* transformation_context,
+      FuzzerContext* fuzzer_context,
+      protobufs::TransformationSequence* transformations,
+      bool ignore_inapplicable_transformations);
+
+  void Apply() override;
+};
+
+}  // namespace fuzz
+}  // namespace spvtools
+
+#endif  // SOURCE_FUZZ_FUZZER_PASS_PERMUTE_FUNCTION_VARIABLES_H_

+ 53 - 0
ThirdParty/Glslang/External/spirv-tools/source/fuzz/fuzzer_pass_swap_functions.cpp

@@ -0,0 +1,53 @@
+// Copyright (c) 2021 Shiyu Liu
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "source/fuzz/fuzzer_pass_swap_functions.h"
+
+#include "source/fuzz/fuzzer_context.h"
+#include "source/fuzz/transformation_swap_two_functions.h"
+
+namespace spvtools {
+namespace fuzz {
+
+FuzzerPassSwapFunctions::FuzzerPassSwapFunctions(
+    opt::IRContext* ir_context, TransformationContext* transformation_context,
+    FuzzerContext* fuzzer_context,
+    protobufs::TransformationSequence* transformations,
+    bool ignore_inapplicable_transformations)
+    : FuzzerPass(ir_context, transformation_context, fuzzer_context,
+                 transformations, ignore_inapplicable_transformations) {}
+
+void FuzzerPassSwapFunctions::Apply() {
+  // Collect all function ids in a module.
+  std::vector<uint32_t> function_ids;
+  for (auto& function : *GetIRContext()->module()) {
+    function_ids.emplace_back(function.result_id());
+  }
+
+  // Iterate through every combination of id i & j where i!=j.
+  for (size_t i = 0; i < function_ids.size(); ++i) {
+    for (size_t j = i + 1; j < function_ids.size(); ++j) {
+      // Perform function swap randomly.
+      if (!GetFuzzerContext()->ChoosePercentage(
+              GetFuzzerContext()->GetChanceOfSwappingFunctions())) {
+        continue;
+      }
+      TransformationSwapTwoFunctions transformation(function_ids[i],
+                                                    function_ids[j]);
+    }
+  }
+}
+
+}  // namespace fuzz
+}  // namespace spvtools

+ 38 - 0
ThirdParty/Glslang/External/spirv-tools/source/fuzz/fuzzer_pass_swap_functions.h

@@ -0,0 +1,38 @@
+// Copyright (c) 2021 Shiyu Liu
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SOURCE_FUZZ_FUZZER_PASS_SWAP_FUNCTIONS_H_
+#define SOURCE_FUZZ_FUZZER_PASS_SWAP_FUNCTIONS_H_
+
+#include "source/fuzz/fuzzer_pass.h"
+
+namespace spvtools {
+namespace fuzz {
+
+// Randomly swap functions within a module.
+class FuzzerPassSwapFunctions : public FuzzerPass {
+ public:
+  FuzzerPassSwapFunctions(opt::IRContext* ir_context,
+                          TransformationContext* transformation_context,
+                          FuzzerContext* fuzzer_context,
+                          protobufs::TransformationSequence* transformations,
+                          bool ignore_inapplicable_transformations);
+
+  void Apply() override;
+};
+
+}  // namespace fuzz
+}  // namespace spvtools
+
+#endif  // SOURCE_FUZZ_FUZZER_PASS_SWAP_FUNCTIONS_H_

+ 144 - 0
ThirdParty/Glslang/External/spirv-tools/source/fuzz/fuzzer_pass_wrap_vector_synonym.cpp

@@ -0,0 +1,144 @@
+// Copyright (c) 2021 Shiyu Liu
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "source/fuzz/fuzzer_pass_wrap_vector_synonym.h"
+#include "source/fuzz/fuzzer_context.h"
+#include "source/fuzz/fuzzer_util.h"
+#include "source/fuzz/transformation_composite_construct.h"
+#include "source/fuzz/transformation_wrap_vector_synonym.h"
+
+namespace spvtools {
+namespace fuzz {
+
+FuzzerPassWrapVectorSynonym::FuzzerPassWrapVectorSynonym(
+    opt::IRContext* ir_context, TransformationContext* transformation_context,
+    FuzzerContext* fuzzer_context,
+    protobufs::TransformationSequence* transformations,
+    bool ignore_inapplicable_transformations)
+    : FuzzerPass(ir_context, transformation_context, fuzzer_context,
+                 transformations, ignore_inapplicable_transformations) {}
+
+void FuzzerPassWrapVectorSynonym::Apply() {
+  ForEachInstructionWithInstructionDescriptor(
+      [this](opt::Function* /*unused*/, opt::BasicBlock* /*unused*/,
+             opt::BasicBlock::iterator instruction_iterator,
+             const protobufs::InstructionDescriptor& instruction_descriptor)
+          -> void {
+
+        // Randomly decide whether to wrap it to a vector operation.
+        if (!GetFuzzerContext()->ChoosePercentage(
+                GetFuzzerContext()->GetChanceOfWrappingVectorSynonym())) {
+          return;
+        }
+
+        // The transformation is not applicable if the instruction has missing
+        // result id, type id, or is not supported type.
+        if (!TransformationWrapVectorSynonym::IsInstructionSupported(
+                GetIRContext(), *instruction_iterator)) {
+          return;
+        }
+
+        // It must be valid to insert an OpCompositeConstruct instruction
+        // before |instruction_iterator|.
+        if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(
+                SpvOpCompositeConstruct, instruction_iterator)) {
+          return;
+        }
+
+        // Get the scalar operands from the original instruction.
+        opt::Instruction* operand1 = GetIRContext()->get_def_use_mgr()->GetDef(
+            instruction_iterator->GetSingleWordInOperand(0));
+        opt::Instruction* operand2 = GetIRContext()->get_def_use_mgr()->GetDef(
+            instruction_iterator->GetSingleWordInOperand(1));
+
+        // We need to be able to make a synonym of the scalar operation's result
+        // id, as well as the operand ids (for example, they cannot be
+        // irrelevant).
+        if (!fuzzerutil::CanMakeSynonymOf(GetIRContext(),
+                                          *GetTransformationContext(),
+                                          *instruction_iterator)) {
+          return;
+        }
+        if (!fuzzerutil::CanMakeSynonymOf(
+                GetIRContext(), *GetTransformationContext(), *operand1)) {
+          return;
+        }
+        if (!fuzzerutil::CanMakeSynonymOf(
+                GetIRContext(), *GetTransformationContext(), *operand2)) {
+          return;
+        }
+
+        // Get a random vector size from 2 to 4.
+        uint32_t vector_size = GetFuzzerContext()->GetWidthOfWrappingVector();
+
+        // Randomly choose a position that target ids should be placed at.
+        // The position is in range [0, n - 1], where n is the size of the
+        // vector.
+        uint32_t position =
+            GetFuzzerContext()->GetRandomIndexForWrappingVector(vector_size);
+
+        // Stores the ids of scalar constants.
+        std::vector<uint32_t> vec1_components;
+        std::vector<uint32_t> vec2_components;
+
+        // Populate components based on vector type and size.
+        for (uint32_t i = 0; i < vector_size; ++i) {
+          if (i == position) {
+            vec1_components.emplace_back(operand1->result_id());
+            vec2_components.emplace_back(operand2->result_id());
+          } else {
+            vec1_components.emplace_back(
+                FindOrCreateZeroConstant(operand1->type_id(), true));
+            vec2_components.emplace_back(
+                FindOrCreateZeroConstant(operand2->type_id(), true));
+          }
+        }
+
+        // Add two OpCompositeConstruct to the module with result id returned.
+        // The added vectors may have different types, for instance if the
+        // scalar instruction operates on integers with differing sign.
+
+        // Add the first OpCompositeConstruct that wraps the id of the first
+        // operand.
+        uint32_t result_id1 = GetFuzzerContext()->GetFreshId();
+        ApplyTransformation(TransformationCompositeConstruct(
+            FindOrCreateVectorType(operand1->type_id(), vector_size),
+            vec1_components, instruction_descriptor, result_id1));
+
+        // Add the second OpCompositeConstruct that wraps the id of the second
+        // operand.
+        uint32_t result_id2 = GetFuzzerContext()->GetFreshId();
+        ApplyTransformation(TransformationCompositeConstruct(
+            FindOrCreateVectorType(operand2->type_id(), vector_size),
+            vec2_components, instruction_descriptor, result_id2));
+
+        // The result of the vector instruction that
+        // TransformationWrapVectorSynonym will create should be a vector of the
+        // right size, with the scalar instruction's result type as its element
+        // type. This can be distinct from the types of the operands, if the
+        // scalar instruction adds two signed integers and stores the result in
+        // an unsigned id, for example. A transformation is applied to add the
+        // right type to the module.
+        FindOrCreateVectorType(instruction_iterator->type_id(), vector_size);
+
+        // Apply transformation to do vector operation and add synonym between
+        // the result vector id and the id of the original instruction.
+        ApplyTransformation(TransformationWrapVectorSynonym(
+            instruction_iterator->result_id(), result_id1, result_id2,
+            GetFuzzerContext()->GetFreshId(), position));
+      });
+}
+
+}  // namespace fuzz
+}  // namespace spvtools

+ 38 - 0
ThirdParty/Glslang/External/spirv-tools/source/fuzz/fuzzer_pass_wrap_vector_synonym.h

@@ -0,0 +1,38 @@
+// Copyright (c) 2021 Shiyu Liu
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SOURCE_FUZZ_FUZZER_PASS_WRAP_VECTOR_SYNONYM_H_
+#define SOURCE_FUZZ_FUZZER_PASS_WRAP_VECTOR_SYNONYM_H_
+
+#include "source/fuzz/fuzzer_pass.h"
+
+namespace spvtools {
+namespace fuzz {
+
+// Randomly wrap a scalar operation into a vector operation.
+class FuzzerPassWrapVectorSynonym : public FuzzerPass {
+ public:
+  FuzzerPassWrapVectorSynonym(
+      opt::IRContext* ir_context, TransformationContext* transformation_context,
+      FuzzerContext* fuzzer_context,
+      protobufs::TransformationSequence* transformations,
+      bool ignore_inapplicable_transformations);
+
+  void Apply() override;
+};
+
+}  // namespace fuzz
+}  // namespace spvtools
+
+#endif  // SOURCE_FUZZ_FUZZER_PASS_WRAP_VECTOR_SYNONYM_H_

+ 93 - 0
ThirdParty/Glslang/External/spirv-tools/source/fuzz/transformation_swap_function_variables.cpp

@@ -0,0 +1,93 @@
+// Copyright (c) 2021 Mostafa Ashraf
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "source/fuzz/transformation_swap_function_variables.h"
+
+#include "source/fuzz/fuzzer_util.h"
+
+namespace spvtools {
+namespace fuzz {
+
+TransformationSwapFunctionVariables::TransformationSwapFunctionVariables(
+    protobufs::TransformationSwapFunctionVariables message)
+    : message_(std::move(message)) {}
+
+TransformationSwapFunctionVariables::TransformationSwapFunctionVariables(
+    uint32_t result_id1, uint32_t result_id2) {
+  message_.set_result_id1(result_id1);
+  message_.set_result_id2(result_id2);
+}
+
+bool TransformationSwapFunctionVariables::IsApplicable(
+    opt::IRContext* ir_context, const TransformationContext& /*unused*/) const {
+  uint32_t result_id1 = message_.result_id1();
+  uint32_t result_id2 = message_.result_id2();
+
+  assert((result_id1 != result_id2) && "Two results ids are equal");
+
+  // The result ids used in the message must refer to instructions.
+  auto instruction1 = ir_context->get_def_use_mgr()->GetDef(result_id1);
+  auto instruction2 = ir_context->get_def_use_mgr()->GetDef(result_id2);
+  if (instruction1 == nullptr || instruction2 == nullptr) {
+    return false;
+  }
+  // Both instructions must be variables.
+  if (instruction1->opcode() != SpvOpVariable ||
+      instruction2->opcode() != SpvOpVariable) {
+    return false;
+  }
+
+  // Both variable instructions must be in some basic block (as they are
+  // function-local variables), and they must be in the same block (as they need
+  // to be variables of the same function).
+  auto* block_1 = ir_context->get_instr_block(result_id1);
+  auto* block_2 = ir_context->get_instr_block(result_id2);
+  if (block_1 == nullptr || block_2 == nullptr) {
+    return false;
+  }
+
+  return block_1 == block_2;
+}
+
+void TransformationSwapFunctionVariables::Apply(
+    opt::IRContext* ir_context, TransformationContext* /*unused*/) const {
+  // The result ids used in the message must refer to instructions.
+  auto instruction1 =
+      ir_context->get_def_use_mgr()->GetDef(message_.result_id1());
+  auto instruction2 =
+      ir_context->get_def_use_mgr()->GetDef(message_.result_id2());
+
+  std::unique_ptr<opt::Instruction> temp_instruction =
+      MakeUnique<opt::Instruction>();
+
+  temp_instruction->InsertBefore(instruction1);
+  instruction1->InsertAfter(instruction2);
+  instruction2->InsertAfter(temp_instruction.get());
+  temp_instruction->RemoveFromList();
+}
+
+protobufs::Transformation TransformationSwapFunctionVariables::ToMessage()
+    const {
+  protobufs::Transformation result;
+  *result.mutable_swap_function_variables() = message_;
+  return result;
+}
+
+std::unordered_set<uint32_t> TransformationSwapFunctionVariables::GetFreshIds()
+    const {
+  return std::unordered_set<uint32_t>();
+}
+
+}  // namespace fuzz
+}  // namespace spvtools

+ 57 - 0
ThirdParty/Glslang/External/spirv-tools/source/fuzz/transformation_swap_function_variables.h

@@ -0,0 +1,57 @@
+// Copyright (c) 2021 Mostafa Ashraf
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SOURCE_FUZZ_TRANSFORMATION_SWAP_FUNCTION_VARIABLES_H_
+#define SOURCE_FUZZ_TRANSFORMATION_SWAP_FUNCTION_VARIABLES_H_
+
+#include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
+#include "source/fuzz/transformation.h"
+#include "source/fuzz/transformation_context.h"
+#include "source/opt/ir_context.h"
+
+namespace spvtools {
+namespace fuzz {
+
+// A transformation that swaps two variable declaration instructions that appear
+// in the same function.
+class TransformationSwapFunctionVariables : public Transformation {
+ public:
+  explicit TransformationSwapFunctionVariables(
+      protobufs::TransformationSwapFunctionVariables message);
+
+  TransformationSwapFunctionVariables(uint32_t result_id1, uint32_t result_id2);
+
+  // - |message_.result_id1| and |message_.result_id2| must be the ids of
+  //   distinct OpVariable instructions appearing in the same function.
+  bool IsApplicable(
+      opt::IRContext* ir_context,
+      const TransformationContext& transformation_context) const override;
+
+  // Swaps two OpVariable instructions with result ids |message_.result_id1|
+  // and |message_.result_id2|.
+  void Apply(opt::IRContext* ir_context,
+             TransformationContext* transformation_context) const override;
+
+  protobufs::Transformation ToMessage() const override;
+
+  std::unordered_set<uint32_t> GetFreshIds() const override;
+
+ private:
+  protobufs::TransformationSwapFunctionVariables message_;
+};
+
+}  // namespace fuzz
+}  // namespace spvtools
+
+#endif  // SOURCE_FUZZ_TRANSFORMATION_SWAP_FUNCTION_VARIABLES_H_

+ 72 - 0
ThirdParty/Glslang/External/spirv-tools/source/fuzz/transformation_swap_two_functions.cpp

@@ -0,0 +1,72 @@
+// Copyright (c) 2021 Shiyu Liu
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "source/fuzz/transformation_swap_two_functions.h"
+
+#include "source/opt/function.h"
+#include "source/opt/module.h"
+
+#include "source/fuzz/fuzzer_util.h"
+
+namespace spvtools {
+namespace fuzz {
+
+TransformationSwapTwoFunctions::TransformationSwapTwoFunctions(
+    protobufs::TransformationSwapTwoFunctions message)
+    : message_(std::move(message)) {}
+
+TransformationSwapTwoFunctions::TransformationSwapTwoFunctions(uint32_t id1,
+                                                               uint32_t id2) {
+  assert(id1 != id2 && "The two function ids cannot be the same.");
+  message_.set_function_id1(id1);
+  message_.set_function_id2(id2);
+}
+
+bool TransformationSwapTwoFunctions::IsApplicable(
+    opt::IRContext* ir_context, const TransformationContext& /*unused*/) const {
+  auto func1_ptr = ir_context->GetFunction(message_.function_id1());
+  auto func2_ptr = ir_context->GetFunction(message_.function_id2());
+  return func1_ptr != nullptr && func2_ptr != nullptr;
+}
+
+void TransformationSwapTwoFunctions::Apply(
+    opt::IRContext* ir_context, TransformationContext* /*unused*/) const {
+  opt::Module::iterator func1_it =
+      fuzzerutil::GetFunctionIterator(ir_context, message_.function_id1());
+  opt::Module::iterator func2_it =
+      fuzzerutil::GetFunctionIterator(ir_context, message_.function_id2());
+
+  assert(func1_it != ir_context->module()->end() &&
+         "Could not find function 1.");
+  assert(func2_it != ir_context->module()->end() &&
+         "Could not find function 2.");
+
+  // Two function pointers are all set, swap the two functions within the
+  // module.
+  std::iter_swap(func1_it.Get(), func2_it.Get());
+}
+
+protobufs::Transformation TransformationSwapTwoFunctions::ToMessage() const {
+  protobufs::Transformation result;
+  *result.mutable_swap_two_functions() = message_;
+  return result;
+}
+
+std::unordered_set<uint32_t> TransformationSwapTwoFunctions::GetFreshIds()
+    const {
+  return std::unordered_set<uint32_t>();
+}
+
+}  // namespace fuzz
+}  // namespace spvtools

+ 56 - 0
ThirdParty/Glslang/External/spirv-tools/source/fuzz/transformation_swap_two_functions.h

@@ -0,0 +1,56 @@
+// Copyright (c) 2021 Shiyu Liu
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SOURCE_FUZZ_TRANSFORMATION_SWAP_TWO_FUNCTIONS_H_
+#define SOURCE_FUZZ_TRANSFORMATION_SWAP_TWO_FUNCTIONS_H_
+
+#include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
+#include "source/fuzz/transformation.h"
+#include "source/fuzz/transformation_context.h"
+#include "source/opt/ir_context.h"
+
+namespace spvtools {
+namespace fuzz {
+
+class TransformationSwapTwoFunctions : public Transformation {
+ public:
+  explicit TransformationSwapTwoFunctions(
+      protobufs::TransformationSwapTwoFunctions message);
+
+  TransformationSwapTwoFunctions(uint32_t function_id1, uint32_t function_id2);
+
+  // |function_id1| and  |function_id1| should all be existing ids.
+  //  Swap function operation is only permitted if:
+  //  - both ids must be ids of functions.
+  //  - both ids can be found in the module.
+  //  - function_id1 and function_id2 are not the same.
+  bool IsApplicable(
+      opt::IRContext* ir_context,
+      const TransformationContext& transformation_context) const override;
+
+  // OpFunction with |function_id1| and |function_id1| are swapped.
+  void Apply(opt::IRContext* ir_context,
+             TransformationContext* transformation_context) const override;
+
+  std::unordered_set<uint32_t> GetFreshIds() const override;
+  protobufs::Transformation ToMessage() const override;
+
+ private:
+  protobufs::TransformationSwapTwoFunctions message_;
+};
+
+}  // namespace fuzz
+}  // namespace spvtools
+
+#endif  // SOURCE_FUZZ_TRANSFORMATION_SWAP_TWO_FUNCTIONS_H_

+ 200 - 0
ThirdParty/Glslang/External/spirv-tools/source/fuzz/transformation_wrap_vector_synonym.cpp

@@ -0,0 +1,200 @@
+// Copyright (c) 2021 Shiyu Liu
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "source/fuzz/transformation_wrap_vector_synonym.h"
+
+#include "source/fuzz/data_descriptor.h"
+#include "source/fuzz/fuzzer_util.h"
+#include "source/opt/instruction.h"
+
+namespace spvtools {
+namespace fuzz {
+
+TransformationWrapVectorSynonym::TransformationWrapVectorSynonym(
+    protobufs::TransformationWrapVectorSynonym message)
+    : message_(std::move(message)) {}
+
+TransformationWrapVectorSynonym::TransformationWrapVectorSynonym(
+    uint32_t instruction_id, uint32_t vector_operand1, uint32_t vector_operand2,
+    uint32_t fresh_id, uint32_t pos) {
+  message_.set_instruction_id(instruction_id);
+  message_.set_vector_operand1(vector_operand1);
+  message_.set_vector_operand2(vector_operand2);
+  message_.set_fresh_id(fresh_id);
+  message_.set_scalar_position(pos);
+}
+
+bool TransformationWrapVectorSynonym::IsApplicable(
+    opt::IRContext* ir_context,
+    const TransformationContext& transformation_context) const {
+  // |fresh_id| must be fresh.
+  if (!fuzzerutil::IsFreshId(ir_context, message_.fresh_id())) {
+    return false;
+  }
+
+  const opt::Instruction* instruction =
+      ir_context->get_def_use_mgr()->GetDef(message_.instruction_id());
+
+  // |instruction_id| must refer to an existing instruction.
+  if (instruction == nullptr) {
+    return false;
+  }
+
+  if (!IsInstructionSupported(ir_context, *instruction)) {
+    return false;
+  }
+
+  // It must be possible to make a synonym of the result id of the scalar
+  // operation
+  if (!fuzzerutil::CanMakeSynonymOf(ir_context, transformation_context,
+                                    *instruction)) {
+    return false;
+  }
+
+  // |vector_operand1| and |vector_operand2| must exist.
+  auto vec1 = ir_context->get_def_use_mgr()->GetDef(message_.vector_operand1());
+  auto vec2 = ir_context->get_def_use_mgr()->GetDef(message_.vector_operand2());
+
+  if (vec1 == nullptr || vec2 == nullptr) {
+    return false;
+  }
+
+  // The 2 vectors must have compatible vector types.
+  auto vec1_type_id = vec1->type_id();
+  auto vec2_type_id = vec2->type_id();
+
+  for (auto operand_index : {0, 1}) {
+    if (!fuzzerutil::TypesAreCompatible(ir_context, instruction->opcode(),
+                                        operand_index, vec1_type_id,
+                                        vec2_type_id)) {
+      return false;
+    }
+  }
+
+  auto vec1_type = ir_context->get_def_use_mgr()->GetDef(vec1_type_id);
+  if (vec1_type->opcode() != SpvOpTypeVector) {
+    return false;
+  }
+
+  // A suitable vector for the result type of the new vector instruction must
+  // exist in the module. This is a vector of the right length, whose element
+  // type matches the result type of the scalar instruction.
+  uint32_t vector_size = vec1_type->GetSingleWordInOperand(1);
+  if (!fuzzerutil::MaybeGetVectorType(ir_context, instruction->type_id(),
+                                      vector_size)) {
+    return false;
+  }
+
+  // |scalar_position| needs to be a non-negative integer less than the vector
+  // length.
+  // OpTypeVector instruction has the component count at index 2.
+  if (message_.scalar_position() >= ir_context->get_def_use_mgr()
+                                        ->GetDef(vec1_type_id)
+                                        ->GetSingleWordInOperand(1)) {
+    return false;
+  }
+
+  if (!transformation_context.GetFactManager()->IsSynonymous(
+          MakeDataDescriptor(message_.vector_operand1(),
+                             {message_.scalar_position()}),
+          MakeDataDescriptor(instruction->GetSingleWordInOperand(0), {}))) {
+    return false;
+  }
+
+  if (!transformation_context.GetFactManager()->IsSynonymous(
+          MakeDataDescriptor(message_.vector_operand2(),
+                             {message_.scalar_position()}),
+          MakeDataDescriptor(instruction->GetSingleWordInOperand(1), {}))) {
+    return false;
+  }
+
+  return true;
+}
+
+void TransformationWrapVectorSynonym::Apply(
+    opt::IRContext* ir_context,
+    TransformationContext* transformation_context) const {
+  // Create an instruction descriptor for the original instruction.
+  auto instruction =
+      ir_context->get_def_use_mgr()->GetDef(message_.instruction_id());
+  auto destination_block = ir_context->get_instr_block(instruction);
+
+  //  Populate input operand list with two vectors for vector operation.
+  opt::Instruction::OperandList in_operands;
+  in_operands.push_back({SPV_OPERAND_TYPE_ID, {message_.vector_operand1()}});
+  in_operands.push_back({SPV_OPERAND_TYPE_ID, {message_.vector_operand2()}});
+
+  // Make a new arithmetic instruction: %fresh_id = OpXX %type_id %result_id1
+  // %result_id2.
+  auto vector_operand_type = ir_context->get_def_use_mgr()->GetDef(
+      fuzzerutil::GetTypeId(ir_context, message_.vector_operand1()));
+  uint32_t vector_size = vector_operand_type->GetSingleWordInOperand(1);
+  auto vec_type_id = fuzzerutil::MaybeGetVectorType(
+      ir_context, instruction->type_id(), vector_size);
+  auto new_instruction = MakeUnique<opt::Instruction>(
+      ir_context, instruction->opcode(), vec_type_id, message_.fresh_id(),
+      std::move(in_operands));
+  auto new_instruction_ptr = new_instruction.get();
+  instruction->InsertBefore(std::move(new_instruction));
+  ir_context->get_def_use_mgr()->AnalyzeInstDefUse(new_instruction_ptr);
+  ir_context->set_instr_block(new_instruction_ptr, destination_block);
+
+  // Add |fresh_id| to id bound.
+  fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id());
+
+  // Add synonyms between |fresh_id| and |instruction_id|.
+  transformation_context->GetFactManager()->AddFactDataSynonym(
+      MakeDataDescriptor(message_.fresh_id(), {message_.scalar_position()}),
+      MakeDataDescriptor(message_.instruction_id(), {}));
+}
+
+protobufs::Transformation TransformationWrapVectorSynonym::ToMessage() const {
+  protobufs::Transformation result;
+  *result.mutable_wrap_vector_synonym() = message_;
+  return result;
+}
+
+std::unordered_set<uint32_t> TransformationWrapVectorSynonym::GetFreshIds()
+    const {
+  return std::unordered_set<uint32_t>{message_.fresh_id()};
+}
+
+bool TransformationWrapVectorSynonym::IsInstructionSupported(
+    opt::IRContext* ir_context, const opt::Instruction& instruction) {
+  if (!instruction.result_id() || !instruction.type_id()) {
+    return false;
+  }
+  auto type_instruction =
+      ir_context->get_def_use_mgr()->GetDef(instruction.type_id());
+
+  if ((type_instruction->opcode() != SpvOpTypeInt &&
+       type_instruction->opcode() != SpvOpTypeFloat)) {
+    return false;
+  }
+
+  switch (instruction.opcode()) {
+    case SpvOpIAdd:
+    case SpvOpISub:
+    case SpvOpIMul:
+    case SpvOpFAdd:
+    case SpvOpFSub:
+    case SpvOpFMul:
+      return true;
+    default:
+      return false;
+  }
+}
+
+}  // namespace fuzz
+}  // namespace spvtools

+ 80 - 0
ThirdParty/Glslang/External/spirv-tools/source/fuzz/transformation_wrap_vector_synonym.h

@@ -0,0 +1,80 @@
+// Copyright (c) 2021 Shiyu Liu
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SOURCE_FUZZ_TRANSFORMATION_WRAP_VECTOR_SYNONYM_H_
+#define SOURCE_FUZZ_TRANSFORMATION_WRAP_VECTOR_SYNONYM_H_
+
+#include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
+#include "source/fuzz/transformation.h"
+#include "source/fuzz/transformation_context.h"
+#include "source/opt/ir_context.h"
+
+namespace spvtools {
+namespace fuzz {
+
+class TransformationWrapVectorSynonym : public Transformation {
+ public:
+  explicit TransformationWrapVectorSynonym(
+      protobufs::TransformationWrapVectorSynonym message);
+
+  TransformationWrapVectorSynonym(uint32_t instruction_id,
+                                  uint32_t vector_operand1,
+                                  uint32_t vector_operand2, uint32_t fresh_id,
+                                  uint32_t pos);
+  // - |instruction_id| must be the id of a supported arithmetic operation
+  //   and must be relevant.
+  // - |vector_operand1| and |vector_operand2| represents the result ids of the
+  //   two vector operands.
+  // - |fresh_id| is an unused id that will be used as a result id of the
+  //   created instruction.
+  // - |vector_operand1| and |vector_operand2| must have compatible vector types
+  //   that are supported by this transformation.
+  // - |pos| is an index of the operands of |instruction_id| in the
+  //   |vector_operand1| and |vector_operand2|. It must be less than the size
+  //   of those vector operands.
+  // - A vector type with the same width as the types of the vector operands,
+  //   and element type matching the type of |instruction_id|, must exist in the
+  //   module.
+  bool IsApplicable(
+      opt::IRContext* ir_context,
+      const TransformationContext& transformation_context) const override;
+
+  // Adds a new instruction before the |instruction_id| with |fresh_id|
+  // result id and |instruction_id|'s opcode. The added instruction has
+  // two operands: |vector_operand1| and |vector_operand2| and its type
+  // id is equal to the type ids of those operands. A new fact is added
+  // to the fact manager specifying that |fresh_id[pos]| is synonymous
+  // to |instruction_id|.
+  void Apply(opt::IRContext* ir_context,
+             TransformationContext* transformation_context) const override;
+
+  std::unordered_set<uint32_t> GetFreshIds() const override;
+  protobufs::Transformation ToMessage() const override;
+
+  // Checks whether the instruction given is supported by the transformation.
+  // A valid instruction must:
+  // - has both result id and type id.
+  // - is a supported scalar operation instruction.
+  // - has a supported type that is either int or float.
+  static bool IsInstructionSupported(opt::IRContext* ir_context,
+                                     const opt::Instruction& instruction);
+
+ private:
+  protobufs::TransformationWrapVectorSynonym message_;
+};
+
+}  // namespace fuzz
+}  // namespace spvtools
+
+#endif  // SOURCE_FUZZ_TRANSFORMATION_WRAP_VECTOR_SYNONYM_H_

+ 61 - 0
ThirdParty/Glslang/External/spirv-tools/source/lint/CMakeLists.txt

@@ -0,0 +1,61 @@
+# Copyright (c) 2021 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.
+set(SPIRV_TOOLS_LINT_SOURCES
+  divergence_analysis.h
+  lints.h
+
+  linter.cpp
+  divergence_analysis.cpp
+  lint_divergent_derivatives.cpp
+)
+
+if(MSVC AND (NOT ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")))
+  # Enable parallel builds across four cores for this lib.
+  add_definitions(/MP4)
+endif()
+
+add_library(SPIRV-Tools-lint ${SPIRV_TOOLS_LIBRARY_TYPE} ${SPIRV_TOOLS_LINT_SOURCES})
+
+spvtools_default_compile_options(SPIRV-Tools-lint)
+target_include_directories(SPIRV-Tools-lint
+  PUBLIC
+	$<BUILD_INTERFACE:${spirv-tools_SOURCE_DIR}/include>
+	$<BUILD_INTERFACE:${SPIRV_HEADER_INCLUDE_DIR}>
+	$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
+  PRIVATE ${spirv-tools_BINARY_DIR}
+)
+# We need the assembling and disassembling functionalities in the main library.
+target_link_libraries(SPIRV-Tools-lint
+  PUBLIC ${SPIRV_TOOLS_FULL_VISIBILITY})
+# We need the internals of spirv-opt.
+target_link_libraries(SPIRV-Tools-lint
+  PUBLIC SPIRV-Tools-opt)
+
+set_property(TARGET SPIRV-Tools-lint PROPERTY FOLDER "SPIRV-Tools libraries")
+spvtools_check_symbol_exports(SPIRV-Tools-lint)
+
+if(ENABLE_SPIRV_TOOLS_INSTALL)
+  install(TARGETS SPIRV-Tools-lint EXPORT SPIRV-Tools-lintTargets
+    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+    ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
+  export(EXPORT SPIRV-Tools-lintTargets FILE SPIRV-Tools-lintTargets.cmake)
+
+  spvtools_config_package_dir(SPIRV-Tools-lint PACKAGE_DIR)
+  install(EXPORT SPIRV-Tools-lintTargets FILE SPIRV-Tools-lintTargets.cmake
+  	DESTINATION ${PACKAGE_DIR})
+
+  spvtools_generate_config_file(SPIRV-Tools-lint)
+  install(FILES ${CMAKE_BINARY_DIR}/SPIRV-Tools-lintConfig.cmake DESTINATION ${PACKAGE_DIR})
+endif(ENABLE_SPIRV_TOOLS_INSTALL)

+ 245 - 0
ThirdParty/Glslang/External/spirv-tools/source/lint/divergence_analysis.cpp

@@ -0,0 +1,245 @@
+// Copyright (c) 2021 Google LLC.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "source/lint/divergence_analysis.h"
+
+#include "source/opt/basic_block.h"
+#include "source/opt/control_dependence.h"
+#include "source/opt/dataflow.h"
+#include "source/opt/function.h"
+#include "source/opt/instruction.h"
+#include "spirv/unified1/spirv.h"
+
+namespace spvtools {
+namespace lint {
+
+void DivergenceAnalysis::EnqueueSuccessors(opt::Instruction* inst) {
+  // Enqueue control dependents of block, if applicable.
+  // There are two ways for a dependence source to be updated:
+  // 1. control -> control: source block is marked divergent.
+  // 2. data -> control: branch condition is marked divergent.
+  uint32_t block_id;
+  if (inst->IsBlockTerminator()) {
+    block_id = context().get_instr_block(inst)->id();
+  } else if (inst->opcode() == SpvOpLabel) {
+    block_id = inst->result_id();
+    opt::BasicBlock* bb = context().cfg()->block(block_id);
+    // Only enqueue phi instructions, as other uses don't affect divergence.
+    bb->ForEachPhiInst([this](opt::Instruction* phi) { Enqueue(phi); });
+  } else {
+    opt::ForwardDataFlowAnalysis::EnqueueUsers(inst);
+    return;
+  }
+  if (!cd_.HasBlock(block_id)) {
+    return;
+  }
+  for (const spvtools::opt::ControlDependence& dep :
+       cd_.GetDependenceTargets(block_id)) {
+    opt::Instruction* target_inst =
+        context().cfg()->block(dep.target_bb_id())->GetLabelInst();
+    Enqueue(target_inst);
+  }
+}
+
+opt::DataFlowAnalysis::VisitResult DivergenceAnalysis::Visit(
+    opt::Instruction* inst) {
+  if (inst->opcode() == SpvOpLabel) {
+    return VisitBlock(inst->result_id());
+  } else {
+    return VisitInstruction(inst);
+  }
+}
+
+opt::DataFlowAnalysis::VisitResult DivergenceAnalysis::VisitBlock(uint32_t id) {
+  if (!cd_.HasBlock(id)) {
+    return opt::DataFlowAnalysis::VisitResult::kResultFixed;
+  }
+  DivergenceLevel& cur_level = divergence_[id];
+  if (cur_level == DivergenceLevel::kDivergent) {
+    return opt::DataFlowAnalysis::VisitResult::kResultFixed;
+  }
+  DivergenceLevel orig = cur_level;
+  for (const spvtools::opt::ControlDependence& dep :
+       cd_.GetDependenceSources(id)) {
+    if (divergence_[dep.source_bb_id()] > cur_level) {
+      cur_level = divergence_[dep.source_bb_id()];
+      divergence_source_[id] = dep.source_bb_id();
+    } else if (dep.source_bb_id() != 0) {
+      uint32_t condition_id = dep.GetConditionID(*context().cfg());
+      DivergenceLevel dep_level = divergence_[condition_id];
+      // Check if we are along the chain of unconditional branches starting from
+      // the branch target.
+      if (follow_unconditional_branches_[dep.branch_target_bb_id()] !=
+          follow_unconditional_branches_[dep.target_bb_id()]) {
+        // We must have reconverged in order to reach this block.
+        // Promote partially uniform to divergent.
+        if (dep_level == DivergenceLevel::kPartiallyUniform) {
+          dep_level = DivergenceLevel::kDivergent;
+        }
+      }
+      if (dep_level > cur_level) {
+        cur_level = dep_level;
+        divergence_source_[id] = condition_id;
+        divergence_dependence_source_[id] = dep.source_bb_id();
+      }
+    }
+  }
+  return cur_level > orig ? VisitResult::kResultChanged
+                          : VisitResult::kResultFixed;
+}
+
+opt::DataFlowAnalysis::VisitResult DivergenceAnalysis::VisitInstruction(
+    opt::Instruction* inst) {
+  if (inst->IsBlockTerminator()) {
+    // This is called only when the condition has changed, so return changed.
+    return VisitResult::kResultChanged;
+  }
+  if (!inst->HasResultId()) {
+    return VisitResult::kResultFixed;
+  }
+  uint32_t id = inst->result_id();
+  DivergenceLevel& cur_level = divergence_[id];
+  if (cur_level == DivergenceLevel::kDivergent) {
+    return opt::DataFlowAnalysis::VisitResult::kResultFixed;
+  }
+  DivergenceLevel orig = cur_level;
+  cur_level = ComputeInstructionDivergence(inst);
+  return cur_level > orig ? VisitResult::kResultChanged
+                          : VisitResult::kResultFixed;
+}
+
+DivergenceAnalysis::DivergenceLevel
+DivergenceAnalysis::ComputeInstructionDivergence(opt::Instruction* inst) {
+  // TODO(kuhar): Check to see if inst is decorated with Uniform or UniformId
+  // and use that to short circuit other checks. Uniform is for subgroups which
+  // would satisfy derivative groups too. UniformId takes a scope, so if it is
+  // subgroup or greater it could satisfy derivative group and
+  // Device/QueueFamily could satisfy fully uniform.
+  uint32_t id = inst->result_id();
+  // Handle divergence roots.
+  if (inst->opcode() == SpvOpFunctionParameter) {
+    divergence_source_[id] = 0;
+    return divergence_[id] = DivergenceLevel::kDivergent;
+  } else if (inst->IsLoad()) {
+    spvtools::opt::Instruction* var = inst->GetBaseAddress();
+    if (var->opcode() != SpvOpVariable) {
+      // Assume divergent.
+      divergence_source_[id] = 0;
+      return DivergenceLevel::kDivergent;
+    }
+    DivergenceLevel ret = ComputeVariableDivergence(var);
+    if (ret > DivergenceLevel::kUniform) {
+      divergence_source_[inst->result_id()] = 0;
+    }
+    return divergence_[id] = ret;
+  }
+  // Get the maximum divergence of the operands.
+  DivergenceLevel ret = DivergenceLevel::kUniform;
+  inst->ForEachInId([this, inst, &ret](const uint32_t* op) {
+    if (!op) return;
+    if (divergence_[*op] > ret) {
+      divergence_source_[inst->result_id()] = *op;
+      ret = divergence_[*op];
+    }
+  });
+  divergence_[inst->result_id()] = ret;
+  return ret;
+}
+
+DivergenceAnalysis::DivergenceLevel
+DivergenceAnalysis::ComputeVariableDivergence(opt::Instruction* var) {
+  uint32_t type_id = var->type_id();
+  spvtools::opt::analysis::Pointer* type =
+      context().get_type_mgr()->GetType(type_id)->AsPointer();
+  assert(type != nullptr);
+  uint32_t def_id = var->result_id();
+  DivergenceLevel ret;
+  switch (type->storage_class()) {
+    case SpvStorageClassFunction:
+    case SpvStorageClassGeneric:
+    case SpvStorageClassAtomicCounter:
+    case SpvStorageClassStorageBuffer:
+    case SpvStorageClassPhysicalStorageBuffer:
+    case SpvStorageClassOutput:
+    case SpvStorageClassWorkgroup:
+    case SpvStorageClassImage:  // Image atomics probably aren't uniform.
+    case SpvStorageClassPrivate:
+      ret = DivergenceLevel::kDivergent;
+      break;
+    case SpvStorageClassInput:
+      ret = DivergenceLevel::kDivergent;
+      // If this variable has a Flat decoration, it is partially uniform.
+      // TODO(kuhar): Track access chain indices and also consider Flat members
+      // of a structure.
+      context().get_decoration_mgr()->WhileEachDecoration(
+          def_id, SpvDecorationFlat, [&ret](const opt::Instruction&) {
+            ret = DivergenceLevel::kPartiallyUniform;
+            return false;
+          });
+      break;
+    case SpvStorageClassUniformConstant:
+      // May be a storage image which is also written to; mark those as
+      // divergent.
+      if (!var->IsVulkanStorageImage() || var->IsReadOnlyPointer()) {
+        ret = DivergenceLevel::kUniform;
+      } else {
+        ret = DivergenceLevel::kDivergent;
+      }
+      break;
+    case SpvStorageClassUniform:
+    case SpvStorageClassPushConstant:
+    case SpvStorageClassCrossWorkgroup:  // Not for shaders; default uniform.
+    default:
+      ret = DivergenceLevel::kUniform;
+      break;
+  }
+  return ret;
+}
+
+void DivergenceAnalysis::Setup(opt::Function* function) {
+  // TODO(kuhar): Run functions called by |function| so we can detect
+  // reconvergence caused by multiple returns.
+  cd_.ComputeControlDependenceGraph(
+      *context().cfg(), *context().GetPostDominatorAnalysis(function));
+  context().cfg()->ForEachBlockInPostOrder(
+      function->entry().get(), [this](const opt::BasicBlock* bb) {
+        uint32_t id = bb->id();
+        if (bb->terminator() == nullptr ||
+            bb->terminator()->opcode() != SpvOpBranch) {
+          follow_unconditional_branches_[id] = id;
+        } else {
+          uint32_t target_id = bb->terminator()->GetSingleWordInOperand(0);
+          // Target is guaranteed to have been visited before us in postorder.
+          follow_unconditional_branches_[id] =
+              follow_unconditional_branches_[target_id];
+        }
+      });
+}
+
+std::ostream& operator<<(std::ostream& os,
+                         DivergenceAnalysis::DivergenceLevel level) {
+  switch (level) {
+    case DivergenceAnalysis::DivergenceLevel::kUniform:
+      return os << "uniform";
+    case DivergenceAnalysis::DivergenceLevel::kPartiallyUniform:
+      return os << "partially uniform";
+    case DivergenceAnalysis::DivergenceLevel::kDivergent:
+      return os << "divergent";
+    default:
+      return os << "<invalid divergence level>";
+  }
+}
+
+}  // namespace lint
+}  // namespace spvtools

+ 163 - 0
ThirdParty/Glslang/External/spirv-tools/source/lint/divergence_analysis.h

@@ -0,0 +1,163 @@
+// Copyright (c) 2021 Google LLC.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SOURCE_LINT_DIVERGENCE_ANALYSIS_H_
+#define SOURCE_LINT_DIVERGENCE_ANALYSIS_H_
+
+#include <cstdint>
+#include <ostream>
+#include <unordered_map>
+
+#include "source/opt/basic_block.h"
+#include "source/opt/control_dependence.h"
+#include "source/opt/dataflow.h"
+#include "source/opt/function.h"
+#include "source/opt/instruction.h"
+
+namespace spvtools {
+namespace lint {
+
+// Computes the static divergence level for blocks (control flow) and values.
+//
+// A value is uniform if all threads that execute it are guaranteed to have the
+// same value. Similarly, a value is partially uniform if this is true only
+// within each derivative group. If neither apply, it is divergent.
+//
+// Control flow through a block is uniform if for any possible execution and
+// point in time, all threads are executing it, or no threads are executing it.
+// In particular, it is never possible for some threads to be inside the block
+// and some threads not executing.
+// TODO(kuhar): Clarify the difference between uniform, divergent, and
+// partially-uniform execution in this analysis.
+//
+// Caveat:
+// As we use control dependence to determine how divergence is propagated, this
+// analysis can be overly permissive when the merge block for a conditional
+// branch or switch is later than (strictly postdominates) the expected merge
+// block, which is the immediate postdominator. However, this is not expected to
+// be a problem in practice, given that SPIR-V is generally output by compilers
+// and other automated tools, which would assign the earliest possible merge
+// block, rather than written by hand.
+// TODO(kuhar): Handle late merges.
+class DivergenceAnalysis : public opt::ForwardDataFlowAnalysis {
+ public:
+  // The tightest (most uniform) level of divergence that can be determined
+  // statically for a value or control flow for a block.
+  //
+  // The values are ordered such that A > B means that A is potentially more
+  // divergent than B.
+  // TODO(kuhar): Rename |PartiallyUniform' to something less confusing. For
+  // example, the enum could be based on scopes.
+  enum class DivergenceLevel {
+    // The value or control flow is uniform across the entire invocation group.
+    kUniform = 0,
+    // The value or control flow is uniform across the derivative group, but not
+    // the invocation group.
+    kPartiallyUniform = 1,
+    // The value or control flow is not statically uniform.
+    kDivergent = 2,
+  };
+
+  DivergenceAnalysis(opt::IRContext& context)
+      : ForwardDataFlowAnalysis(context, LabelPosition::kLabelsAtEnd) {}
+
+  // Returns the divergence level for the given value (non-label instructions),
+  // or control flow for the given block.
+  DivergenceLevel GetDivergenceLevel(uint32_t id) {
+    auto it = divergence_.find(id);
+    if (it == divergence_.end()) {
+      return DivergenceLevel::kUniform;
+    }
+    return it->second;
+  }
+
+  // Returns the divergence source for the given id. The following types of
+  // divergence flows from A to B are possible:
+  //
+  // data -> data: A is used as an operand in the definition of B.
+  // data -> control: B is control-dependent on a branch with condition A.
+  // control -> data: B is a OpPhi instruction in which A is a block operand.
+  // control -> control: B is control-dependent on A.
+  uint32_t GetDivergenceSource(uint32_t id) {
+    auto it = divergence_source_.find(id);
+    if (it == divergence_source_.end()) {
+      return 0;
+    }
+    return it->second;
+  }
+
+  // Returns the dependence source for the control dependence for the given id.
+  // This only exists for data -> control edges.
+  //
+  // In other words, if block 2 is dependent on block 1 due to value 3 (e.g.
+  // block 1 terminates with OpBranchConditional %3 %2 %4):
+  // * GetDivergenceSource(2) = 3
+  // * GetDivergenceDependenceSource(2) = 1
+  //
+  // Returns 0 if not applicable.
+  uint32_t GetDivergenceDependenceSource(uint32_t id) {
+    auto it = divergence_dependence_source_.find(id);
+    if (it == divergence_dependence_source_.end()) {
+      return 0;
+    }
+    return it->second;
+  }
+
+  void InitializeWorklist(opt::Function* function,
+                          bool is_first_iteration) override {
+    // Since |EnqueueSuccessors| is complete, we only need one pass.
+    if (is_first_iteration) {
+      Setup(function);
+      opt::ForwardDataFlowAnalysis::InitializeWorklist(function, true);
+    }
+  }
+
+  void EnqueueSuccessors(opt::Instruction* inst) override;
+
+  VisitResult Visit(opt::Instruction* inst) override;
+
+ private:
+  VisitResult VisitBlock(uint32_t id);
+  VisitResult VisitInstruction(opt::Instruction* inst);
+
+  // Computes the divergence level for the result of the given instruction
+  // based on the current state of the analysis. This is always an
+  // underapproximation, which will be improved as the analysis proceeds.
+  DivergenceLevel ComputeInstructionDivergence(opt::Instruction* inst);
+
+  // Computes the divergence level for a variable, which is used for loads.
+  DivergenceLevel ComputeVariableDivergence(opt::Instruction* var);
+
+  // Initializes data structures for performing dataflow on the given function.
+  void Setup(opt::Function* function);
+
+  std::unordered_map<uint32_t, DivergenceLevel> divergence_;
+  std::unordered_map<uint32_t, uint32_t> divergence_source_;
+  std::unordered_map<uint32_t, uint32_t> divergence_dependence_source_;
+
+  // Stores the result of following unconditional branches starting from the
+  // given block. This is used to detect when reconvergence needs to be
+  // accounted for.
+  std::unordered_map<uint32_t, uint32_t> follow_unconditional_branches_;
+
+  opt::ControlDependenceAnalysis cd_;
+};
+
+std::ostream& operator<<(std::ostream& os,
+                         DivergenceAnalysis::DivergenceLevel level);
+
+}  // namespace lint
+}  // namespace spvtools
+
+#endif  // SOURCE_LINT_DIVERGENCE_ANALYSIS_H_

+ 169 - 0
ThirdParty/Glslang/External/spirv-tools/source/lint/lint_divergent_derivatives.cpp

@@ -0,0 +1,169 @@
+// Copyright (c) 2021 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 <cassert>
+#include <sstream>
+#include <string>
+
+#include "source/diagnostic.h"
+#include "source/lint/divergence_analysis.h"
+#include "source/lint/lints.h"
+#include "source/opt/basic_block.h"
+#include "source/opt/cfg.h"
+#include "source/opt/control_dependence.h"
+#include "source/opt/def_use_manager.h"
+#include "source/opt/dominator_analysis.h"
+#include "source/opt/instruction.h"
+#include "source/opt/ir_context.h"
+#include "spirv-tools/libspirv.h"
+#include "spirv/unified1/spirv.h"
+
+namespace spvtools {
+namespace lint {
+namespace lints {
+namespace {
+// Returns the %name[id], where `name` is the first name associated with the
+// given id, or just %id if one is not found.
+std::string GetFriendlyName(opt::IRContext* context, uint32_t id) {
+  auto names = context->GetNames(id);
+  std::stringstream ss;
+  ss << "%";
+  if (names.empty()) {
+    ss << id;
+  } else {
+    opt::Instruction* inst_name = names.begin()->second;
+    if (inst_name->opcode() == SpvOpName) {
+      ss << names.begin()->second->GetInOperand(0).AsString();
+      ss << "[" << id << "]";
+    } else {
+      ss << id;
+    }
+  }
+  return ss.str();
+}
+
+bool InstructionHasDerivative(const opt::Instruction& inst) {
+  static const SpvOp derivative_opcodes[] = {
+      // Implicit derivatives.
+      SpvOpImageSampleImplicitLod,
+      SpvOpImageSampleDrefImplicitLod,
+      SpvOpImageSampleProjImplicitLod,
+      SpvOpImageSampleProjDrefImplicitLod,
+      SpvOpImageSparseSampleImplicitLod,
+      SpvOpImageSparseSampleDrefImplicitLod,
+      SpvOpImageSparseSampleProjImplicitLod,
+      SpvOpImageSparseSampleProjDrefImplicitLod,
+      // Explicit derivatives.
+      SpvOpDPdx,
+      SpvOpDPdy,
+      SpvOpFwidth,
+      SpvOpDPdxFine,
+      SpvOpDPdyFine,
+      SpvOpFwidthFine,
+      SpvOpDPdxCoarse,
+      SpvOpDPdyCoarse,
+      SpvOpFwidthCoarse,
+  };
+  return std::find(std::begin(derivative_opcodes), std::end(derivative_opcodes),
+                   inst.opcode()) != std::end(derivative_opcodes);
+}
+
+spvtools::DiagnosticStream Warn(opt::IRContext* context,
+                                opt::Instruction* inst) {
+  if (inst == nullptr) {
+    return DiagnosticStream({0, 0, 0}, context->consumer(), "", SPV_WARNING);
+  } else {
+    // TODO(kuhar): Use line numbers based on debug info.
+    return DiagnosticStream(
+        {0, 0, 0}, context->consumer(),
+        inst->PrettyPrint(SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES),
+        SPV_WARNING);
+  }
+}
+
+void PrintDivergenceFlow(opt::IRContext* context, DivergenceAnalysis div,
+                         uint32_t id) {
+  opt::analysis::DefUseManager* def_use = context->get_def_use_mgr();
+  opt::CFG* cfg = context->cfg();
+  while (id != 0) {
+    bool is_block = def_use->GetDef(id)->opcode() == SpvOpLabel;
+    if (is_block) {
+      Warn(context, nullptr)
+          << "block " << GetFriendlyName(context, id) << " is divergent";
+      uint32_t source = div.GetDivergenceSource(id);
+      // Skip intermediate blocks.
+      while (source != 0 && def_use->GetDef(source)->opcode() == SpvOpLabel) {
+        id = source;
+        source = div.GetDivergenceSource(id);
+      }
+      if (source == 0) break;
+      spvtools::opt::Instruction* branch =
+          cfg->block(div.GetDivergenceDependenceSource(id))->terminator();
+      Warn(context, branch)
+          << "because it depends on a conditional branch on divergent value "
+          << GetFriendlyName(context, source) << "";
+      id = source;
+    } else {
+      Warn(context, nullptr)
+          << "value " << GetFriendlyName(context, id) << " is divergent";
+      uint32_t source = div.GetDivergenceSource(id);
+      opt::Instruction* def = def_use->GetDef(id);
+      opt::Instruction* source_def =
+          source == 0 ? nullptr : def_use->GetDef(source);
+      // First print data -> data dependencies.
+      while (source != 0 && source_def->opcode() != SpvOpLabel) {
+        Warn(context, def_use->GetDef(id))
+            << "because " << GetFriendlyName(context, id) << " uses value "
+            << GetFriendlyName(context, source)
+            << "in its definition, which is divergent";
+        id = source;
+        def = source_def;
+        source = div.GetDivergenceSource(id);
+        source_def = def_use->GetDef(source);
+      }
+      if (source == 0) {
+        Warn(context, def) << "because it has a divergent definition";
+        break;
+      }
+      Warn(context, def) << "because it is conditionally set in block "
+                         << GetFriendlyName(context, source);
+      id = source;
+    }
+  }
+}
+}  // namespace
+
+bool CheckDivergentDerivatives(opt::IRContext* context) {
+  DivergenceAnalysis div(*context);
+  for (opt::Function& func : *context->module()) {
+    div.Run(&func);
+    for (const opt::BasicBlock& bb : func) {
+      for (const opt::Instruction& inst : bb) {
+        if (InstructionHasDerivative(inst) &&
+            div.GetDivergenceLevel(bb.id()) >
+                DivergenceAnalysis::DivergenceLevel::kPartiallyUniform) {
+          Warn(context, nullptr)
+              << "derivative with divergent control flow"
+              << " located in block " << GetFriendlyName(context, bb.id());
+          PrintDivergenceFlow(context, div, bb.id());
+        }
+      }
+    }
+  }
+  return true;
+}
+
+}  // namespace lints
+}  // namespace lint
+}  // namespace spvtools

+ 60 - 0
ThirdParty/Glslang/External/spirv-tools/source/lint/linter.cpp

@@ -0,0 +1,60 @@
+// Copyright (c) 2021 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 "spirv-tools/linter.hpp"
+
+#include "source/lint/lints.h"
+#include "source/opt/build_module.h"
+#include "source/opt/ir_context.h"
+#include "spirv-tools/libspirv.h"
+#include "spirv-tools/libspirv.hpp"
+#include "spirv/unified1/spirv.h"
+
+namespace spvtools {
+
+struct Linter::Impl {
+  explicit Impl(spv_target_env env) : target_env(env) {
+    message_consumer = [](spv_message_level_t /*level*/, const char* /*source*/,
+                          const spv_position_t& /*position*/,
+                          const char* /*message*/) {};
+  }
+
+  spv_target_env target_env;         // Target environment.
+  MessageConsumer message_consumer;  // Message consumer.
+};
+
+Linter::Linter(spv_target_env env) : impl_(new Impl(env)) {}
+
+Linter::~Linter() {}
+
+void Linter::SetMessageConsumer(MessageConsumer consumer) {
+  impl_->message_consumer = std::move(consumer);
+}
+
+const MessageConsumer& Linter::Consumer() const {
+  return impl_->message_consumer;
+}
+
+bool Linter::Run(const uint32_t* binary, size_t binary_size) {
+  std::unique_ptr<opt::IRContext> context =
+      BuildModule(SPV_ENV_VULKAN_1_2, Consumer(), binary, binary_size);
+  if (context == nullptr) return false;
+
+  bool result = true;
+  result &= lint::lints::CheckDivergentDerivatives(context.get());
+
+  return result;
+}
+
+}  // namespace spvtools

+ 34 - 0
ThirdParty/Glslang/External/spirv-tools/source/lint/lints.h

@@ -0,0 +1,34 @@
+// Copyright (c) 2021 Google LLC.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SOURCE_LINT_LINTS_H_
+#define SOURCE_LINT_LINTS_H_
+
+#include "source/opt/ir_context.h"
+
+namespace spvtools {
+namespace lint {
+
+// All of the functions in this namespace output to the error consumer in the
+// |context| argument and return |true| if no errors are found. They do not
+// modify the IR.
+namespace lints {
+
+bool CheckDivergentDerivatives(opt::IRContext* context);
+
+}  // namespace lints
+}  // namespace lint
+}  // namespace spvtools
+
+#endif  // SOURCE_LINT_LINTS_H_

+ 156 - 0
ThirdParty/Glslang/External/spirv-tools/source/opt/control_dependence.cpp

@@ -0,0 +1,156 @@
+// Copyright (c) 2021 Google LLC.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "source/opt/control_dependence.h"
+
+#include <cassert>
+#include <tuple>
+#include <utility>
+#include <vector>
+
+#include "source/opt/basic_block.h"
+#include "source/opt/cfg.h"
+#include "source/opt/dominator_analysis.h"
+#include "source/opt/function.h"
+#include "source/opt/instruction.h"
+#include "spirv/unified1/spirv.h"
+
+// Computes the control dependence graph (CDG) using the algorithm in Cytron
+// 1991, "Efficiently Computing Static Single Assignment Form and the Control
+// Dependence Graph." It relies on the fact that the control dependence sources
+// (blocks on which a block is control dependent) are exactly the post-dominance
+// frontier for that block. The explanation and proofs are given in Section 6 of
+// that paper.
+// Link: https://www.cs.utexas.edu/~pingali/CS380C/2010/papers/ssaCytron.pdf
+//
+// The algorithm in Section 4.2 of the same paper is used to construct the
+// dominance frontier. It uses the post-dominance tree, which is available in
+// the IR context.
+
+namespace spvtools {
+namespace opt {
+constexpr uint32_t ControlDependenceAnalysis::kPseudoEntryBlock;
+
+uint32_t ControlDependence::GetConditionID(const CFG& cfg) const {
+  if (source_bb_id() == 0) {
+    // Entry dependence; return 0.
+    return 0;
+  }
+  const BasicBlock* source_bb = cfg.block(source_bb_id());
+  const Instruction* branch = source_bb->terminator();
+  assert((branch->opcode() == SpvOpBranchConditional ||
+          branch->opcode() == SpvOpSwitch) &&
+         "invalid control dependence; last instruction must be conditional "
+         "branch or switch");
+  return branch->GetSingleWordInOperand(0);
+}
+
+bool ControlDependence::operator<(const ControlDependence& other) const {
+  return std::tie(source_bb_id_, target_bb_id_, branch_target_bb_id_) <
+         std::tie(other.source_bb_id_, other.target_bb_id_,
+                  other.branch_target_bb_id_);
+}
+
+bool ControlDependence::operator==(const ControlDependence& other) const {
+  return std::tie(source_bb_id_, target_bb_id_, branch_target_bb_id_) ==
+         std::tie(other.source_bb_id_, other.target_bb_id_,
+                  other.branch_target_bb_id_);
+}
+
+std::ostream& operator<<(std::ostream& os, const ControlDependence& dep) {
+  os << dep.source_bb_id() << "->" << dep.target_bb_id();
+  if (dep.branch_target_bb_id() != dep.target_bb_id()) {
+    os << " through " << dep.branch_target_bb_id();
+  }
+  return os;
+}
+
+void ControlDependenceAnalysis::ComputePostDominanceFrontiers(
+    const CFG& cfg, const PostDominatorAnalysis& pdom) {
+  // Compute post-dominance frontiers (reverse graph).
+  // The dominance frontier for a block X is equal to (Equation 4)
+  //   DF_local(X) U { B in DF_up(Z) | X = ipdom(Z) }
+  //   (ipdom(Z) is the immediate post-dominator of Z.)
+  // where
+  //   DF_local(X) = { Y | X -> Y in CFG, X does not strictly post-dominate Y }
+  //     represents the contribution of X's predecessors to the DF, and
+  //   DF_up(Z) = { Y | Y in DF(Z), ipdom(Z) does not strictly post-dominate Y }
+  //     (note: ipdom(Z) = X.)
+  //     represents the contribution of a block to its immediate post-
+  //     dominator's DF.
+  // This is computed in one pass through a post-order traversal of the
+  // post-dominator tree.
+
+  // Assert that there is a block other than the pseudo exit in the pdom tree,
+  // as we need one to get the function entry point (as the pseudo exit is not
+  // actually part of the function.)
+  assert(!cfg.IsPseudoExitBlock(pdom.GetDomTree().post_begin()->bb_));
+  Function* function = pdom.GetDomTree().post_begin()->bb_->GetParent();
+  uint32_t function_entry = function->entry()->id();
+  // Explicitly initialize pseudo-entry block, as it doesn't depend on anything,
+  // so it won't be initialized in the following loop.
+  reverse_nodes_[kPseudoEntryBlock] = {};
+  for (auto it = pdom.GetDomTree().post_cbegin();
+       it != pdom.GetDomTree().post_cend(); ++it) {
+    ComputePostDominanceFrontierForNode(cfg, pdom, function_entry, *it);
+  }
+}
+
+void ControlDependenceAnalysis::ComputePostDominanceFrontierForNode(
+    const CFG& cfg, const PostDominatorAnalysis& pdom, uint32_t function_entry,
+    const DominatorTreeNode& pdom_node) {
+  const uint32_t label = pdom_node.id();
+  ControlDependenceList& edges = reverse_nodes_[label];
+  for (uint32_t pred : cfg.preds(label)) {
+    if (!pdom.StrictlyDominates(label, pred)) {
+      edges.push_back(ControlDependence(pred, label));
+    }
+  }
+  if (label == function_entry) {
+    // Add edge from pseudo-entry to entry.
+    // In CDG construction, an edge is added from entry to exit, so only the
+    // exit node can post-dominate entry.
+    edges.push_back(ControlDependence(kPseudoEntryBlock, label));
+  }
+  for (DominatorTreeNode* child : pdom_node) {
+    // Note: iterate dependences by value, as we need a copy.
+    for (const ControlDependence& dep : reverse_nodes_[child->id()]) {
+      // Special-case pseudo-entry, as above.
+      if (dep.source_bb_id() == kPseudoEntryBlock ||
+          !pdom.StrictlyDominates(label, dep.source_bb_id())) {
+        edges.push_back(ControlDependence(dep.source_bb_id(), label,
+                                          dep.branch_target_bb_id()));
+      }
+    }
+  }
+}
+
+void ControlDependenceAnalysis::ComputeControlDependenceGraph(
+    const CFG& cfg, const PostDominatorAnalysis& pdom) {
+  ComputePostDominanceFrontiers(cfg, pdom);
+  ComputeForwardGraphFromReverse();
+}
+
+void ControlDependenceAnalysis::ComputeForwardGraphFromReverse() {
+  for (const auto& entry : reverse_nodes_) {
+    // Ensure an entry is created for each node.
+    forward_nodes_[entry.first];
+    for (const ControlDependence& dep : entry.second) {
+      forward_nodes_[dep.source_bb_id()].push_back(dep);
+    }
+  }
+}
+
+}  // namespace opt
+}  // namespace spvtools

+ 197 - 0
ThirdParty/Glslang/External/spirv-tools/source/opt/control_dependence.h

@@ -0,0 +1,197 @@
+// Copyright (c) 2021 Google LLC.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SOURCE_OPT_CONTROL_DEPENDENCE_H_
+#define SOURCE_OPT_CONTROL_DEPENDENCE_H_
+
+#include <algorithm>
+#include <cstdint>
+#include <functional>
+#include <ostream>
+#include <unordered_map>
+#include <vector>
+
+#include "source/opt/cfg.h"
+#include "source/opt/dominator_analysis.h"
+
+namespace spvtools {
+namespace opt {
+
+class ControlDependence {
+ public:
+  // The label of the source of this dependence, i.e. the block on which the
+  // target is dependent on.
+  // A |source_bb_id| of 0 represents an "entry" dependence, meaning that the
+  // execution of |target_bb_id| is only dependent on entry to the function.
+  uint32_t source_bb_id() const { return source_bb_id_; }
+  // The label of the target of this dependence, i.e. the block which is
+  // dependent on the source.
+  uint32_t target_bb_id() const { return target_bb_id_; }
+  // The label of the target of the *branch* for this dependence.
+  // Equal to the ID of the entry block for entry dependences.
+  //
+  // For example, for the partial CFG pictured below:
+  // 1 ---> 2 ---> 4 ---> 6
+  //  \      \            ^
+  //   \-> 3  \-> 5 -----/
+  // Block 6 is control dependent on block 1, but this dependence comes from the
+  // branch 1 -> 2, so in this case the branch target ID would be 2.
+  uint32_t branch_target_bb_id() const { return branch_target_bb_id_; }
+
+  // Create a direct control dependence from BB ID |source| to |target|.
+  ControlDependence(uint32_t source, uint32_t target)
+      : source_bb_id_(source),
+        target_bb_id_(target),
+        branch_target_bb_id_(target) {}
+  // Create a control dependence from BB ID |source| to |target| through the
+  // branch from |source| to |branch_target|.
+  ControlDependence(uint32_t source, uint32_t target, uint32_t branch_target)
+      : source_bb_id_(source),
+        target_bb_id_(target),
+        branch_target_bb_id_(branch_target) {}
+
+  // Gets the ID of the conditional value for the branch corresponding to this
+  // control dependence. This is the first input operand for both
+  // OpConditionalBranch and OpSwitch.
+  // Returns 0 for entry dependences.
+  uint32_t GetConditionID(const CFG& cfg) const;
+
+  bool operator==(const ControlDependence& other) const;
+  bool operator!=(const ControlDependence& other) const {
+    return !(*this == other);
+  }
+
+  // Comparison operators, ordered lexicographically. Total ordering.
+  bool operator<(const ControlDependence& other) const;
+  bool operator>(const ControlDependence& other) const { return other < *this; }
+  bool operator<=(const ControlDependence& other) const {
+    return !(*this > other);
+  }
+  bool operator>=(const ControlDependence& other) const {
+    return !(*this < other);
+  }
+
+ private:
+  uint32_t source_bb_id_;
+  uint32_t target_bb_id_;
+  uint32_t branch_target_bb_id_;
+};
+
+// Prints |dep| to |os| in a human-readable way. For example,
+//   1->2           (target_bb_id = branch_target_bb_id = 2)
+//   3->4 through 5 (target_bb_id = 4, branch_target_bb_id = 5)
+std::ostream& operator<<(std::ostream& os, const ControlDependence& dep);
+
+// Represents the control dependence graph. A basic block is control dependent
+// on another if the result of that block (e.g. the condition of a conditional
+// branch) influences whether it is executed or not. More formally, a block A is
+// control dependent on B iff:
+// 1. there exists a path from A to the exit node that does *not* go through B
+//    (i.e., A does not postdominate B), and
+// 2. there exists a path B -> b_1 -> ... -> b_n -> A such that A post-dominates
+//    all nodes b_i.
+class ControlDependenceAnalysis {
+ public:
+  // Map basic block labels to control dependencies/dependents.
+  // Not guaranteed to be in any particular order.
+  using ControlDependenceList = std::vector<ControlDependence>;
+  using ControlDependenceListMap =
+      std::unordered_map<uint32_t, ControlDependenceList>;
+
+  // 0, the label number for the pseudo entry block.
+  // All control dependences on the pseudo entry block are of type kEntry, and
+  // vice versa.
+  static constexpr uint32_t kPseudoEntryBlock = 0;
+
+  // Build the control dependence graph for the given control flow graph |cfg|
+  // and corresponding post-dominator analysis |pdom|.
+  void ComputeControlDependenceGraph(const CFG& cfg,
+                                     const PostDominatorAnalysis& pdom);
+
+  // Get the list of the nodes that depend on a block.
+  // Return value is not guaranteed to be in any particular order.
+  const ControlDependenceList& GetDependenceTargets(uint32_t block) const {
+    return forward_nodes_.at(block);
+  }
+
+  // Get the list of the nodes on which a block depends on.
+  // Return value is not guaranteed to be in any particular order.
+  const ControlDependenceList& GetDependenceSources(uint32_t block) const {
+    return reverse_nodes_.at(block);
+  }
+
+  // Runs the function |f| on each block label in the CDG. If any iteration
+  // returns false, immediately stops iteration and returns false. Otherwise
+  // returns true. Nodes are iterated in some undefined order, including the
+  // pseudo-entry block.
+  bool WhileEachBlockLabel(std::function<bool(uint32_t)> f) const {
+    for (const auto& entry : forward_nodes_) {
+      if (!f(entry.first)) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  // Runs the function |f| on each block label in the CDG. Nodes are iterated in
+  // some undefined order, including the pseudo-entry block.
+  void ForEachBlockLabel(std::function<void(uint32_t)> f) const {
+    WhileEachBlockLabel([&f](uint32_t label) {
+      f(label);
+      return true;
+    });
+  }
+
+  // Returns true if the block |id| exists in the control dependence graph.
+  // This can be false even if the block exists in the function when it is part
+  // of an infinite loop, since it is not part of the post-dominator tree.
+  bool HasBlock(uint32_t id) const { return forward_nodes_.count(id) > 0; }
+
+  // Returns true if block |a| is dependent on block |b|.
+  bool IsDependent(uint32_t a, uint32_t b) const {
+    if (!HasBlock(a)) return false;
+    // BBs tend to have more dependents (targets) than they are dependent on
+    // (sources), so search sources.
+    const ControlDependenceList& a_sources = GetDependenceSources(a);
+    return std::find_if(a_sources.begin(), a_sources.end(),
+                        [b](const ControlDependence& dep) {
+                          return dep.source_bb_id() == b;
+                        }) != a_sources.end();
+  }
+
+ private:
+  // Computes the post-dominance frontiers (i.e. the reverse CDG) for each node
+  // in the post-dominator tree. Only modifies reverse_nodes_; forward_nodes_ is
+  // not modified.
+  void ComputePostDominanceFrontiers(const CFG& cfg,
+                                     const PostDominatorAnalysis& pdom);
+  // Computes the post-dominance frontier for a specific node |pdom_node| in the
+  // post-dominator tree. Result is placed in reverse_nodes_[pdom_node.id()].
+  void ComputePostDominanceFrontierForNode(const CFG& cfg,
+                                           const PostDominatorAnalysis& pdom,
+                                           uint32_t function_entry,
+                                           const DominatorTreeNode& pdom_node);
+
+  // Computes the forward graph (forward_nodes_) from the reverse graph
+  // (reverse_nodes_).
+  void ComputeForwardGraphFromReverse();
+
+  ControlDependenceListMap forward_nodes_;
+  ControlDependenceListMap reverse_nodes_;
+};
+
+}  // namespace opt
+}  // namespace spvtools
+
+#endif  // SOURCE_OPT_CONTROL_DEPENDENCE_H_

+ 437 - 0
ThirdParty/Glslang/External/spirv-tools/source/opt/convert_to_sampled_image_pass.cpp

@@ -0,0 +1,437 @@
+// Copyright (c) 2021 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "source/opt/convert_to_sampled_image_pass.h"
+
+#include <cctype>
+#include <cstring>
+#include <tuple>
+
+#include "source/opt/ir_builder.h"
+#include "source/util/make_unique.h"
+#include "source/util/parse_number.h"
+
+namespace spvtools {
+namespace opt {
+
+using VectorOfDescriptorSetAndBindingPairs =
+    std::vector<DescriptorSetAndBinding>;
+using DescriptorSetBindingToInstruction =
+    ConvertToSampledImagePass::DescriptorSetBindingToInstruction;
+
+namespace {
+
+using utils::ParseNumber;
+
+// Returns true if the given char is ':', '\0' or considered as blank space
+// (i.e.: '\n', '\r', '\v', '\t', '\f' and ' ').
+bool IsSeparator(char ch) {
+  return std::strchr(":\0", ch) || std::isspace(ch) != 0;
+}
+
+// Reads characters starting from |str| until it meets a separator. Parses a
+// number from the characters and stores it into |number|. Returns the pointer
+// to the separator if it succeeds. Otherwise, returns nullptr.
+const char* ParseNumberUntilSeparator(const char* str, uint32_t* number) {
+  const char* number_begin = str;
+  while (!IsSeparator(*str)) str++;
+  const char* number_end = str;
+  std::string number_in_str(number_begin, number_end - number_begin);
+  if (!utils::ParseNumber(number_in_str.c_str(), number)) {
+    // The descriptor set is not a valid uint32 number.
+    return nullptr;
+  }
+  return str;
+}
+
+// Returns id of the image type used for the sampled image type of
+// |sampled_image|.
+uint32_t GetImageTypeOfSampledImage(analysis::TypeManager* type_mgr,
+                                    Instruction* sampled_image) {
+  auto* sampled_image_type =
+      type_mgr->GetType(sampled_image->type_id())->AsSampledImage();
+  return type_mgr->GetTypeInstruction(sampled_image_type->image_type());
+}
+
+// Finds the instruction whose id is |inst_id|. Follows the operand of
+// OpCopyObject recursively if the opcode of the instruction is OpCopyObject
+// and returns the first instruction that does not have OpCopyObject as opcode.
+Instruction* GetNonCopyObjectDef(analysis::DefUseManager* def_use_mgr,
+                                 uint32_t inst_id) {
+  Instruction* inst = def_use_mgr->GetDef(inst_id);
+  while (inst->opcode() == SpvOpCopyObject) {
+    inst_id = inst->GetSingleWordInOperand(0u);
+    inst = def_use_mgr->GetDef(inst_id);
+  }
+  return inst;
+}
+
+}  // namespace
+
+bool ConvertToSampledImagePass::GetDescriptorSetBinding(
+    const Instruction& inst,
+    DescriptorSetAndBinding* descriptor_set_binding) const {
+  auto* decoration_manager = context()->get_decoration_mgr();
+  bool found_descriptor_set_to_convert = false;
+  bool found_binding_to_convert = false;
+  for (auto decorate :
+       decoration_manager->GetDecorationsFor(inst.result_id(), false)) {
+    uint32_t decoration = decorate->GetSingleWordInOperand(1u);
+    if (decoration == SpvDecorationDescriptorSet) {
+      if (found_descriptor_set_to_convert) {
+        assert(false && "A resource has two OpDecorate for the descriptor set");
+        return false;
+      }
+      descriptor_set_binding->descriptor_set =
+          decorate->GetSingleWordInOperand(2u);
+      found_descriptor_set_to_convert = true;
+    } else if (decoration == SpvDecorationBinding) {
+      if (found_binding_to_convert) {
+        assert(false && "A resource has two OpDecorate for the binding");
+        return false;
+      }
+      descriptor_set_binding->binding = decorate->GetSingleWordInOperand(2u);
+      found_binding_to_convert = true;
+    }
+  }
+  return found_descriptor_set_to_convert && found_binding_to_convert;
+}
+
+bool ConvertToSampledImagePass::ShouldResourceBeConverted(
+    const DescriptorSetAndBinding& descriptor_set_binding) const {
+  return descriptor_set_binding_pairs_.find(descriptor_set_binding) !=
+         descriptor_set_binding_pairs_.end();
+}
+
+const analysis::Type* ConvertToSampledImagePass::GetVariableType(
+    const Instruction& variable) const {
+  if (variable.opcode() != SpvOpVariable) return nullptr;
+  auto* type = context()->get_type_mgr()->GetType(variable.type_id());
+  auto* pointer_type = type->AsPointer();
+  if (!pointer_type) return nullptr;
+
+  return pointer_type->pointee_type();
+}
+
+SpvStorageClass ConvertToSampledImagePass::GetStorageClass(
+    const Instruction& variable) const {
+  assert(variable.opcode() == SpvOpVariable);
+  auto* type = context()->get_type_mgr()->GetType(variable.type_id());
+  auto* pointer_type = type->AsPointer();
+  if (!pointer_type) return SpvStorageClassMax;
+
+  return pointer_type->storage_class();
+}
+
+bool ConvertToSampledImagePass::CollectResourcesToConvert(
+    DescriptorSetBindingToInstruction* descriptor_set_binding_pair_to_sampler,
+    DescriptorSetBindingToInstruction* descriptor_set_binding_pair_to_image)
+    const {
+  for (auto& inst : context()->types_values()) {
+    const auto* variable_type = GetVariableType(inst);
+    if (variable_type == nullptr) continue;
+
+    DescriptorSetAndBinding descriptor_set_binding;
+    if (!GetDescriptorSetBinding(inst, &descriptor_set_binding)) continue;
+
+    if (!ShouldResourceBeConverted(descriptor_set_binding)) {
+      continue;
+    }
+
+    if (variable_type->AsImage()) {
+      if (!descriptor_set_binding_pair_to_image
+               ->insert({descriptor_set_binding, &inst})
+               .second) {
+        return false;
+      }
+    } else if (variable_type->AsSampler()) {
+      if (!descriptor_set_binding_pair_to_sampler
+               ->insert({descriptor_set_binding, &inst})
+               .second) {
+        return false;
+      }
+    }
+  }
+  return true;
+}
+
+Pass::Status ConvertToSampledImagePass::Process() {
+  Status status = Status::SuccessWithoutChange;
+
+  DescriptorSetBindingToInstruction descriptor_set_binding_pair_to_sampler,
+      descriptor_set_binding_pair_to_image;
+  if (!CollectResourcesToConvert(&descriptor_set_binding_pair_to_sampler,
+                                 &descriptor_set_binding_pair_to_image)) {
+    return Status::Failure;
+  }
+
+  for (auto& image : descriptor_set_binding_pair_to_image) {
+    status = CombineStatus(
+        status, UpdateImageVariableToSampledImage(image.second, image.first));
+    if (status == Status::Failure) {
+      return status;
+    }
+  }
+
+  for (const auto& sampler : descriptor_set_binding_pair_to_sampler) {
+    // Converting only a Sampler to Sampled Image is not allowed. It must have a
+    // corresponding image to combine the sampler with.
+    auto image_itr = descriptor_set_binding_pair_to_image.find(sampler.first);
+    if (image_itr == descriptor_set_binding_pair_to_image.end() ||
+        image_itr->second == nullptr) {
+      return Status::Failure;
+    }
+
+    status = CombineStatus(
+        status, CheckUsesOfSamplerVariable(sampler.second, image_itr->second));
+    if (status == Status::Failure) {
+      return status;
+    }
+  }
+
+  return status;
+}
+
+void ConvertToSampledImagePass::FindUses(const Instruction* inst,
+                                         std::vector<Instruction*>* uses,
+                                         uint32_t user_opcode) const {
+  auto* def_use_mgr = context()->get_def_use_mgr();
+  def_use_mgr->ForEachUser(inst, [uses, user_opcode, this](Instruction* user) {
+    if (user->opcode() == user_opcode) {
+      uses->push_back(user);
+    } else if (user->opcode() == SpvOpCopyObject) {
+      FindUses(user, uses, user_opcode);
+    }
+  });
+}
+
+void ConvertToSampledImagePass::FindUsesOfImage(
+    const Instruction* image, std::vector<Instruction*>* uses) const {
+  auto* def_use_mgr = context()->get_def_use_mgr();
+  def_use_mgr->ForEachUser(image, [uses, this](Instruction* user) {
+    switch (user->opcode()) {
+      case SpvOpImageFetch:
+      case SpvOpImageRead:
+      case SpvOpImageWrite:
+      case SpvOpImageQueryFormat:
+      case SpvOpImageQueryOrder:
+      case SpvOpImageQuerySizeLod:
+      case SpvOpImageQuerySize:
+      case SpvOpImageQueryLevels:
+      case SpvOpImageQuerySamples:
+      case SpvOpImageSparseFetch:
+        uses->push_back(user);
+      default:
+        break;
+    }
+    if (user->opcode() == SpvOpCopyObject) {
+      FindUsesOfImage(user, uses);
+    }
+  });
+}
+
+Instruction* ConvertToSampledImagePass::CreateImageExtraction(
+    Instruction* sampled_image) {
+  InstructionBuilder builder(
+      context(), sampled_image->NextNode(),
+      IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping);
+  return builder.AddUnaryOp(
+      GetImageTypeOfSampledImage(context()->get_type_mgr(), sampled_image),
+      SpvOpImage, sampled_image->result_id());
+}
+
+uint32_t ConvertToSampledImagePass::GetSampledImageTypeForImage(
+    Instruction* image_variable) {
+  const auto* variable_type = GetVariableType(*image_variable);
+  if (variable_type == nullptr) return 0;
+  const auto* image_type = variable_type->AsImage();
+  if (image_type == nullptr) return 0;
+
+  analysis::Image image_type_for_sampled_image(*image_type);
+  analysis::SampledImage sampled_image_type(&image_type_for_sampled_image);
+  return context()->get_type_mgr()->GetTypeInstruction(&sampled_image_type);
+}
+
+Instruction* ConvertToSampledImagePass::UpdateImageUses(
+    Instruction* sampled_image_load) {
+  std::vector<Instruction*> uses_of_load;
+  FindUsesOfImage(sampled_image_load, &uses_of_load);
+  if (uses_of_load.empty()) return nullptr;
+
+  auto* extracted_image = CreateImageExtraction(sampled_image_load);
+  for (auto* user : uses_of_load) {
+    user->SetInOperand(0, {extracted_image->result_id()});
+    context()->get_def_use_mgr()->AnalyzeInstUse(user);
+  }
+  return extracted_image;
+}
+
+bool ConvertToSampledImagePass::
+    IsSamplerOfSampledImageDecoratedByDescriptorSetBinding(
+        Instruction* sampled_image_inst,
+        const DescriptorSetAndBinding& descriptor_set_binding) {
+  auto* def_use_mgr = context()->get_def_use_mgr();
+  uint32_t sampler_id = sampled_image_inst->GetSingleWordInOperand(1u);
+  auto* sampler_load = def_use_mgr->GetDef(sampler_id);
+  if (sampler_load->opcode() != SpvOpLoad) return false;
+  auto* sampler = def_use_mgr->GetDef(sampler_load->GetSingleWordInOperand(0u));
+  DescriptorSetAndBinding sampler_descriptor_set_binding;
+  return GetDescriptorSetBinding(*sampler, &sampler_descriptor_set_binding) &&
+         sampler_descriptor_set_binding == descriptor_set_binding;
+}
+
+void ConvertToSampledImagePass::UpdateSampledImageUses(
+    Instruction* image_load, Instruction* image_extraction,
+    const DescriptorSetAndBinding& image_descriptor_set_binding) {
+  std::vector<Instruction*> sampled_image_users;
+  FindUses(image_load, &sampled_image_users, SpvOpSampledImage);
+
+  auto* def_use_mgr = context()->get_def_use_mgr();
+  for (auto* sampled_image_inst : sampled_image_users) {
+    if (IsSamplerOfSampledImageDecoratedByDescriptorSetBinding(
+            sampled_image_inst, image_descriptor_set_binding)) {
+      context()->ReplaceAllUsesWith(sampled_image_inst->result_id(),
+                                    image_load->result_id());
+      def_use_mgr->AnalyzeInstUse(image_load);
+      context()->KillInst(sampled_image_inst);
+    } else {
+      if (!image_extraction)
+        image_extraction = CreateImageExtraction(image_load);
+      sampled_image_inst->SetInOperand(0, {image_extraction->result_id()});
+      def_use_mgr->AnalyzeInstUse(sampled_image_inst);
+    }
+  }
+}
+
+void ConvertToSampledImagePass::MoveInstructionNextToType(Instruction* inst,
+                                                          uint32_t type_id) {
+  auto* type_inst = context()->get_def_use_mgr()->GetDef(type_id);
+  inst->SetResultType(type_id);
+  inst->RemoveFromList();
+  inst->InsertAfter(type_inst);
+}
+
+bool ConvertToSampledImagePass::ConvertImageVariableToSampledImage(
+    Instruction* image_variable, uint32_t sampled_image_type_id) {
+  auto* sampled_image_type =
+      context()->get_type_mgr()->GetType(sampled_image_type_id);
+  if (sampled_image_type == nullptr) return false;
+  auto storage_class = GetStorageClass(*image_variable);
+  if (storage_class == SpvStorageClassMax) return false;
+  analysis::Pointer sampled_image_pointer(sampled_image_type, storage_class);
+
+  // Make sure |image_variable| is behind its type i.e., avoid the forward
+  // reference.
+  uint32_t type_id =
+      context()->get_type_mgr()->GetTypeInstruction(&sampled_image_pointer);
+  MoveInstructionNextToType(image_variable, type_id);
+  return true;
+}
+
+Pass::Status ConvertToSampledImagePass::UpdateImageVariableToSampledImage(
+    Instruction* image_variable,
+    const DescriptorSetAndBinding& descriptor_set_binding) {
+  std::vector<Instruction*> image_variable_loads;
+  FindUses(image_variable, &image_variable_loads, SpvOpLoad);
+  if (image_variable_loads.empty()) return Status::SuccessWithoutChange;
+
+  const uint32_t sampled_image_type_id =
+      GetSampledImageTypeForImage(image_variable);
+  if (!sampled_image_type_id) return Status::Failure;
+
+  for (auto* load : image_variable_loads) {
+    load->SetResultType(sampled_image_type_id);
+    auto* image_extraction = UpdateImageUses(load);
+    UpdateSampledImageUses(load, image_extraction, descriptor_set_binding);
+  }
+
+  return ConvertImageVariableToSampledImage(image_variable,
+                                            sampled_image_type_id)
+             ? Status::SuccessWithChange
+             : Status::Failure;
+}
+
+bool ConvertToSampledImagePass::DoesSampledImageReferenceImage(
+    Instruction* sampled_image_inst, Instruction* image_variable) {
+  if (sampled_image_inst->opcode() != SpvOpSampledImage) return false;
+  auto* def_use_mgr = context()->get_def_use_mgr();
+  auto* image_load = GetNonCopyObjectDef(
+      def_use_mgr, sampled_image_inst->GetSingleWordInOperand(0u));
+  if (image_load->opcode() != SpvOpLoad) return false;
+  auto* image =
+      GetNonCopyObjectDef(def_use_mgr, image_load->GetSingleWordInOperand(0u));
+  return image->opcode() == SpvOpVariable &&
+         image->result_id() == image_variable->result_id();
+}
+
+Pass::Status ConvertToSampledImagePass::CheckUsesOfSamplerVariable(
+    const Instruction* sampler_variable,
+    Instruction* image_to_be_combined_with) {
+  if (image_to_be_combined_with == nullptr) return Status::Failure;
+
+  std::vector<Instruction*> sampler_variable_loads;
+  FindUses(sampler_variable, &sampler_variable_loads, SpvOpLoad);
+  for (auto* load : sampler_variable_loads) {
+    std::vector<Instruction*> sampled_image_users;
+    FindUses(load, &sampled_image_users, SpvOpSampledImage);
+    for (auto* sampled_image_inst : sampled_image_users) {
+      if (!DoesSampledImageReferenceImage(sampled_image_inst,
+                                          image_to_be_combined_with)) {
+        return Status::Failure;
+      }
+    }
+  }
+  return Status::SuccessWithoutChange;
+}
+
+std::unique_ptr<VectorOfDescriptorSetAndBindingPairs>
+ConvertToSampledImagePass::ParseDescriptorSetBindingPairsString(
+    const char* str) {
+  if (!str) return nullptr;
+
+  auto descriptor_set_binding_pairs =
+      MakeUnique<VectorOfDescriptorSetAndBindingPairs>();
+
+  while (std::isspace(*str)) str++;  // skip leading spaces.
+
+  // The parsing loop, break when points to the end.
+  while (*str) {
+    // Parse the descriptor set.
+    uint32_t descriptor_set = 0;
+    str = ParseNumberUntilSeparator(str, &descriptor_set);
+    if (str == nullptr) return nullptr;
+
+    // Find the ':', spaces between the descriptor set and the ':' are not
+    // allowed.
+    if (*str++ != ':') {
+      // ':' not found
+      return nullptr;
+    }
+
+    // Parse the binding.
+    uint32_t binding = 0;
+    str = ParseNumberUntilSeparator(str, &binding);
+    if (str == nullptr) return nullptr;
+
+    descriptor_set_binding_pairs->push_back({descriptor_set, binding});
+
+    // Skip trailing spaces.
+    while (std::isspace(*str)) str++;
+  }
+
+  return descriptor_set_binding_pairs;
+}
+
+}  // namespace opt
+}  // namespace spvtools

+ 207 - 0
ThirdParty/Glslang/External/spirv-tools/source/opt/convert_to_sampled_image_pass.h

@@ -0,0 +1,207 @@
+// Copyright (c) 2021 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SOURCE_OPT_CONVERT_TO_SAMPLED_IMAGE_PASS_H_
+#define SOURCE_OPT_CONVERT_TO_SAMPLED_IMAGE_PASS_H_
+
+#include <memory>
+#include <unordered_set>
+#include <utility>
+
+#include "source/opt/pass.h"
+#include "source/opt/types.h"
+
+namespace spvtools {
+namespace opt {
+
+// A struct for a pair of descriptor set and binding.
+struct DescriptorSetAndBinding {
+  uint32_t descriptor_set;
+  uint32_t binding;
+
+  bool operator==(const DescriptorSetAndBinding& descriptor_set_binding) const {
+    return descriptor_set_binding.descriptor_set == descriptor_set &&
+           descriptor_set_binding.binding == binding;
+  }
+};
+
+// See optimizer.hpp for documentation.
+class ConvertToSampledImagePass : public Pass {
+ public:
+  // Hashing functor for the pair of descriptor set and binding.
+  struct DescriptorSetAndBindingHash {
+    size_t operator()(
+        const DescriptorSetAndBinding& descriptor_set_binding) const {
+      return std::hash<uint32_t>()(descriptor_set_binding.descriptor_set) ^
+             std::hash<uint32_t>()(descriptor_set_binding.binding);
+    }
+  };
+
+  using SetOfDescriptorSetAndBindingPairs =
+      std::unordered_set<DescriptorSetAndBinding, DescriptorSetAndBindingHash>;
+  using DescriptorSetBindingToInstruction =
+      std::unordered_map<DescriptorSetAndBinding, Instruction*,
+                         DescriptorSetAndBindingHash>;
+
+  explicit ConvertToSampledImagePass(
+      const std::vector<DescriptorSetAndBinding>& descriptor_set_binding_pairs)
+      : descriptor_set_binding_pairs_(descriptor_set_binding_pairs.begin(),
+                                      descriptor_set_binding_pairs.end()) {}
+
+  const char* name() const override { return "convert-to-sampled-image"; }
+  Status Process() override;
+
+  // Parses the given null-terminated C string to get a vector of descriptor set
+  // and binding pairs. Returns a unique pointer to the vector of descriptor set
+  // and binding pairs built from the given |str| on success. Returns a nullptr
+  // if the given string is not valid for building the vector of pairs.
+  // A valid string for building the vector of pairs should follow the rule
+  // below:
+  //
+  //  "<descriptor set>:<binding> <descriptor set>:<binding> ..."
+  //  Example:
+  //    "3:5 2:1 0:4"
+  //
+  //  Entries are separated with blank spaces (i.e.:' ', '\n', '\r', '\t',
+  //  '\f', '\v'). Each entry corresponds to a descriptor set and binding pair.
+  //  Multiple spaces between, before or after entries are allowed. However,
+  //  spaces are not allowed within a descriptor set or binding.
+  //
+  //  In each entry, the descriptor set and binding are separated by ':'.
+  //  Missing ':' in any entry is invalid. And it is invalid to have blank
+  //  spaces in between the descriptor set and ':' or ':' and the binding.
+  //
+  //  <descriptor set>: the descriptor set.
+  //    The text must represent a valid uint32_t number.
+  //
+  //  <binding>: the binding.
+  //    The text must represent a valid uint32_t number.
+  static std::unique_ptr<std::vector<DescriptorSetAndBinding>>
+  ParseDescriptorSetBindingPairsString(const char* str);
+
+ private:
+  // Collects resources to convert to sampled image and saves them in
+  // |descriptor_set_binding_pair_to_sampler| if the resource is a sampler and
+  // saves them in |descriptor_set_binding_pair_to_image| if the resource is an
+  // image. Returns false if two samplers or two images have the same descriptor
+  // set and binding. Otherwise, returns true.
+  bool CollectResourcesToConvert(
+      DescriptorSetBindingToInstruction* descriptor_set_binding_pair_to_sampler,
+      DescriptorSetBindingToInstruction* descriptor_set_binding_pair_to_image)
+      const;
+
+  // Finds an OpDecorate with DescriptorSet decorating |inst| and another
+  // OpDecorate with Binding decorating |inst|. Stores the descriptor set and
+  // binding in |descriptor_set_binding|. Returns whether it successfully finds
+  // the descriptor set and binding or not.
+  bool GetDescriptorSetBinding(
+      const Instruction& inst,
+      DescriptorSetAndBinding* descriptor_set_binding) const;
+
+  // Returns whether |descriptor_set_binding| is a pair of a descriptor set
+  // and a binding that we have to convert resources with it to a sampled image
+  // or not.
+  bool ShouldResourceBeConverted(
+      const DescriptorSetAndBinding& descriptor_set_binding) const;
+
+  // Returns the pointee type of the type of variable |variable|. If |variable|
+  // is not an OpVariable instruction, just returns nullptr.
+  const analysis::Type* GetVariableType(const Instruction& variable) const;
+
+  // Returns the storage class of |variable|.
+  SpvStorageClass GetStorageClass(const Instruction& variable) const;
+
+  // Finds |inst|'s users whose opcode is |user_opcode| or users of OpCopyObject
+  // instructions of |inst| whose opcode is |user_opcode| and puts them in
+  // |uses|.
+  void FindUses(const Instruction* inst, std::vector<Instruction*>* uses,
+                uint32_t user_opcode) const;
+
+  // Finds OpImage* instructions using |image| or OpCopyObject instructions that
+  // copy |image| and puts them in |uses|.
+  void FindUsesOfImage(const Instruction* image,
+                       std::vector<Instruction*>* uses) const;
+
+  // Creates an OpImage instruction that extracts the image from the sampled
+  // image |sampled_image|.
+  Instruction* CreateImageExtraction(Instruction* sampled_image);
+
+  // Converts |image_variable| whose type is an image pointer to sampled image
+  // type. Updates users of |image_variable| accordingly. If some instructions
+  // e.g., OpImageRead use |image_variable| as an Image operand, creates an
+  // image extracted from the sampled image using OpImage and replace the Image
+  // operands of the users with the extracted image. If some OpSampledImage
+  // instructions use |image_variable| and sampler whose descriptor set and
+  // binding are the same with |image_variable|, just combines |image_variable|
+  // and the sampler to a sampled image.
+  Pass::Status UpdateImageVariableToSampledImage(
+      Instruction* image_variable,
+      const DescriptorSetAndBinding& descriptor_set_binding);
+
+  // Returns the id of type sampled image type whose image type is the one of
+  // |image_variable|.
+  uint32_t GetSampledImageTypeForImage(Instruction* image_variable);
+
+  // Moves |inst| next to the OpType* instruction with |type_id|.
+  void MoveInstructionNextToType(Instruction* inst, uint32_t type_id);
+
+  // Converts |image_variable| whose type is an image pointer to sampled image
+  // with the type id |sampled_image_type_id|. Returns whether it successfully
+  // converts the type of |image_variable| or not.
+  bool ConvertImageVariableToSampledImage(Instruction* image_variable,
+                                          uint32_t sampled_image_type_id);
+
+  // Replaces |sampled_image_load| instruction used by OpImage* with the image
+  // extracted from |sampled_image_load|. Returns the extracted image or nullptr
+  // if it does not have uses.
+  Instruction* UpdateImageUses(Instruction* sampled_image_load);
+
+  // Returns true if the sampler of |sampled_image_inst| is decorated by a
+  // descriptor set and a binding |descriptor_set_binding|.
+  bool IsSamplerOfSampledImageDecoratedByDescriptorSetBinding(
+      Instruction* sampled_image_inst,
+      const DescriptorSetAndBinding& descriptor_set_binding);
+
+  // Replaces OpSampledImage instructions using |image_load| with |image_load|
+  // if the sampler of the OpSampledImage instruction has descriptor set and
+  // binding |image_descriptor_set_binding|. Otherwise, replaces |image_load|
+  // with |image_extraction|.
+  void UpdateSampledImageUses(
+      Instruction* image_load, Instruction* image_extraction,
+      const DescriptorSetAndBinding& image_descriptor_set_binding);
+
+  // Checks the uses of |sampler_variable|. When a sampler is used by
+  // OpSampledImage instruction, the corresponding image must be
+  // |image_to_be_combined_with| that should be already converted to a sampled
+  // image by UpdateImageVariableToSampledImage() method.
+  Pass::Status CheckUsesOfSamplerVariable(
+      const Instruction* sampler_variable,
+      Instruction* image_to_be_combined_with);
+
+  // Returns true if Image operand of |sampled_image_inst| is the image of
+  // |image_variable|.
+  bool DoesSampledImageReferenceImage(Instruction* sampled_image_inst,
+                                      Instruction* image_variable);
+
+  // A set of pairs of descriptor set and binding. If an image and/or a sampler
+  // have a pair of descriptor set and binding that is an element of
+  // |descriptor_set_binding_pairs_|, they/it will be converted to a sampled
+  // image by this pass.
+  const SetOfDescriptorSetAndBindingPairs descriptor_set_binding_pairs_;
+};
+
+}  // namespace opt
+}  // namespace spvtools
+
+#endif  // SOURCE_OPT_CONVERT_TO_SAMPLED_IMAGE_PASS_H_

+ 91 - 0
ThirdParty/Glslang/External/spirv-tools/source/opt/dataflow.cpp

@@ -0,0 +1,91 @@
+// Copyright (c) 2021 Google LLC.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "source/opt/dataflow.h"
+
+#include <algorithm>
+#include <cstdint>
+
+namespace spvtools {
+namespace opt {
+
+bool DataFlowAnalysis::Enqueue(Instruction* inst) {
+  bool& is_enqueued = on_worklist_[inst];
+  if (is_enqueued) return false;
+  is_enqueued = true;
+  worklist_.push(inst);
+  return true;
+}
+
+DataFlowAnalysis::VisitResult DataFlowAnalysis::RunOnce(
+    Function* function, bool is_first_iteration) {
+  InitializeWorklist(function, is_first_iteration);
+  VisitResult ret = VisitResult::kResultFixed;
+  while (!worklist_.empty()) {
+    Instruction* top = worklist_.front();
+    worklist_.pop();
+    on_worklist_[top] = false;
+    VisitResult result = Visit(top);
+    if (result == VisitResult::kResultChanged) {
+      EnqueueSuccessors(top);
+      ret = VisitResult::kResultChanged;
+    }
+  }
+  return ret;
+}
+
+void DataFlowAnalysis::Run(Function* function) {
+  VisitResult result = RunOnce(function, true);
+  while (result == VisitResult::kResultChanged) {
+    result = RunOnce(function, false);
+  }
+}
+
+void ForwardDataFlowAnalysis::InitializeWorklist(Function* function,
+                                                 bool /*is_first_iteration*/) {
+  context().cfg()->ForEachBlockInReversePostOrder(
+      function->entry().get(), [this](BasicBlock* bb) {
+        if (label_position_ == LabelPosition::kLabelsOnly) {
+          Enqueue(bb->GetLabelInst());
+          return;
+        }
+        if (label_position_ == LabelPosition::kLabelsAtBeginning) {
+          Enqueue(bb->GetLabelInst());
+        }
+        for (Instruction& inst : *bb) {
+          Enqueue(&inst);
+        }
+        if (label_position_ == LabelPosition::kLabelsAtEnd) {
+          Enqueue(bb->GetLabelInst());
+        }
+      });
+}
+
+void ForwardDataFlowAnalysis::EnqueueUsers(Instruction* inst) {
+  context().get_def_use_mgr()->ForEachUser(
+      inst, [this](Instruction* user) { Enqueue(user); });
+}
+
+void ForwardDataFlowAnalysis::EnqueueBlockSuccessors(Instruction* inst) {
+  if (inst->opcode() != SpvOpLabel) return;
+  context()
+      .cfg()
+      ->block(inst->result_id())
+      ->ForEachSuccessorLabel([this](uint32_t* label) {
+        Enqueue(context().cfg()->block(*label)->GetLabelInst());
+      });
+}
+
+}  // namespace opt
+}  // namespace spvtools

+ 148 - 0
ThirdParty/Glslang/External/spirv-tools/source/opt/dataflow.h

@@ -0,0 +1,148 @@
+// Copyright (c) 2021 Google LLC.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SOURCE_OPT_DATAFLOW_H_
+#define SOURCE_OPT_DATAFLOW_H_
+
+#include <queue>
+#include <unordered_map>
+#include <vector>
+
+#include "source/opt/instruction.h"
+#include "source/opt/ir_context.h"
+
+namespace spvtools {
+namespace opt {
+
+// Generic data-flow analysis.
+// Maintains a worklist of instructions to process and processes them in a
+// specified order. See also ForwardDataFlowAnalysis, which is specialized for
+// forward data-flow analysis.
+class DataFlowAnalysis {
+ public:
+  // The result of a |Visit| operation on an instruction.
+  // This is used to determine when analysis has reached a fixpoint.
+  enum class VisitResult {
+    // The analysis result for this instruction has changed.
+    // This means that any instructions that depend on it (its successors) must
+    // be recomputed.
+    kResultChanged,
+    // The analysis result for this instruction has not changed.
+    // When all visit operations return |kResultFixed|, the analysis has reached
+    // a fixpoint (converged).
+    kResultFixed,
+  };
+
+  virtual ~DataFlowAnalysis() {}
+
+  // Run this analysis on a given function.
+  // For analyses which work interprocedurally, |function| may be ignored.
+  void Run(Function* function);
+
+ protected:
+  DataFlowAnalysis(IRContext& context) : context_(context) {}
+
+  // Initialize the worklist for a given function.
+  // |is_first_iteration| is true on the first call to |Run| and false
+  // afterwards. All subsequent runs are only necessary to check if the analysis
+  // has converged; if |EnqueueSuccessors| is complete, |InitializeWorklist|
+  // should do nothing after the first iteration.
+  virtual void InitializeWorklist(Function* function,
+                                  bool is_first_iteration) = 0;
+
+  // Enqueues the successors (instructions which use the analysis result) of
+  // |inst|. This is not required to be complete, but convergence is faster when
+  // it is. This is called whenever |Visit| returns |kResultChanged|.
+  virtual void EnqueueSuccessors(Instruction* inst) = 0;
+
+  // Visits the given instruction, recomputing the analysis result. This is
+  // called once per instruction queued in |InitializeWorklist| and afterward
+  // when a predecessor is changed, through |EnqueueSuccessors|.
+  virtual VisitResult Visit(Instruction* inst) = 0;
+
+  // Enqueues the given instruction to be visited. Ignored if already in the
+  // worklist.
+  bool Enqueue(Instruction* inst);
+
+  IRContext& context() { return context_; }
+
+ private:
+  // Runs one pass, calling |InitializeWorklist| and then iterating through the
+  // worklist until all fixed.
+  VisitResult RunOnce(Function* function, bool is_first_iteration);
+
+  IRContext& context_;
+  std::unordered_map<Instruction*, bool> on_worklist_;
+  // The worklist, which contains the list of instructions to be visited.
+  //
+  // The choice of data structure was influenced by the data in "Iterative
+  // Data-flow Analysis, Revisited" (Cooper et al, 2002).
+  // https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.125.1549&rep=rep1&type=pdf
+  // The paper shows that the overall performance benefit of a priority queue
+  // over a regular queue or stack is relatively small (or negative).
+  //
+  // A queue has the advantage that nodes are visited in the same order they are
+  // enqueued, which relieves the analysis from inserting nodes "backwards", for
+  // example in worklist initialization. Also, as the paper claims that sorting
+  // successors does not improve runtime, we can use a single queue which is
+  // modified during iteration.
+  std::queue<Instruction*> worklist_;
+};
+
+// A generic data flow analysis, specialized for forward analysis.
+class ForwardDataFlowAnalysis : public DataFlowAnalysis {
+ public:
+  // Indicates where labels should be in the worklist RPO ordering.
+  enum class LabelPosition {
+    // Labels should be placed at the beginning of their blocks.
+    kLabelsAtBeginning,
+    // Labels should be placed at the end of their blocks.
+    kLabelsAtEnd,
+    // Labels should not be in the worklist.
+    kNoLabels,
+    // Only labels should be placed in the worklist.
+    kLabelsOnly,
+  };
+
+  ForwardDataFlowAnalysis(IRContext& context, LabelPosition label_position)
+      : DataFlowAnalysis(context), label_position_(label_position) {}
+
+ protected:
+  // Initializes the worklist in reverse postorder, regardless of
+  // |is_first_iteration|. Labels are placed according to the label position
+  // specified in the constructor.
+  void InitializeWorklist(Function* function, bool is_first_iteration) override;
+
+  // Enqueues the users and block successors of the given instruction.
+  // See |EnqueueUsers| and |EnqueueBlockSuccessors|.
+  void EnqueueSuccessors(Instruction* inst) override {
+    EnqueueUsers(inst);
+    EnqueueBlockSuccessors(inst);
+  }
+
+  // Enqueues the users of the given instruction.
+  void EnqueueUsers(Instruction* inst);
+
+  // Enqueues the labels of the successors of the block corresponding to the
+  // given label instruction. Does nothing for other instructions.
+  void EnqueueBlockSuccessors(Instruction* inst);
+
+ private:
+  LabelPosition label_position_;
+};
+
+}  // namespace opt
+}  // namespace spvtools
+
+#endif  // SOURCE_OPT_DATAFLOW_H_

+ 117 - 0
ThirdParty/Glslang/External/spirv-tools/source/opt/desc_sroa_util.cpp

@@ -0,0 +1,117 @@
+// Copyright (c) 2021 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "source/opt/desc_sroa_util.h"
+
+namespace spvtools {
+namespace opt {
+namespace {
+
+const uint32_t kOpAccessChainInOperandIndexes = 1;
+
+// Returns the length of array type |type|.
+uint32_t GetLengthOfArrayType(IRContext* context, Instruction* type) {
+  assert(type->opcode() == SpvOpTypeArray && "type must be array");
+  uint32_t length_id = type->GetSingleWordInOperand(1);
+  const analysis::Constant* length_const =
+      context->get_constant_mgr()->FindDeclaredConstant(length_id);
+  assert(length_const != nullptr);
+  return length_const->GetU32();
+}
+
+}  // namespace
+
+namespace descsroautil {
+
+bool IsDescriptorArray(IRContext* context, Instruction* var) {
+  if (var->opcode() != SpvOpVariable) {
+    return false;
+  }
+
+  uint32_t ptr_type_id = var->type_id();
+  Instruction* ptr_type_inst = context->get_def_use_mgr()->GetDef(ptr_type_id);
+  if (ptr_type_inst->opcode() != SpvOpTypePointer) {
+    return false;
+  }
+
+  uint32_t var_type_id = ptr_type_inst->GetSingleWordInOperand(1);
+  Instruction* var_type_inst = context->get_def_use_mgr()->GetDef(var_type_id);
+  if (var_type_inst->opcode() != SpvOpTypeArray &&
+      var_type_inst->opcode() != SpvOpTypeStruct) {
+    return false;
+  }
+
+  // All structures with descriptor assignments must be replaced by variables,
+  // one for each of their members - with the exceptions of buffers.
+  if (IsTypeOfStructuredBuffer(context, var_type_inst)) {
+    return false;
+  }
+
+  if (!context->get_decoration_mgr()->HasDecoration(
+          var->result_id(), SpvDecorationDescriptorSet)) {
+    return false;
+  }
+
+  return context->get_decoration_mgr()->HasDecoration(var->result_id(),
+                                                      SpvDecorationBinding);
+}
+
+bool IsTypeOfStructuredBuffer(IRContext* context, const Instruction* type) {
+  if (type->opcode() != SpvOpTypeStruct) {
+    return false;
+  }
+
+  // All buffers have offset decorations for members of their structure types.
+  // This is how we distinguish it from a structure of descriptors.
+  return context->get_decoration_mgr()->HasDecoration(type->result_id(),
+                                                      SpvDecorationOffset);
+}
+
+const analysis::Constant* GetAccessChainIndexAsConst(
+    IRContext* context, Instruction* access_chain) {
+  if (access_chain->NumInOperands() <= 1) {
+    return nullptr;
+  }
+  uint32_t idx_id = GetFirstIndexOfAccessChain(access_chain);
+  const analysis::Constant* idx_const =
+      context->get_constant_mgr()->FindDeclaredConstant(idx_id);
+  return idx_const;
+}
+
+uint32_t GetFirstIndexOfAccessChain(Instruction* access_chain) {
+  assert(access_chain->NumInOperands() > 1 &&
+         "OpAccessChain does not have Indexes operand");
+  return access_chain->GetSingleWordInOperand(kOpAccessChainInOperandIndexes);
+}
+
+uint32_t GetNumberOfElementsForArrayOrStruct(IRContext* context,
+                                             Instruction* var) {
+  uint32_t ptr_type_id = var->type_id();
+  Instruction* ptr_type_inst = context->get_def_use_mgr()->GetDef(ptr_type_id);
+  assert(ptr_type_inst->opcode() == SpvOpTypePointer &&
+         "Variable should be a pointer to an array or structure.");
+  uint32_t pointee_type_id = ptr_type_inst->GetSingleWordInOperand(1);
+  Instruction* pointee_type_inst =
+      context->get_def_use_mgr()->GetDef(pointee_type_id);
+  if (pointee_type_inst->opcode() == SpvOpTypeArray) {
+    return GetLengthOfArrayType(context, pointee_type_inst);
+  }
+  assert(pointee_type_inst->opcode() == SpvOpTypeStruct &&
+         "Variable should be a pointer to an array or structure.");
+  return pointee_type_inst->NumInOperands();
+}
+
+}  // namespace descsroautil
+}  // namespace opt
+}  // namespace spvtools

+ 54 - 0
ThirdParty/Glslang/External/spirv-tools/source/opt/desc_sroa_util.h

@@ -0,0 +1,54 @@
+// Copyright (c) 2021 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SOURCE_OPT_DESC_SROA_UTIL_H_
+#define SOURCE_OPT_DESC_SROA_UTIL_H_
+
+#include "source/opt/ir_context.h"
+
+namespace spvtools {
+namespace opt {
+
+// Provides functions for the descriptor array SROA.
+namespace descsroautil {
+
+// Returns true if |var| is an OpVariable instruction that represents a
+// descriptor array.
+bool IsDescriptorArray(IRContext* context, Instruction* var);
+
+// Returns true if |type| is a type that could be used for a structured buffer
+// as opposed to a type that would be used for a structure of resource
+// descriptors.
+bool IsTypeOfStructuredBuffer(IRContext* context, const Instruction* type);
+
+// Returns the first index of the OpAccessChain instruction |access_chain| as
+// a constant. Returns nullptr if it is not a constant.
+const analysis::Constant* GetAccessChainIndexAsConst(IRContext* context,
+                                                     Instruction* access_chain);
+
+// Returns the number of elements of an OpVariable instruction |var| whose type
+// must be a pointer to an array or a struct.
+uint32_t GetNumberOfElementsForArrayOrStruct(IRContext* context,
+                                             Instruction* var);
+
+// Returns the first Indexes operand id of the OpAccessChain or
+// OpInBoundsAccessChain instruction |access_chain|. The access chain must have
+// at least 1 index.
+uint32_t GetFirstIndexOfAccessChain(Instruction* access_chain);
+
+}  // namespace descsroautil
+}  // namespace opt
+}  // namespace spvtools
+
+#endif  // SOURCE_OPT_DESC_SROA_UTIL_H_

+ 146 - 0
ThirdParty/Glslang/External/spirv-tools/source/opt/eliminate_dead_input_components_pass.cpp

@@ -0,0 +1,146 @@
+// Copyright (c) 2022 The Khronos Group Inc.
+// Copyright (c) 2022 LunarG Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "source/opt/eliminate_dead_input_components_pass.h"
+
+#include <set>
+#include <vector>
+
+#include "source/opt/instruction.h"
+#include "source/opt/ir_builder.h"
+#include "source/opt/ir_context.h"
+#include "source/util/bit_vector.h"
+
+namespace {
+
+const uint32_t kAccessChainBaseInIdx = 0;
+const uint32_t kAccessChainIndex0InIdx = 1;
+const uint32_t kConstantValueInIdx = 0;
+const uint32_t kVariableStorageClassInIdx = 0;
+
+}  // namespace
+
+namespace spvtools {
+namespace opt {
+
+Pass::Status EliminateDeadInputComponentsPass::Process() {
+  // Current functionality assumes shader capability
+  if (!context()->get_feature_mgr()->HasCapability(SpvCapabilityShader))
+    return Status::SuccessWithoutChange;
+  analysis::DefUseManager* def_use_mgr = context()->get_def_use_mgr();
+  analysis::TypeManager* type_mgr = context()->get_type_mgr();
+  bool modified = false;
+  std::vector<std::pair<Instruction*, unsigned>> arrays_to_change;
+  for (auto& var : context()->types_values()) {
+    if (var.opcode() != SpvOpVariable) {
+      continue;
+    }
+    analysis::Type* var_type = type_mgr->GetType(var.type_id());
+    analysis::Pointer* ptr_type = var_type->AsPointer();
+    if (ptr_type == nullptr) {
+      continue;
+    }
+    if (ptr_type->storage_class() != SpvStorageClassInput) {
+      continue;
+    }
+    const analysis::Array* arr_type = ptr_type->pointee_type()->AsArray();
+    if (arr_type == nullptr) {
+      continue;
+    }
+    unsigned arr_len_id = arr_type->LengthId();
+    Instruction* arr_len_inst = def_use_mgr->GetDef(arr_len_id);
+    if (arr_len_inst->opcode() != SpvOpConstant) {
+      continue;
+    }
+    // SPIR-V requires array size is >= 1, so this works for signed or
+    // unsigned size
+    unsigned original_max =
+        arr_len_inst->GetSingleWordInOperand(kConstantValueInIdx) - 1;
+    unsigned max_idx = FindMaxIndex(var, original_max);
+    if (max_idx != original_max) {
+      ChangeArrayLength(var, max_idx + 1);
+      modified = true;
+    }
+  }
+
+  return modified ? Status::SuccessWithChange : Status::SuccessWithoutChange;
+}
+
+unsigned EliminateDeadInputComponentsPass::FindMaxIndex(Instruction& var,
+                                                        unsigned original_max) {
+  unsigned max = 0;
+  bool seen_non_const_ac = false;
+  assert(var.opcode() == SpvOpVariable && "must be variable");
+  context()->get_def_use_mgr()->WhileEachUser(
+      var.result_id(), [&max, &seen_non_const_ac, var, this](Instruction* use) {
+        auto use_opcode = use->opcode();
+        if (use_opcode == SpvOpLoad || use_opcode == SpvOpCopyMemory ||
+            use_opcode == SpvOpCopyMemorySized ||
+            use_opcode == SpvOpCopyObject) {
+          seen_non_const_ac = true;
+          return false;
+        }
+        if (use->opcode() != SpvOpAccessChain &&
+            use->opcode() != SpvOpInBoundsAccessChain) {
+          return true;
+        }
+        // OpAccessChain with no indices currently not optimized
+        if (use->NumInOperands() == 1) {
+          seen_non_const_ac = true;
+          return false;
+        }
+        unsigned base_id = use->GetSingleWordInOperand(kAccessChainBaseInIdx);
+        USE_ASSERT(base_id == var.result_id() && "unexpected base");
+        unsigned idx_id = use->GetSingleWordInOperand(kAccessChainIndex0InIdx);
+        Instruction* idx_inst = context()->get_def_use_mgr()->GetDef(idx_id);
+        if (idx_inst->opcode() != SpvOpConstant) {
+          seen_non_const_ac = true;
+          return false;
+        }
+        unsigned value = idx_inst->GetSingleWordInOperand(kConstantValueInIdx);
+        if (value > max) max = value;
+        return true;
+      });
+  return seen_non_const_ac ? original_max : max;
+}
+
+void EliminateDeadInputComponentsPass::ChangeArrayLength(Instruction& arr,
+                                                         unsigned length) {
+  analysis::TypeManager* type_mgr = context()->get_type_mgr();
+  analysis::ConstantManager* const_mgr = context()->get_constant_mgr();
+  analysis::DefUseManager* def_use_mgr = context()->get_def_use_mgr();
+  analysis::Pointer* ptr_type = type_mgr->GetType(arr.type_id())->AsPointer();
+  const analysis::Array* arr_ty = ptr_type->pointee_type()->AsArray();
+  assert(arr_ty && "expecting array type");
+  uint32_t length_id = const_mgr->GetUIntConst(length);
+  analysis::Array new_arr_ty(arr_ty->element_type(),
+                             arr_ty->GetConstantLengthInfo(length_id, length));
+  analysis::Type* reg_new_arr_ty = type_mgr->GetRegisteredType(&new_arr_ty);
+  analysis::Pointer new_ptr_ty(reg_new_arr_ty, SpvStorageClassInput);
+  analysis::Type* reg_new_ptr_ty = type_mgr->GetRegisteredType(&new_ptr_ty);
+  uint32_t new_ptr_ty_id = type_mgr->GetTypeInstruction(reg_new_ptr_ty);
+  arr.SetResultType(new_ptr_ty_id);
+  def_use_mgr->AnalyzeInstUse(&arr);
+  // Move array OpVariable instruction after its new type to preserve order
+  USE_ASSERT(arr.GetSingleWordInOperand(kVariableStorageClassInIdx) !=
+                 SpvStorageClassFunction &&
+             "cannot move Function variable");
+  Instruction* new_ptr_ty_inst = def_use_mgr->GetDef(new_ptr_ty_id);
+  arr.RemoveFromList();
+  arr.InsertAfter(new_ptr_ty_inst);
+}
+
+}  // namespace opt
+}  // namespace spvtools

+ 59 - 0
ThirdParty/Glslang/External/spirv-tools/source/opt/eliminate_dead_input_components_pass.h

@@ -0,0 +1,59 @@
+// Copyright (c) 2022 The Khronos Group Inc.
+// Copyright (c) 2022 LunarG Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SOURCE_OPT_ELIMINATE_DEAD_INPUT_COMPONENTS_H_
+#define SOURCE_OPT_ELIMINATE_DEAD_INPUT_COMPONENTS_H_
+
+#include <unordered_map>
+
+#include "source/opt/ir_context.h"
+#include "source/opt/module.h"
+#include "source/opt/pass.h"
+
+namespace spvtools {
+namespace opt {
+
+// See optimizer.hpp for documentation.
+class EliminateDeadInputComponentsPass : public Pass {
+ public:
+  explicit EliminateDeadInputComponentsPass() {}
+
+  const char* name() const override { return "reduce-load-size"; }
+  Status Process() override;
+
+  // Return the mask of preserved Analyses.
+  IRContext::Analysis GetPreservedAnalyses() override {
+    return IRContext::kAnalysisDefUse |
+           IRContext::kAnalysisInstrToBlockMapping |
+           IRContext::kAnalysisCombinators | IRContext::kAnalysisCFG |
+           IRContext::kAnalysisDominatorAnalysis |
+           IRContext::kAnalysisLoopAnalysis | IRContext::kAnalysisNameMap |
+           IRContext::kAnalysisConstants | IRContext::kAnalysisTypes;
+  }
+
+ private:
+  // Find the max constant used to index the variable declared by |var|
+  // through OpAccessChain or OpInBoundsAccessChain. If any non-constant
+  // indices or non-Op*AccessChain use of |var|, return |original_max|.
+  unsigned FindMaxIndex(Instruction& var, unsigned original_max);
+
+  // Change the length of the array |inst| to |length|
+  void ChangeArrayLength(Instruction& inst, unsigned length);
+};
+
+}  // namespace opt
+}  // namespace spvtools
+
+#endif  // SOURCE_OPT_ELIMINATE_DEAD_INPUT_COMPONENTS_H_

+ 124 - 0
ThirdParty/Glslang/External/spirv-tools/source/opt/interp_fixup_pass.cpp

@@ -0,0 +1,124 @@
+// Copyright (c) 2021 The Khronos Group Inc.
+// Copyright (c) 2021 Valve Corporation
+// Copyright (c) 2021 LunarG Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "source/opt/interp_fixup_pass.h"
+
+#include <set>
+#include <string>
+
+#include "ir_builder.h"
+#include "source/opt/ir_context.h"
+#include "type_manager.h"
+
+namespace spvtools {
+namespace opt {
+
+namespace {
+
+// Input Operand Indices
+static const int kSpvVariableStorageClassInIdx = 0;
+
+// Folding rule function which attempts to replace |op(OpLoad(a),...)|
+// by |op(a,...)|, where |op| is one of the GLSLstd450 InterpolateAt*
+// instructions. Returns true if replaced, false otherwise.
+bool ReplaceInternalInterpolate(IRContext* ctx, Instruction* inst,
+                                const std::vector<const analysis::Constant*>&) {
+  uint32_t glsl450_ext_inst_id =
+      ctx->get_feature_mgr()->GetExtInstImportId_GLSLstd450();
+  assert(glsl450_ext_inst_id != 0);
+
+  uint32_t ext_opcode = inst->GetSingleWordInOperand(1);
+
+  uint32_t op1_id = inst->GetSingleWordInOperand(2);
+
+  Instruction* load_inst = ctx->get_def_use_mgr()->GetDef(op1_id);
+  if (load_inst->opcode() != SpvOpLoad) return false;
+
+  Instruction* base_inst = load_inst->GetBaseAddress();
+  USE_ASSERT(base_inst->opcode() == SpvOpVariable &&
+             base_inst->GetSingleWordInOperand(kSpvVariableStorageClassInIdx) ==
+                 SpvStorageClassInput &&
+             "unexpected interpolant in InterpolateAt*");
+
+  uint32_t ptr_id = load_inst->GetSingleWordInOperand(0);
+  uint32_t op2_id = (ext_opcode != GLSLstd450InterpolateAtCentroid)
+                        ? inst->GetSingleWordInOperand(3)
+                        : 0;
+
+  Instruction::OperandList new_operands;
+  new_operands.push_back({SPV_OPERAND_TYPE_ID, {glsl450_ext_inst_id}});
+  new_operands.push_back(
+      {SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER, {ext_opcode}});
+  new_operands.push_back({SPV_OPERAND_TYPE_ID, {ptr_id}});
+  if (op2_id != 0) new_operands.push_back({SPV_OPERAND_TYPE_ID, {op2_id}});
+
+  inst->SetInOperands(std::move(new_operands));
+  ctx->UpdateDefUse(inst);
+  return true;
+}
+
+class InterpFoldingRules : public FoldingRules {
+ public:
+  explicit InterpFoldingRules(IRContext* ctx) : FoldingRules(ctx) {}
+
+ protected:
+  virtual void AddFoldingRules() override {
+    uint32_t extension_id =
+        context()->get_feature_mgr()->GetExtInstImportId_GLSLstd450();
+
+    if (extension_id != 0) {
+      ext_rules_[{extension_id, GLSLstd450InterpolateAtCentroid}].push_back(
+          ReplaceInternalInterpolate);
+      ext_rules_[{extension_id, GLSLstd450InterpolateAtSample}].push_back(
+          ReplaceInternalInterpolate);
+      ext_rules_[{extension_id, GLSLstd450InterpolateAtOffset}].push_back(
+          ReplaceInternalInterpolate);
+    }
+  }
+};
+
+class InterpConstFoldingRules : public ConstantFoldingRules {
+ public:
+  InterpConstFoldingRules(IRContext* ctx) : ConstantFoldingRules(ctx) {}
+
+ protected:
+  virtual void AddFoldingRules() override {}
+};
+
+}  // namespace
+
+Pass::Status InterpFixupPass::Process() {
+  bool changed = false;
+
+  // Traverse the body of the functions to replace instructions that require
+  // the extensions.
+  InstructionFolder folder(
+      context(),
+      std::unique_ptr<InterpFoldingRules>(new InterpFoldingRules(context())),
+      MakeUnique<InterpConstFoldingRules>(context()));
+  for (Function& func : *get_module()) {
+    func.ForEachInst([&changed, &folder](Instruction* inst) {
+      if (folder.FoldInstruction(inst)) {
+        changed = true;
+      }
+    });
+  }
+
+  return changed ? Status::SuccessWithChange : Status::SuccessWithoutChange;
+}
+
+}  // namespace opt
+}  // namespace spvtools

+ 54 - 0
ThirdParty/Glslang/External/spirv-tools/source/opt/interp_fixup_pass.h

@@ -0,0 +1,54 @@
+// Copyright (c) 2021 The Khronos Group Inc.
+// Copyright (c) 2021 Valve Corporation
+// Copyright (c) 2021 LunarG Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SOURCE_OPT_INTERP_FIXUP_H
+#define SOURCE_OPT_INTERP_FIXUP_H
+
+#include "source/opt/ir_context.h"
+#include "source/opt/module.h"
+#include "source/opt/pass.h"
+
+namespace spvtools {
+namespace opt {
+
+// Replaces overloaded internal form for GLSLstd450Interpolate* instructions
+// with external form. Specifically, removes OpLoad from the first argument
+// and replaces it with the pointer for the OpLoad. glslang generates the
+// internal form. This pass is called as part of glslang HLSL legalization.
+class InterpFixupPass : public Pass {
+ public:
+  const char* name() const override { return "interp-fixup"; }
+  Status Process() override;
+
+  IRContext::Analysis GetPreservedAnalyses() override {
+    return IRContext::kAnalysisInstrToBlockMapping |
+           IRContext::kAnalysisDecorations | IRContext::kAnalysisCombinators |
+           IRContext::kAnalysisCFG | IRContext::kAnalysisDominatorAnalysis |
+           IRContext::kAnalysisLoopAnalysis | IRContext::kAnalysisNameMap |
+           IRContext::kAnalysisScalarEvolution |
+           IRContext::kAnalysisRegisterPressure |
+           IRContext::kAnalysisValueNumberTable |
+           IRContext::kAnalysisStructuredCFG |
+           IRContext::kAnalysisBuiltinVarId |
+           IRContext::kAnalysisIdToFuncMapping | IRContext::kAnalysisTypes |
+           IRContext::kAnalysisDefUse | IRContext::kAnalysisConstants;
+  }
+};
+
+}  // namespace opt
+}  // namespace spvtools
+
+#endif  // SOURCE_OPT_INTERP_FIXUP_H

+ 49 - 0
ThirdParty/Glslang/External/spirv-tools/source/opt/remove_dontinline_pass.cpp

@@ -0,0 +1,49 @@
+// Copyright (c) 2022 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "source/opt/remove_dontinline_pass.h"
+
+namespace spvtools {
+namespace opt {
+
+Pass::Status RemoveDontInline::Process() {
+  bool modified = false;
+  modified = ClearDontInlineFunctionControl();
+  return (modified ? Status::SuccessWithChange : Status::SuccessWithoutChange);
+}
+
+bool RemoveDontInline::ClearDontInlineFunctionControl() {
+  bool modified = false;
+  for (auto& func : *get_module()) {
+    ClearDontInlineFunctionControl(&func);
+  }
+  return modified;
+}
+
+bool RemoveDontInline::ClearDontInlineFunctionControl(Function* function) {
+  constexpr uint32_t kFunctionControlInOperandIdx = 0;
+  Instruction* function_inst = &function->DefInst();
+  uint32_t function_control =
+      function_inst->GetSingleWordInOperand(kFunctionControlInOperandIdx);
+
+  if ((function_control & SpvFunctionControlDontInlineMask) == 0) {
+    return false;
+  }
+  function_control &= ~SpvFunctionControlDontInlineMask;
+  function_inst->SetInOperand(kFunctionControlInOperandIdx, {function_control});
+  return true;
+}
+
+}  // namespace opt
+}  // namespace spvtools

+ 42 - 0
ThirdParty/Glslang/External/spirv-tools/source/opt/remove_dontinline_pass.h

@@ -0,0 +1,42 @@
+// Copyright (c) 2022 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SOURCE_OPT_REMOVE_DONTINLINE_PASS_H_
+#define SOURCE_OPT_REMOVE_DONTINLINE_PASS_H_
+
+#include "source/opt/pass.h"
+
+namespace spvtools {
+namespace opt {
+
+// See optimizer.hpp for documentation.
+class RemoveDontInline : public Pass {
+ public:
+  const char* name() const override { return "remove-dont-inline"; }
+  Status Process() override;
+
+ private:
+  // Clears the DontInline function control from every function in the module.
+  // Returns true of a change was made.
+  bool ClearDontInlineFunctionControl();
+
+  // Clears the DontInline function control from |function|.
+  // Returns true of a change was made.
+  bool ClearDontInlineFunctionControl(Function* function);
+};
+
+}  // namespace opt
+}  // namespace spvtools
+
+#endif  // SOURCE_OPT_REMOVE_DONTINLINE_PASS_H_

+ 93 - 0
ThirdParty/Glslang/External/spirv-tools/source/opt/remove_unused_interface_variables_pass.cpp

@@ -0,0 +1,93 @@
+// Copyright (c) 2021 ZHOU He
+//
+// 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 "remove_unused_interface_variables_pass.h"
+#include "source/spirv_constant.h"
+namespace spvtools {
+namespace opt {
+
+class RemoveUnusedInterfaceVariablesContext {
+  RemoveUnusedInterfaceVariablesPass& parent_;
+  Instruction& entry_;
+  std::unordered_set<uint32_t> used_variables_;
+  IRContext::ProcessFunction pfn_ =
+      std::bind(&RemoveUnusedInterfaceVariablesContext::processFunction, this,
+                std::placeholders::_1);
+
+  bool processFunction(Function* func) {
+    for (const auto& basic_block : *func)
+      for (const auto& instruction : basic_block)
+        instruction.ForEachInId([&](const uint32_t* id) {
+          if (used_variables_.count(*id)) return;
+          auto* var = parent_.get_def_use_mgr()->GetDef(*id);
+          if (!var || var->opcode() != SpvOpVariable) return;
+          auto storage_class = var->GetSingleWordInOperand(0);
+          if (storage_class != SpvStorageClassFunction &&
+              (parent_.get_module()->version() >=
+                   SPV_SPIRV_VERSION_WORD(1, 4) ||
+               storage_class == SpvStorageClassInput ||
+               storage_class == SpvStorageClassOutput))
+            used_variables_.insert(*id);
+        });
+    return false;
+  }
+
+ public:
+  RemoveUnusedInterfaceVariablesContext(
+      RemoveUnusedInterfaceVariablesPass& parent, Instruction& entry)
+      : parent_(parent), entry_(entry) {}
+
+  void CollectUsedVariables() {
+    std::queue<uint32_t> roots;
+    roots.push(entry_.GetSingleWordInOperand(1));
+    parent_.context()->ProcessCallTreeFromRoots(pfn_, &roots);
+  }
+
+  bool ShouldModify() {
+    std::unordered_set<uint32_t> old_variables;
+    for (int i = entry_.NumInOperands() - 1; i >= 3; --i) {
+      auto variable = entry_.GetInOperand(i).words[0];
+      if (!used_variables_.count(variable)) return true;  // It is unused.
+      if (old_variables.count(variable)) return true;     // It is duplicate.
+      old_variables.insert(variable);
+    }
+    if (old_variables.size() != used_variables_.size())  // Missing IDs.
+      return true;
+    return false;
+  }
+
+  void Modify() {
+    for (int i = entry_.NumInOperands() - 1; i >= 3; --i)
+      entry_.RemoveInOperand(i);
+    for (auto id : used_variables_) {
+      entry_.AddOperand(Operand(SPV_OPERAND_TYPE_ID, {id}));
+    }
+  }
+};
+
+RemoveUnusedInterfaceVariablesPass::Status
+RemoveUnusedInterfaceVariablesPass::Process() {
+  bool modified = false;
+  for (auto& entry : get_module()->entry_points()) {
+    RemoveUnusedInterfaceVariablesContext context(*this, entry);
+    context.CollectUsedVariables();
+    if (context.ShouldModify()) {
+      context.Modify();
+      modified = true;
+    }
+  }
+  return (modified ? Status::SuccessWithChange : Status::SuccessWithoutChange);
+}
+}  // namespace opt
+}  // namespace spvtools

+ 26 - 0
ThirdParty/Glslang/External/spirv-tools/source/opt/remove_unused_interface_variables_pass.h

@@ -0,0 +1,26 @@
+// Copyright (c) 2021 ZHOU He
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "source/opt/pass.h"
+namespace spvtools {
+namespace opt {
+
+class RemoveUnusedInterfaceVariablesPass : public Pass {
+  const char* name() const override {
+    return "remove-unused-interface-variables-pass";
+  }
+  Status Process() override;
+};
+}  // namespace opt
+}  // namespace spvtools

+ 427 - 0
ThirdParty/Glslang/External/spirv-tools/source/opt/replace_desc_array_access_using_var_index.cpp

@@ -0,0 +1,427 @@
+// Copyright (c) 2021 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "source/opt/replace_desc_array_access_using_var_index.h"
+
+#include "source/opt/desc_sroa_util.h"
+#include "source/opt/ir_builder.h"
+#include "source/util/string_utils.h"
+
+namespace spvtools {
+namespace opt {
+namespace {
+
+const uint32_t kOpAccessChainInOperandIndexes = 1;
+const uint32_t kOpTypePointerInOperandType = 1;
+const uint32_t kOpTypeArrayInOperandType = 0;
+const uint32_t kOpTypeStructInOperandMember = 0;
+IRContext::Analysis kAnalysisDefUseAndInstrToBlockMapping =
+    IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping;
+
+uint32_t GetValueWithKeyExistenceCheck(
+    uint32_t key, const std::unordered_map<uint32_t, uint32_t>& map) {
+  auto itr = map.find(key);
+  assert(itr != map.end() && "Key does not exist");
+  return itr->second;
+}
+
+}  // namespace
+
+Pass::Status ReplaceDescArrayAccessUsingVarIndex::Process() {
+  Status status = Status::SuccessWithoutChange;
+  for (Instruction& var : context()->types_values()) {
+    if (descsroautil::IsDescriptorArray(context(), &var)) {
+      if (ReplaceVariableAccessesWithConstantElements(&var))
+        status = Status::SuccessWithChange;
+    }
+  }
+  return status;
+}
+
+bool ReplaceDescArrayAccessUsingVarIndex::
+    ReplaceVariableAccessesWithConstantElements(Instruction* var) const {
+  std::vector<Instruction*> work_list;
+  get_def_use_mgr()->ForEachUser(var, [&work_list](Instruction* use) {
+    switch (use->opcode()) {
+      case SpvOpAccessChain:
+      case SpvOpInBoundsAccessChain:
+        work_list.push_back(use);
+        break;
+      default:
+        break;
+    }
+  });
+
+  bool updated = false;
+  for (Instruction* access_chain : work_list) {
+    if (descsroautil::GetAccessChainIndexAsConst(context(), access_chain) ==
+        nullptr) {
+      ReplaceAccessChain(var, access_chain);
+      updated = true;
+    }
+  }
+  // Note that we do not consider OpLoad and OpCompositeExtract because
+  // OpCompositeExtract always has constant literals for indices.
+  return updated;
+}
+
+void ReplaceDescArrayAccessUsingVarIndex::ReplaceAccessChain(
+    Instruction* var, Instruction* access_chain) const {
+  uint32_t number_of_elements =
+      descsroautil::GetNumberOfElementsForArrayOrStruct(context(), var);
+  assert(number_of_elements != 0 && "Number of element is 0");
+  if (number_of_elements == 1) {
+    UseConstIndexForAccessChain(access_chain, 0);
+    get_def_use_mgr()->AnalyzeInstUse(access_chain);
+    return;
+  }
+  ReplaceUsersOfAccessChain(access_chain, number_of_elements);
+}
+
+void ReplaceDescArrayAccessUsingVarIndex::ReplaceUsersOfAccessChain(
+    Instruction* access_chain, uint32_t number_of_elements) const {
+  std::vector<Instruction*> final_users;
+  CollectRecursiveUsersWithConcreteType(access_chain, &final_users);
+  for (auto* inst : final_users) {
+    std::deque<Instruction*> insts_to_be_cloned =
+        CollectRequiredImageInsts(inst);
+    ReplaceNonUniformAccessWithSwitchCase(
+        inst, access_chain, number_of_elements, insts_to_be_cloned);
+  }
+}
+
+void ReplaceDescArrayAccessUsingVarIndex::CollectRecursiveUsersWithConcreteType(
+    Instruction* access_chain, std::vector<Instruction*>* final_users) const {
+  std::queue<Instruction*> work_list;
+  work_list.push(access_chain);
+  while (!work_list.empty()) {
+    auto* inst_from_work_list = work_list.front();
+    work_list.pop();
+    get_def_use_mgr()->ForEachUser(
+        inst_from_work_list, [this, final_users, &work_list](Instruction* use) {
+          // TODO: Support Boolean type as well.
+          if (!use->HasResultId() || IsConcreteType(use->type_id())) {
+            final_users->push_back(use);
+          } else {
+            work_list.push(use);
+          }
+        });
+  }
+}
+
+std::deque<Instruction*>
+ReplaceDescArrayAccessUsingVarIndex::CollectRequiredImageInsts(
+    Instruction* user_of_image_insts) const {
+  std::unordered_set<uint32_t> seen_inst_ids;
+  std::queue<Instruction*> work_list;
+
+  auto decision_to_include_operand = [this, &seen_inst_ids,
+                                      &work_list](uint32_t* idp) {
+    if (!seen_inst_ids.insert(*idp).second) return;
+    Instruction* operand = get_def_use_mgr()->GetDef(*idp);
+    if (context()->get_instr_block(operand) != nullptr &&
+        HasImageOrImagePtrType(operand)) {
+      work_list.push(operand);
+    }
+  };
+
+  std::deque<Instruction*> required_image_insts;
+  required_image_insts.push_front(user_of_image_insts);
+  user_of_image_insts->ForEachInId(decision_to_include_operand);
+  while (!work_list.empty()) {
+    auto* inst_from_work_list = work_list.front();
+    work_list.pop();
+    required_image_insts.push_front(inst_from_work_list);
+    inst_from_work_list->ForEachInId(decision_to_include_operand);
+  }
+  return required_image_insts;
+}
+
+bool ReplaceDescArrayAccessUsingVarIndex::HasImageOrImagePtrType(
+    const Instruction* inst) const {
+  assert(inst != nullptr && inst->type_id() != 0 && "Invalid instruction");
+  return IsImageOrImagePtrType(get_def_use_mgr()->GetDef(inst->type_id()));
+}
+
+bool ReplaceDescArrayAccessUsingVarIndex::IsImageOrImagePtrType(
+    const Instruction* type_inst) const {
+  if (type_inst->opcode() == SpvOpTypeImage ||
+      type_inst->opcode() == SpvOpTypeSampler ||
+      type_inst->opcode() == SpvOpTypeSampledImage) {
+    return true;
+  }
+  if (type_inst->opcode() == SpvOpTypePointer) {
+    Instruction* pointee_type_inst = get_def_use_mgr()->GetDef(
+        type_inst->GetSingleWordInOperand(kOpTypePointerInOperandType));
+    return IsImageOrImagePtrType(pointee_type_inst);
+  }
+  if (type_inst->opcode() == SpvOpTypeArray) {
+    Instruction* element_type_inst = get_def_use_mgr()->GetDef(
+        type_inst->GetSingleWordInOperand(kOpTypeArrayInOperandType));
+    return IsImageOrImagePtrType(element_type_inst);
+  }
+  if (type_inst->opcode() != SpvOpTypeStruct) return false;
+  for (uint32_t in_operand_idx = kOpTypeStructInOperandMember;
+       in_operand_idx < type_inst->NumInOperands(); ++in_operand_idx) {
+    Instruction* member_type_inst = get_def_use_mgr()->GetDef(
+        type_inst->GetSingleWordInOperand(kOpTypeStructInOperandMember));
+    if (IsImageOrImagePtrType(member_type_inst)) return true;
+  }
+  return false;
+}
+
+bool ReplaceDescArrayAccessUsingVarIndex::IsConcreteType(
+    uint32_t type_id) const {
+  Instruction* type_inst = get_def_use_mgr()->GetDef(type_id);
+  if (type_inst->opcode() == SpvOpTypeInt ||
+      type_inst->opcode() == SpvOpTypeFloat) {
+    return true;
+  }
+  if (type_inst->opcode() == SpvOpTypeVector ||
+      type_inst->opcode() == SpvOpTypeMatrix ||
+      type_inst->opcode() == SpvOpTypeArray) {
+    return IsConcreteType(type_inst->GetSingleWordInOperand(0));
+  }
+  if (type_inst->opcode() == SpvOpTypeStruct) {
+    for (uint32_t i = 0; i < type_inst->NumInOperands(); ++i) {
+      if (!IsConcreteType(type_inst->GetSingleWordInOperand(i))) return false;
+    }
+    return true;
+  }
+  return false;
+}
+
+BasicBlock* ReplaceDescArrayAccessUsingVarIndex::CreateCaseBlock(
+    Instruction* access_chain, uint32_t element_index,
+    const std::deque<Instruction*>& insts_to_be_cloned,
+    uint32_t branch_target_id,
+    std::unordered_map<uint32_t, uint32_t>* old_ids_to_new_ids) const {
+  auto* case_block = CreateNewBlock();
+  AddConstElementAccessToCaseBlock(case_block, access_chain, element_index,
+                                   old_ids_to_new_ids);
+  CloneInstsToBlock(case_block, access_chain, insts_to_be_cloned,
+                    old_ids_to_new_ids);
+  AddBranchToBlock(case_block, branch_target_id);
+  UseNewIdsInBlock(case_block, *old_ids_to_new_ids);
+  return case_block;
+}
+
+void ReplaceDescArrayAccessUsingVarIndex::CloneInstsToBlock(
+    BasicBlock* block, Instruction* inst_to_skip_cloning,
+    const std::deque<Instruction*>& insts_to_be_cloned,
+    std::unordered_map<uint32_t, uint32_t>* old_ids_to_new_ids) const {
+  for (auto* inst_to_be_cloned : insts_to_be_cloned) {
+    if (inst_to_be_cloned == inst_to_skip_cloning) continue;
+    std::unique_ptr<Instruction> clone(inst_to_be_cloned->Clone(context()));
+    if (inst_to_be_cloned->HasResultId()) {
+      uint32_t new_id = context()->TakeNextId();
+      clone->SetResultId(new_id);
+      (*old_ids_to_new_ids)[inst_to_be_cloned->result_id()] = new_id;
+    }
+    get_def_use_mgr()->AnalyzeInstDefUse(clone.get());
+    context()->set_instr_block(clone.get(), block);
+    block->AddInstruction(std::move(clone));
+  }
+}
+
+void ReplaceDescArrayAccessUsingVarIndex::UseNewIdsInBlock(
+    BasicBlock* block,
+    const std::unordered_map<uint32_t, uint32_t>& old_ids_to_new_ids) const {
+  for (auto block_itr = block->begin(); block_itr != block->end();
+       ++block_itr) {
+    (&*block_itr)->ForEachInId([&old_ids_to_new_ids](uint32_t* idp) {
+      auto old_ids_to_new_ids_itr = old_ids_to_new_ids.find(*idp);
+      if (old_ids_to_new_ids_itr == old_ids_to_new_ids.end()) return;
+      *idp = old_ids_to_new_ids_itr->second;
+    });
+    get_def_use_mgr()->AnalyzeInstUse(&*block_itr);
+  }
+}
+
+void ReplaceDescArrayAccessUsingVarIndex::ReplaceNonUniformAccessWithSwitchCase(
+    Instruction* access_chain_final_user, Instruction* access_chain,
+    uint32_t number_of_elements,
+    const std::deque<Instruction*>& insts_to_be_cloned) const {
+  auto* block = context()->get_instr_block(access_chain_final_user);
+  // If the instruction does not belong to a block (i.e. in the case of
+  // OpDecorate), no replacement is needed.
+  if (!block) return;
+
+  // Create merge block and add terminator
+  auto* merge_block = SeparateInstructionsIntoNewBlock(
+      block, access_chain_final_user->NextNode());
+
+  auto* function = block->GetParent();
+
+  // Add case blocks
+  std::vector<uint32_t> phi_operands;
+  std::vector<uint32_t> case_block_ids;
+  for (uint32_t idx = 0; idx < number_of_elements; ++idx) {
+    std::unordered_map<uint32_t, uint32_t> old_ids_to_new_ids_for_cloned_insts;
+    std::unique_ptr<BasicBlock> case_block(CreateCaseBlock(
+        access_chain, idx, insts_to_be_cloned, merge_block->id(),
+        &old_ids_to_new_ids_for_cloned_insts));
+    case_block_ids.push_back(case_block->id());
+    function->InsertBasicBlockBefore(std::move(case_block), merge_block);
+
+    // Keep the operand for OpPhi
+    if (!access_chain_final_user->HasResultId()) continue;
+    uint32_t phi_operand =
+        GetValueWithKeyExistenceCheck(access_chain_final_user->result_id(),
+                                      old_ids_to_new_ids_for_cloned_insts);
+    phi_operands.push_back(phi_operand);
+  }
+
+  // Create default block
+  std::unique_ptr<BasicBlock> default_block(
+      CreateDefaultBlock(access_chain_final_user->HasResultId(), &phi_operands,
+                         merge_block->id()));
+  uint32_t default_block_id = default_block->id();
+  function->InsertBasicBlockBefore(std::move(default_block), merge_block);
+
+  // Create OpSwitch
+  uint32_t access_chain_index_var_id =
+      descsroautil::GetFirstIndexOfAccessChain(access_chain);
+  AddSwitchForAccessChain(block, access_chain_index_var_id, default_block_id,
+                          merge_block->id(), case_block_ids);
+
+  // Create phi instructions
+  if (!phi_operands.empty()) {
+    uint32_t phi_id = CreatePhiInstruction(merge_block, phi_operands,
+                                           case_block_ids, default_block_id);
+    context()->ReplaceAllUsesWith(access_chain_final_user->result_id(), phi_id);
+  }
+
+  // Replace OpPhi incoming block operand that uses |block| with |merge_block|
+  ReplacePhiIncomingBlock(block->id(), merge_block->id());
+}
+
+BasicBlock*
+ReplaceDescArrayAccessUsingVarIndex::SeparateInstructionsIntoNewBlock(
+    BasicBlock* block, Instruction* separation_begin_inst) const {
+  auto separation_begin = block->begin();
+  while (separation_begin != block->end() &&
+         &*separation_begin != separation_begin_inst) {
+    ++separation_begin;
+  }
+  return block->SplitBasicBlock(context(), context()->TakeNextId(),
+                                separation_begin);
+}
+
+BasicBlock* ReplaceDescArrayAccessUsingVarIndex::CreateNewBlock() const {
+  auto* new_block = new BasicBlock(std::unique_ptr<Instruction>(
+      new Instruction(context(), SpvOpLabel, 0, context()->TakeNextId(), {})));
+  get_def_use_mgr()->AnalyzeInstDefUse(new_block->GetLabelInst());
+  context()->set_instr_block(new_block->GetLabelInst(), new_block);
+  return new_block;
+}
+
+void ReplaceDescArrayAccessUsingVarIndex::UseConstIndexForAccessChain(
+    Instruction* access_chain, uint32_t const_element_idx) const {
+  uint32_t const_element_idx_id =
+      context()->get_constant_mgr()->GetUIntConst(const_element_idx);
+  access_chain->SetInOperand(kOpAccessChainInOperandIndexes,
+                             {const_element_idx_id});
+}
+
+void ReplaceDescArrayAccessUsingVarIndex::AddConstElementAccessToCaseBlock(
+    BasicBlock* case_block, Instruction* access_chain,
+    uint32_t const_element_idx,
+    std::unordered_map<uint32_t, uint32_t>* old_ids_to_new_ids) const {
+  std::unique_ptr<Instruction> access_clone(access_chain->Clone(context()));
+  UseConstIndexForAccessChain(access_clone.get(), const_element_idx);
+
+  uint32_t new_access_id = context()->TakeNextId();
+  (*old_ids_to_new_ids)[access_clone->result_id()] = new_access_id;
+  access_clone->SetResultId(new_access_id);
+  get_def_use_mgr()->AnalyzeInstDefUse(access_clone.get());
+
+  context()->set_instr_block(access_clone.get(), case_block);
+  case_block->AddInstruction(std::move(access_clone));
+}
+
+void ReplaceDescArrayAccessUsingVarIndex::AddBranchToBlock(
+    BasicBlock* parent_block, uint32_t branch_destination) const {
+  InstructionBuilder builder{context(), parent_block,
+                             kAnalysisDefUseAndInstrToBlockMapping};
+  builder.AddBranch(branch_destination);
+}
+
+BasicBlock* ReplaceDescArrayAccessUsingVarIndex::CreateDefaultBlock(
+    bool null_const_for_phi_is_needed, std::vector<uint32_t>* phi_operands,
+    uint32_t merge_block_id) const {
+  auto* default_block = CreateNewBlock();
+  AddBranchToBlock(default_block, merge_block_id);
+  if (!null_const_for_phi_is_needed) return default_block;
+
+  // Create null value for OpPhi
+  Instruction* inst = context()->get_def_use_mgr()->GetDef((*phi_operands)[0]);
+  auto* null_const_inst = GetConstNull(inst->type_id());
+  phi_operands->push_back(null_const_inst->result_id());
+  return default_block;
+}
+
+Instruction* ReplaceDescArrayAccessUsingVarIndex::GetConstNull(
+    uint32_t type_id) const {
+  assert(type_id != 0 && "Result type is expected");
+  auto* type = context()->get_type_mgr()->GetType(type_id);
+  auto* null_const = context()->get_constant_mgr()->GetConstant(type, {});
+  return context()->get_constant_mgr()->GetDefiningInstruction(null_const);
+}
+
+void ReplaceDescArrayAccessUsingVarIndex::AddSwitchForAccessChain(
+    BasicBlock* parent_block, uint32_t access_chain_index_var_id,
+    uint32_t default_id, uint32_t merge_id,
+    const std::vector<uint32_t>& case_block_ids) const {
+  InstructionBuilder builder{context(), parent_block,
+                             kAnalysisDefUseAndInstrToBlockMapping};
+  std::vector<std::pair<Operand::OperandData, uint32_t>> cases;
+  for (uint32_t i = 0; i < static_cast<uint32_t>(case_block_ids.size()); ++i) {
+    cases.emplace_back(Operand::OperandData{i}, case_block_ids[i]);
+  }
+  builder.AddSwitch(access_chain_index_var_id, default_id, cases, merge_id);
+}
+
+uint32_t ReplaceDescArrayAccessUsingVarIndex::CreatePhiInstruction(
+    BasicBlock* parent_block, const std::vector<uint32_t>& phi_operands,
+    const std::vector<uint32_t>& case_block_ids,
+    uint32_t default_block_id) const {
+  std::vector<uint32_t> incomings;
+  assert(case_block_ids.size() + 1 == phi_operands.size() &&
+         "Number of Phi operands must be exactly 1 bigger than the one of case "
+         "blocks");
+  for (size_t i = 0; i < case_block_ids.size(); ++i) {
+    incomings.push_back(phi_operands[i]);
+    incomings.push_back(case_block_ids[i]);
+  }
+  incomings.push_back(phi_operands.back());
+  incomings.push_back(default_block_id);
+
+  InstructionBuilder builder{context(), &*parent_block->begin(),
+                             kAnalysisDefUseAndInstrToBlockMapping};
+  uint32_t phi_result_type_id =
+      context()->get_def_use_mgr()->GetDef(phi_operands[0])->type_id();
+  auto* phi = builder.AddPhi(phi_result_type_id, incomings);
+  return phi->result_id();
+}
+
+void ReplaceDescArrayAccessUsingVarIndex::ReplacePhiIncomingBlock(
+    uint32_t old_incoming_block_id, uint32_t new_incoming_block_id) const {
+  context()->ReplaceAllUsesWithPredicate(
+      old_incoming_block_id, new_incoming_block_id,
+      [](Instruction* use) { return use->opcode() == SpvOpPhi; });
+}
+
+}  // namespace opt
+}  // namespace spvtools

+ 204 - 0
ThirdParty/Glslang/External/spirv-tools/source/opt/replace_desc_array_access_using_var_index.h

@@ -0,0 +1,204 @@
+// Copyright (c) 2021 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SOURCE_OPT_REPLACE_DESC_VAR_INDEX_ACCESS_H_
+#define SOURCE_OPT_REPLACE_DESC_VAR_INDEX_ACCESS_H_
+
+#include <cstdio>
+#include <memory>
+#include <queue>
+#include <unordered_map>
+#include <unordered_set>
+#include <vector>
+
+#include "source/opt/function.h"
+#include "source/opt/pass.h"
+#include "source/opt/type_manager.h"
+
+namespace spvtools {
+namespace opt {
+
+// See optimizer.hpp for documentation.
+class ReplaceDescArrayAccessUsingVarIndex : public Pass {
+ public:
+  ReplaceDescArrayAccessUsingVarIndex() {}
+
+  const char* name() const override {
+    return "replace-desc-array-access-using-var-index";
+  }
+
+  Status Process() override;
+
+  IRContext::Analysis GetPreservedAnalyses() override {
+    return IRContext::kAnalysisDefUse |
+           IRContext::kAnalysisInstrToBlockMapping |
+           IRContext::kAnalysisConstants | IRContext::kAnalysisTypes;
+  }
+
+ private:
+  // Replaces all accesses to |var| using variable indices with constant
+  // elements of the array |var|. Creates switch-case statements to determine
+  // the value of the variable index for all the possible cases. Returns
+  // whether replacement is done or not.
+  bool ReplaceVariableAccessesWithConstantElements(Instruction* var) const;
+
+  // Replaces the OpAccessChain or OpInBoundsAccessChain instruction |use| that
+  // uses the descriptor variable |var| with the OpAccessChain or
+  // OpInBoundsAccessChain instruction with a constant Indexes operand.
+  void ReplaceAccessChain(Instruction* var, Instruction* use) const;
+
+  // Updates the first Indexes operand of the OpAccessChain or
+  // OpInBoundsAccessChain instruction |access_chain| to let it use a constant
+  // index |const_element_idx|.
+  void UseConstIndexForAccessChain(Instruction* access_chain,
+                                   uint32_t const_element_idx) const;
+
+  // Replaces users of the OpAccessChain or OpInBoundsAccessChain instruction
+  // |access_chain| that accesses an array descriptor variable using variable
+  // indices with constant elements. |number_of_elements| is the number
+  // of array elements.
+  void ReplaceUsersOfAccessChain(Instruction* access_chain,
+                                 uint32_t number_of_elements) const;
+
+  // Puts all the recursive users of |access_chain| with concrete result types
+  // or the ones without result it in |final_users|.
+  void CollectRecursiveUsersWithConcreteType(
+      Instruction* access_chain, std::vector<Instruction*>* final_users) const;
+
+  // Recursively collects the operands of |user_of_image_insts| (and operands
+  // of the operands) whose result types are images/samplers or pointers/array/
+  // struct of them and returns them.
+  std::deque<Instruction*> CollectRequiredImageInsts(
+      Instruction* user_of_image_insts) const;
+
+  // Returns whether result type of |inst| is an image/sampler/pointer of image
+  // or sampler or not.
+  bool HasImageOrImagePtrType(const Instruction* inst) const;
+
+  // Returns whether |type_inst| is an image/sampler or pointer/array/struct of
+  // image or sampler or not.
+  bool IsImageOrImagePtrType(const Instruction* type_inst) const;
+
+  // Returns whether the type with |type_id| is a concrete type or not.
+  bool IsConcreteType(uint32_t type_id) const;
+
+  // Replaces the non-uniform access to a descriptor variable
+  // |access_chain_final_user| with OpSwitch instruction and case blocks. Each
+  // case block will contain a clone of |access_chain| and clones of
+  // |non_uniform_accesses_to_clone| that are recursively used by
+  // |access_chain_final_user|. The clone of |access_chain| (or
+  // OpInBoundsAccessChain) will have a constant index for its first index. The
+  // OpSwitch instruction will have the cases for the variable index of
+  // |access_chain| from 0 to |number_of_elements| - 1.
+  void ReplaceNonUniformAccessWithSwitchCase(
+      Instruction* access_chain_final_user, Instruction* access_chain,
+      uint32_t number_of_elements,
+      const std::deque<Instruction*>& non_uniform_accesses_to_clone) const;
+
+  // Creates and returns a new basic block that contains all instructions of
+  // |block| after |separation_begin_inst|. The new basic block is added to the
+  // function in this method.
+  BasicBlock* SeparateInstructionsIntoNewBlock(
+      BasicBlock* block, Instruction* separation_begin_inst) const;
+
+  // Creates and returns a new block.
+  BasicBlock* CreateNewBlock() const;
+
+  // Returns the first operand id of the OpAccessChain or OpInBoundsAccessChain
+  // instruction |access_chain|.
+  uint32_t GetFirstIndexOfAccessChain(Instruction* access_chain) const;
+
+  // Adds a clone of the OpAccessChain or OpInBoundsAccessChain instruction
+  // |access_chain| to |case_block|. The clone of |access_chain| will use
+  // |const_element_idx| for its first index. |old_ids_to_new_ids| keeps the
+  // mapping from the result id of |access_chain| to the result of its clone.
+  void AddConstElementAccessToCaseBlock(
+      BasicBlock* case_block, Instruction* access_chain,
+      uint32_t const_element_idx,
+      std::unordered_map<uint32_t, uint32_t>* old_ids_to_new_ids) const;
+
+  // Clones all instructions in |insts_to_be_cloned| and put them to |block|.
+  // |old_ids_to_new_ids| keeps the mapping from the result id of each
+  // instruction of |insts_to_be_cloned| to the result of their clones.
+  void CloneInstsToBlock(
+      BasicBlock* block, Instruction* inst_to_skip_cloning,
+      const std::deque<Instruction*>& insts_to_be_cloned,
+      std::unordered_map<uint32_t, uint32_t>* old_ids_to_new_ids) const;
+
+  // Adds OpBranch to |branch_destination| at the end of |parent_block|.
+  void AddBranchToBlock(BasicBlock* parent_block,
+                        uint32_t branch_destination) const;
+
+  // Replaces in-operands of all instructions in the basic block |block| using
+  // |old_ids_to_new_ids|. It conducts the replacement only if the in-operand
+  // id is a key of |old_ids_to_new_ids|.
+  void UseNewIdsInBlock(
+      BasicBlock* block,
+      const std::unordered_map<uint32_t, uint32_t>& old_ids_to_new_ids) const;
+
+  // Creates a case block for |element_index| case. It adds clones of
+  // |insts_to_be_cloned| and a clone of |access_chain| with |element_index| as
+  // its first index. The termination instruction of the created case block will
+  // be a branch to |branch_target_id|. Puts old ids to new ids map for the
+  // cloned instructions in |old_ids_to_new_ids|.
+  BasicBlock* CreateCaseBlock(
+      Instruction* access_chain, uint32_t element_index,
+      const std::deque<Instruction*>& insts_to_be_cloned,
+      uint32_t branch_target_id,
+      std::unordered_map<uint32_t, uint32_t>* old_ids_to_new_ids) const;
+
+  // Creates a default block for switch-case statement that has only a single
+  // instruction OpBranch whose target is a basic block with |merge_block_id|.
+  // If |null_const_for_phi_is_needed| is true, gets or creates a default null
+  // constant value for a phi instruction whose operands are |phi_operands| and
+  // puts it in |phi_operands|.
+  BasicBlock* CreateDefaultBlock(bool null_const_for_phi_is_needed,
+                                 std::vector<uint32_t>* phi_operands,
+                                 uint32_t merge_block_id) const;
+
+  // Creates and adds an OpSwitch used for the selection of OpAccessChain whose
+  // first Indexes operand is |access_chain_index_var_id|. The OpSwitch will be
+  // added at the end of |parent_block|. It will jump to |default_id| for the
+  // default case and jumps to one of case blocks whose ids are |case_block_ids|
+  // if |access_chain_index_var_id| matches the case number. |merge_id| is the
+  // merge block id.
+  void AddSwitchForAccessChain(
+      BasicBlock* parent_block, uint32_t access_chain_index_var_id,
+      uint32_t default_id, uint32_t merge_id,
+      const std::vector<uint32_t>& case_block_ids) const;
+
+  // Creates a phi instruction with |phi_operands| as values and
+  // |case_block_ids| and |default_block_id| as incoming blocks. The size of
+  // |phi_operands| must be exactly 1 larger than the size of |case_block_ids|.
+  // The last element of |phi_operands| will be used for |default_block_id|. It
+  // adds the phi instruction to the beginning of |parent_block|.
+  uint32_t CreatePhiInstruction(BasicBlock* parent_block,
+                                const std::vector<uint32_t>& phi_operands,
+                                const std::vector<uint32_t>& case_block_ids,
+                                uint32_t default_block_id) const;
+
+  // Replaces the incoming block operand of OpPhi instructions with
+  // |new_incoming_block_id| if the incoming block operand is
+  // |old_incoming_block_id|.
+  void ReplacePhiIncomingBlock(uint32_t old_incoming_block_id,
+                               uint32_t new_incoming_block_id) const;
+
+  // Create an OpConstantNull instruction whose result type id is |type_id|.
+  Instruction* GetConstNull(uint32_t type_id) const;
+};
+
+}  // namespace opt
+}  // namespace spvtools
+
+#endif  // SOURCE_OPT_REPLACE_DESC_VAR_INDEX_ACCESS_H_

+ 314 - 0
ThirdParty/Glslang/External/spirv-tools/source/opt/spread_volatile_semantics.cpp

@@ -0,0 +1,314 @@
+// Copyright (c) 2022 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "source/opt/spread_volatile_semantics.h"
+
+#include "source/opt/decoration_manager.h"
+#include "source/opt/ir_builder.h"
+#include "source/spirv_constant.h"
+
+namespace spvtools {
+namespace opt {
+namespace {
+
+const uint32_t kOpDecorateInOperandBuiltinDecoration = 2u;
+const uint32_t kOpLoadInOperandMemoryOperands = 1u;
+const uint32_t kOpEntryPointInOperandEntryPoint = 1u;
+const uint32_t kOpEntryPointInOperandInterface = 3u;
+
+bool HasBuiltinDecoration(analysis::DecorationManager* decoration_manager,
+                          uint32_t var_id, uint32_t built_in) {
+  return decoration_manager->FindDecoration(
+      var_id, SpvDecorationBuiltIn, [built_in](const Instruction& inst) {
+        return built_in == inst.GetSingleWordInOperand(
+                               kOpDecorateInOperandBuiltinDecoration);
+      });
+}
+
+bool IsBuiltInForRayTracingVolatileSemantics(uint32_t built_in) {
+  switch (built_in) {
+    case SpvBuiltInSMIDNV:
+    case SpvBuiltInWarpIDNV:
+    case SpvBuiltInSubgroupSize:
+    case SpvBuiltInSubgroupLocalInvocationId:
+    case SpvBuiltInSubgroupEqMask:
+    case SpvBuiltInSubgroupGeMask:
+    case SpvBuiltInSubgroupGtMask:
+    case SpvBuiltInSubgroupLeMask:
+    case SpvBuiltInSubgroupLtMask:
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool HasBuiltinForRayTracingVolatileSemantics(
+    analysis::DecorationManager* decoration_manager, uint32_t var_id) {
+  return decoration_manager->FindDecoration(
+      var_id, SpvDecorationBuiltIn, [](const Instruction& inst) {
+        uint32_t built_in =
+            inst.GetSingleWordInOperand(kOpDecorateInOperandBuiltinDecoration);
+        return IsBuiltInForRayTracingVolatileSemantics(built_in);
+      });
+}
+
+bool HasVolatileDecoration(analysis::DecorationManager* decoration_manager,
+                           uint32_t var_id) {
+  return decoration_manager->HasDecoration(var_id, SpvDecorationVolatile);
+}
+
+bool HasOnlyEntryPointsAsFunctions(IRContext* context, Module* module) {
+  std::unordered_set<uint32_t> entry_function_ids;
+  for (Instruction& entry_point : module->entry_points()) {
+    entry_function_ids.insert(
+        entry_point.GetSingleWordInOperand(kOpEntryPointInOperandEntryPoint));
+  }
+  for (auto& function : *module) {
+    if (entry_function_ids.find(function.result_id()) ==
+        entry_function_ids.end()) {
+      std::string message(
+          "Functions of SPIR-V for spread-volatile-semantics pass input must "
+          "be inlined except entry points");
+      message += "\n  " + function.DefInst().PrettyPrint(
+                              SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES);
+      context->consumer()(SPV_MSG_ERROR, "", {0, 0, 0}, message.c_str());
+      return false;
+    }
+  }
+  return true;
+}
+
+}  // namespace
+
+Pass::Status SpreadVolatileSemantics::Process() {
+  if (!HasOnlyEntryPointsAsFunctions(context(), get_module())) {
+    return Status::Failure;
+  }
+
+  const bool is_vk_memory_model_enabled =
+      context()->get_feature_mgr()->HasCapability(
+          SpvCapabilityVulkanMemoryModel);
+  CollectTargetsForVolatileSemantics(is_vk_memory_model_enabled);
+
+  // If VulkanMemoryModel capability is not enabled, we have to set Volatile
+  // decoration for interface variables instead of setting Volatile for load
+  // instructions. If an interface (or pointers to it) is used by two load
+  // instructions in two entry points and one must be volatile while another
+  // is not, we have to report an error for the conflict.
+  if (!is_vk_memory_model_enabled &&
+      HasInterfaceInConflictOfVolatileSemantics()) {
+    return Status::Failure;
+  }
+
+  return SpreadVolatileSemanticsToVariables(is_vk_memory_model_enabled);
+}
+
+Pass::Status SpreadVolatileSemantics::SpreadVolatileSemanticsToVariables(
+    const bool is_vk_memory_model_enabled) {
+  Status status = Status::SuccessWithoutChange;
+  for (Instruction& var : context()->types_values()) {
+    auto entry_function_ids =
+        EntryFunctionsToSpreadVolatileSemanticsForVar(var.result_id());
+    if (entry_function_ids.empty()) {
+      continue;
+    }
+
+    if (is_vk_memory_model_enabled) {
+      SetVolatileForLoadsInEntries(&var, entry_function_ids);
+    } else {
+      DecorateVarWithVolatile(&var);
+    }
+    status = Status::SuccessWithChange;
+  }
+  return status;
+}
+
+bool SpreadVolatileSemantics::IsTargetUsedByNonVolatileLoadInEntryPoint(
+    uint32_t var_id, Instruction* entry_point) {
+  uint32_t entry_function_id =
+      entry_point->GetSingleWordInOperand(kOpEntryPointInOperandEntryPoint);
+  return !VisitLoadsOfPointersToVariableInEntries(
+      var_id,
+      [](Instruction* load) {
+        // If it has a load without volatile memory operand, finish traversal
+        // and return false.
+        if (load->NumInOperands() <= kOpLoadInOperandMemoryOperands) {
+          return false;
+        }
+        uint32_t memory_operands =
+            load->GetSingleWordInOperand(kOpLoadInOperandMemoryOperands);
+        return (memory_operands & SpvMemoryAccessVolatileMask) != 0;
+      },
+      {entry_function_id});
+}
+
+bool SpreadVolatileSemantics::HasInterfaceInConflictOfVolatileSemantics() {
+  for (Instruction& entry_point : get_module()->entry_points()) {
+    SpvExecutionModel execution_model =
+        static_cast<SpvExecutionModel>(entry_point.GetSingleWordInOperand(0));
+    for (uint32_t operand_index = kOpEntryPointInOperandInterface;
+         operand_index < entry_point.NumInOperands(); ++operand_index) {
+      uint32_t var_id = entry_point.GetSingleWordInOperand(operand_index);
+      if (!EntryFunctionsToSpreadVolatileSemanticsForVar(var_id).empty() &&
+          !IsTargetForVolatileSemantics(var_id, execution_model) &&
+          IsTargetUsedByNonVolatileLoadInEntryPoint(var_id, &entry_point)) {
+        Instruction* inst = context()->get_def_use_mgr()->GetDef(var_id);
+        context()->EmitErrorMessage(
+            "Variable is a target for Volatile semantics for an entry point, "
+            "but it is not for another entry point",
+            inst);
+        return true;
+      }
+    }
+  }
+  return false;
+}
+
+void SpreadVolatileSemantics::MarkVolatileSemanticsForVariable(
+    uint32_t var_id, Instruction* entry_point) {
+  uint32_t entry_function_id =
+      entry_point->GetSingleWordInOperand(kOpEntryPointInOperandEntryPoint);
+  auto itr = var_ids_to_entry_fn_for_volatile_semantics_.find(var_id);
+  if (itr == var_ids_to_entry_fn_for_volatile_semantics_.end()) {
+    var_ids_to_entry_fn_for_volatile_semantics_[var_id] = {entry_function_id};
+    return;
+  }
+  itr->second.insert(entry_function_id);
+}
+
+void SpreadVolatileSemantics::CollectTargetsForVolatileSemantics(
+    const bool is_vk_memory_model_enabled) {
+  for (Instruction& entry_point : get_module()->entry_points()) {
+    SpvExecutionModel execution_model =
+        static_cast<SpvExecutionModel>(entry_point.GetSingleWordInOperand(0));
+    for (uint32_t operand_index = kOpEntryPointInOperandInterface;
+         operand_index < entry_point.NumInOperands(); ++operand_index) {
+      uint32_t var_id = entry_point.GetSingleWordInOperand(operand_index);
+      if (!IsTargetForVolatileSemantics(var_id, execution_model)) {
+        continue;
+      }
+      if (is_vk_memory_model_enabled ||
+          IsTargetUsedByNonVolatileLoadInEntryPoint(var_id, &entry_point)) {
+        MarkVolatileSemanticsForVariable(var_id, &entry_point);
+      }
+    }
+  }
+}
+
+void SpreadVolatileSemantics::DecorateVarWithVolatile(Instruction* var) {
+  analysis::DecorationManager* decoration_manager =
+      context()->get_decoration_mgr();
+  uint32_t var_id = var->result_id();
+  if (HasVolatileDecoration(decoration_manager, var_id)) {
+    return;
+  }
+  get_decoration_mgr()->AddDecoration(
+      SpvOpDecorate, {{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {var_id}},
+                      {spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER,
+                       {SpvDecorationVolatile}}});
+}
+
+bool SpreadVolatileSemantics::VisitLoadsOfPointersToVariableInEntries(
+    uint32_t var_id, const std::function<bool(Instruction*)>& handle_load,
+    const std::unordered_set<uint32_t>& entry_function_ids) {
+  std::vector<uint32_t> worklist({var_id});
+  auto* def_use_mgr = context()->get_def_use_mgr();
+  while (!worklist.empty()) {
+    uint32_t ptr_id = worklist.back();
+    worklist.pop_back();
+    bool finish_traversal = !def_use_mgr->WhileEachUser(
+        ptr_id, [this, &worklist, &ptr_id, handle_load,
+                 &entry_function_ids](Instruction* user) {
+          BasicBlock* block = context()->get_instr_block(user);
+          if (block == nullptr ||
+              entry_function_ids.find(block->GetParent()->result_id()) ==
+                  entry_function_ids.end()) {
+            return true;
+          }
+
+          if (user->opcode() == SpvOpAccessChain ||
+              user->opcode() == SpvOpInBoundsAccessChain ||
+              user->opcode() == SpvOpPtrAccessChain ||
+              user->opcode() == SpvOpInBoundsPtrAccessChain ||
+              user->opcode() == SpvOpCopyObject) {
+            if (ptr_id == user->GetSingleWordInOperand(0))
+              worklist.push_back(user->result_id());
+            return true;
+          }
+
+          if (user->opcode() != SpvOpLoad) {
+            return true;
+          }
+
+          return handle_load(user);
+        });
+    if (finish_traversal) return false;
+  }
+  return true;
+}
+
+void SpreadVolatileSemantics::SetVolatileForLoadsInEntries(
+    Instruction* var, const std::unordered_set<uint32_t>& entry_function_ids) {
+  // Set Volatile memory operand for all load instructions if they do not have
+  // it.
+  VisitLoadsOfPointersToVariableInEntries(
+      var->result_id(),
+      [](Instruction* load) {
+        if (load->NumInOperands() <= kOpLoadInOperandMemoryOperands) {
+          load->AddOperand(
+              {SPV_OPERAND_TYPE_MEMORY_ACCESS, {SpvMemoryAccessVolatileMask}});
+          return true;
+        }
+        uint32_t memory_operands =
+            load->GetSingleWordInOperand(kOpLoadInOperandMemoryOperands);
+        memory_operands |= SpvMemoryAccessVolatileMask;
+        load->SetInOperand(kOpLoadInOperandMemoryOperands, {memory_operands});
+        return true;
+      },
+      entry_function_ids);
+}
+
+bool SpreadVolatileSemantics::IsTargetForVolatileSemantics(
+    uint32_t var_id, SpvExecutionModel execution_model) {
+  analysis::DecorationManager* decoration_manager =
+      context()->get_decoration_mgr();
+  if (execution_model == SpvExecutionModelFragment) {
+    return get_module()->version() >= SPV_SPIRV_VERSION_WORD(1, 6) &&
+           HasBuiltinDecoration(decoration_manager, var_id,
+                                SpvBuiltInHelperInvocation);
+  }
+
+  if (execution_model == SpvExecutionModelIntersectionKHR ||
+      execution_model == SpvExecutionModelIntersectionNV) {
+    if (HasBuiltinDecoration(decoration_manager, var_id,
+                             SpvBuiltInRayTmaxKHR)) {
+      return true;
+    }
+  }
+
+  switch (execution_model) {
+    case SpvExecutionModelRayGenerationKHR:
+    case SpvExecutionModelClosestHitKHR:
+    case SpvExecutionModelMissKHR:
+    case SpvExecutionModelCallableKHR:
+    case SpvExecutionModelIntersectionKHR:
+      return HasBuiltinForRayTracingVolatileSemantics(decoration_manager,
+                                                      var_id);
+    default:
+      return false;
+  }
+}
+
+}  // namespace opt
+}  // namespace spvtools

+ 110 - 0
ThirdParty/Glslang/External/spirv-tools/source/opt/spread_volatile_semantics.h

@@ -0,0 +1,110 @@
+// Copyright (c) 2022 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SOURCE_OPT_SPREAD_VOLATILE_SEMANTICS_H_
+#define SOURCE_OPT_SPREAD_VOLATILE_SEMANTICS_H_
+
+#include "source/opt/pass.h"
+
+namespace spvtools {
+namespace opt {
+
+// See optimizer.hpp for documentation.
+class SpreadVolatileSemantics : public Pass {
+ public:
+  SpreadVolatileSemantics() {}
+
+  const char* name() const override { return "spread-volatile-semantics"; }
+
+  Status Process() override;
+
+  IRContext::Analysis GetPreservedAnalyses() override {
+    return IRContext::kAnalysisDefUse | IRContext::kAnalysisDecorations |
+           IRContext::kAnalysisInstrToBlockMapping;
+  }
+
+ private:
+  // Iterates interface variables and spreads the Volatile semantics if it has
+  // load instructions for the Volatile semantics.
+  Pass::Status SpreadVolatileSemanticsToVariables(
+      const bool is_vk_memory_model_enabled);
+
+  // Returns whether |var_id| is the result id of a target builtin variable for
+  // the volatile semantics for |execution_model| based on the Vulkan spec
+  // VUID-StandaloneSpirv-VulkanMemoryModel-04678 or
+  // VUID-StandaloneSpirv-VulkanMemoryModel-04679.
+  bool IsTargetForVolatileSemantics(uint32_t var_id,
+                                    SpvExecutionModel execution_model);
+
+  // Collects interface variables that need the volatile semantics.
+  // |is_vk_memory_model_enabled| is true if VulkanMemoryModel capability is
+  // enabled.
+  void CollectTargetsForVolatileSemantics(
+      const bool is_vk_memory_model_enabled);
+
+  // Reports an error if an interface variable is used by two entry points and
+  // it needs the Volatile decoration for one but not for another. Returns true
+  // if the error must be reported.
+  bool HasInterfaceInConflictOfVolatileSemantics();
+
+  // Returns whether the variable whose result is |var_id| is used by a
+  // non-volatile load or a pointer to it is used by a non-volatile load in
+  // |entry_point| or not.
+  bool IsTargetUsedByNonVolatileLoadInEntryPoint(uint32_t var_id,
+                                                 Instruction* entry_point);
+
+  // Visits load instructions of pointers to variable whose result id is
+  // |var_id| if the load instructions are in entry points whose
+  // function id is one of |entry_function_ids|. |handle_load| is a function to
+  // do some actions for the load instructions. Finishes the traversal and
+  // returns false if |handle_load| returns false for a load instruction.
+  // Otherwise, returns true after running |handle_load| for all the load
+  // instructions.
+  bool VisitLoadsOfPointersToVariableInEntries(
+      uint32_t var_id, const std::function<bool(Instruction*)>& handle_load,
+      const std::unordered_set<uint32_t>& entry_function_ids);
+
+  // Sets Memory Operands of OpLoad instructions that load |var| or pointers
+  // of |var| as Volatile if the function id of the OpLoad instruction is
+  // included in |entry_function_ids|.
+  void SetVolatileForLoadsInEntries(
+      Instruction* var, const std::unordered_set<uint32_t>& entry_function_ids);
+
+  // Adds OpDecorate Volatile for |var| if it does not exist.
+  void DecorateVarWithVolatile(Instruction* var);
+
+  // Returns a set of entry function ids to spread the volatile semantics for
+  // the variable with the result id |var_id|.
+  std::unordered_set<uint32_t> EntryFunctionsToSpreadVolatileSemanticsForVar(
+      uint32_t var_id) {
+    auto itr = var_ids_to_entry_fn_for_volatile_semantics_.find(var_id);
+    if (itr == var_ids_to_entry_fn_for_volatile_semantics_.end()) return {};
+    return itr->second;
+  }
+
+  // Specifies that we have to spread the volatile semantics for the
+  // variable with the result id |var_id| for the entry point |entry_point|.
+  void MarkVolatileSemanticsForVariable(uint32_t var_id,
+                                        Instruction* entry_point);
+
+  // Result ids of variables to entry function ids for the volatile semantics
+  // spread.
+  std::unordered_map<uint32_t, std::unordered_set<uint32_t>>
+      var_ids_to_entry_fn_for_volatile_semantics_;
+};
+
+}  // namespace opt
+}  // namespace spvtools
+
+#endif  // SOURCE_OPT_SPREAD_VOLATILE_SEMANTICS_H_

+ 115 - 0
ThirdParty/Glslang/External/spirv-tools/source/opt/strip_nonsemantic_info_pass.cpp

@@ -0,0 +1,115 @@
+// Copyright (c) 2018 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "source/opt/strip_nonsemantic_info_pass.h"
+
+#include <cstring>
+#include <vector>
+
+#include "source/opt/instruction.h"
+#include "source/opt/ir_context.h"
+#include "source/util/string_utils.h"
+
+namespace spvtools {
+namespace opt {
+
+Pass::Status StripNonSemanticInfoPass::Process() {
+  bool modified = false;
+
+  std::vector<Instruction*> to_remove;
+
+  bool other_uses_for_decorate_string = false;
+  for (auto& inst : context()->module()->annotations()) {
+    switch (inst.opcode()) {
+      case SpvOpDecorateStringGOOGLE:
+        if (inst.GetSingleWordInOperand(1) == SpvDecorationHlslSemanticGOOGLE ||
+            inst.GetSingleWordInOperand(1) == SpvDecorationUserTypeGOOGLE) {
+          to_remove.push_back(&inst);
+        } else {
+          other_uses_for_decorate_string = true;
+        }
+        break;
+
+      case SpvOpMemberDecorateStringGOOGLE:
+        if (inst.GetSingleWordInOperand(2) == SpvDecorationHlslSemanticGOOGLE ||
+            inst.GetSingleWordInOperand(2) == SpvDecorationUserTypeGOOGLE) {
+          to_remove.push_back(&inst);
+        } else {
+          other_uses_for_decorate_string = true;
+        }
+        break;
+
+      case SpvOpDecorateId:
+        if (inst.GetSingleWordInOperand(1) ==
+            SpvDecorationHlslCounterBufferGOOGLE) {
+          to_remove.push_back(&inst);
+        }
+        break;
+
+      default:
+        break;
+    }
+  }
+
+  for (auto& inst : context()->module()->extensions()) {
+    const std::string ext_name = inst.GetInOperand(0).AsString();
+    if (ext_name == "SPV_GOOGLE_hlsl_functionality1") {
+      to_remove.push_back(&inst);
+    } else if (ext_name == "SPV_GOOGLE_user_type") {
+      to_remove.push_back(&inst);
+    } else if (!other_uses_for_decorate_string &&
+               ext_name == "SPV_GOOGLE_decorate_string") {
+      to_remove.push_back(&inst);
+    } else if (ext_name == "SPV_KHR_non_semantic_info") {
+      to_remove.push_back(&inst);
+    }
+  }
+
+  // remove any extended inst imports that are non semantic
+  std::unordered_set<uint32_t> non_semantic_sets;
+  for (auto& inst : context()->module()->ext_inst_imports()) {
+    assert(inst.opcode() == SpvOpExtInstImport &&
+           "Expecting an import of an extension's instruction set.");
+    const std::string extension_name = inst.GetInOperand(0).AsString();
+    if (spvtools::utils::starts_with(extension_name, "NonSemantic.")) {
+      non_semantic_sets.insert(inst.result_id());
+      to_remove.push_back(&inst);
+    }
+  }
+
+  // if we removed some non-semantic sets, then iterate over the instructions in
+  // the module to remove any OpExtInst that referenced those sets
+  if (!non_semantic_sets.empty()) {
+    context()->module()->ForEachInst(
+        [&non_semantic_sets, &to_remove](Instruction* inst) {
+          if (inst->opcode() == SpvOpExtInst) {
+            if (non_semantic_sets.find(inst->GetSingleWordInOperand(0)) !=
+                non_semantic_sets.end()) {
+              to_remove.push_back(inst);
+            }
+          }
+        },
+        true);
+  }
+
+  for (auto* inst : to_remove) {
+    modified = true;
+    context()->KillInst(inst);
+  }
+
+  return modified ? Status::SuccessWithChange : Status::SuccessWithoutChange;
+}
+
+}  // namespace opt
+}  // namespace spvtools

+ 44 - 0
ThirdParty/Glslang/External/spirv-tools/source/opt/strip_nonsemantic_info_pass.h

@@ -0,0 +1,44 @@
+// Copyright (c) 2018 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SOURCE_OPT_STRIP_NONSEMANTIC_INFO_PASS_H_
+#define SOURCE_OPT_STRIP_NONSEMANTIC_INFO_PASS_H_
+
+#include "source/opt/ir_context.h"
+#include "source/opt/module.h"
+#include "source/opt/pass.h"
+
+namespace spvtools {
+namespace opt {
+
+// See optimizer.hpp for documentation.
+class StripNonSemanticInfoPass : public Pass {
+ public:
+  const char* name() const override { return "strip-nonsemantic"; }
+  Status Process() override;
+
+  // Return the mask of preserved Analyses.
+  IRContext::Analysis GetPreservedAnalyses() override {
+    return IRContext::kAnalysisInstrToBlockMapping |
+           IRContext::kAnalysisCombinators | IRContext::kAnalysisCFG |
+           IRContext::kAnalysisDominatorAnalysis |
+           IRContext::kAnalysisLoopAnalysis | IRContext::kAnalysisNameMap |
+           IRContext::kAnalysisConstants | IRContext::kAnalysisTypes;
+  }
+};
+
+}  // namespace opt
+}  // namespace spvtools
+
+#endif  // SOURCE_OPT_STRIP_NONSEMANTIC_INFO_PASS_H_

+ 67 - 0
ThirdParty/Glslang/External/spirv-tools/source/reduce/structured_construct_to_block_reduction_opportunity.cpp

@@ -0,0 +1,67 @@
+// Copyright (c) 2021 Alastair F. Donaldson
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "source/reduce/structured_construct_to_block_reduction_opportunity.h"
+
+namespace spvtools {
+namespace reduce {
+
+bool StructuredConstructToBlockReductionOpportunity::PreconditionHolds() {
+  return context_->get_def_use_mgr()->GetDef(construct_header_) != nullptr;
+}
+
+void StructuredConstructToBlockReductionOpportunity::Apply() {
+  auto header_block = context_->cfg()->block(construct_header_);
+  auto merge_block = context_->cfg()->block(header_block->MergeBlockId());
+
+  auto* enclosing_function = header_block->GetParent();
+
+  // A region of blocks is defined in terms of dominators and post-dominators,
+  // so we compute these for the enclosing function.
+  auto* dominators = context_->GetDominatorAnalysis(enclosing_function);
+  auto* postdominators = context_->GetPostDominatorAnalysis(enclosing_function);
+
+  // For each block in the function, determine whether it is inside the region.
+  // If it is, delete it.
+  for (auto block_it = enclosing_function->begin();
+       block_it != enclosing_function->end();) {
+    if (header_block != &*block_it && merge_block != &*block_it &&
+        dominators->Dominates(header_block, &*block_it) &&
+        postdominators->Dominates(merge_block, &*block_it)) {
+      block_it = block_it.Erase();
+    } else {
+      ++block_it;
+    }
+  }
+  // Having removed some blocks from the module it is necessary to invalidate
+  // analyses, since the remaining patch-up work depends on various analyses
+  // which will otherwise reference blocks that have been deleted.
+  context_->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone);
+
+  // We demote the header of the region to a regular block by deleting its merge
+  // instruction.
+  context_->KillInst(header_block->GetMergeInst());
+
+  // The terminator for the header block is changed to be an unconditional
+  // branch to the merge block.
+  header_block->terminator()->SetOpcode(SpvOpBranch);
+  header_block->terminator()->SetInOperands(
+      {{SPV_OPERAND_TYPE_ID, {merge_block->id()}}});
+
+  // This is an intrusive change, so we invalidate all analyses.
+  context_->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone);
+}
+
+}  // namespace reduce
+}  // namespace spvtools

+ 49 - 0
ThirdParty/Glslang/External/spirv-tools/source/reduce/structured_construct_to_block_reduction_opportunity.h

@@ -0,0 +1,49 @@
+// Copyright (c) 2021 Alastair F. Donaldson
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SOURCE_REDUCE_STRUCTURED_CONSTRUCT_TO_BLOCK_REDUCTION_OPPORTUNITY_H_
+#define SOURCE_REDUCE_STRUCTURED_CONSTRUCT_TO_BLOCK_REDUCTION_OPPORTUNITY_H_
+
+#include "source/opt/ir_context.h"
+#include "source/reduce/reduction_opportunity.h"
+
+namespace spvtools {
+namespace reduce {
+
+// An opportunity to replace a skeletal structured control flow construct with a
+// single block.
+class StructuredConstructToBlockReductionOpportunity
+    : public ReductionOpportunity {
+ public:
+  // Constructs an opportunity from a header block id.
+  StructuredConstructToBlockReductionOpportunity(opt::IRContext* context,
+                                                 uint32_t construct_header)
+      : context_(context), construct_header_(construct_header) {}
+
+  // Returns true if and only if |construct_header_| exists in the module -
+  // another opportunity may have removed it.
+  bool PreconditionHolds() override;
+
+ protected:
+  void Apply() override;
+
+ private:
+  opt::IRContext* context_;
+  uint32_t construct_header_;
+};
+
+}  // namespace reduce
+}  // namespace spvtools
+
+#endif  // SOURCE_REDUCE_STRUCTURED_CONSTRUCT_TO_BLOCK_REDUCTION_OPPORTUNITY_H_

+ 185 - 0
ThirdParty/Glslang/External/spirv-tools/source/reduce/structured_construct_to_block_reduction_opportunity_finder.cpp

@@ -0,0 +1,185 @@
+// Copyright (c) 2021 Alastair F. Donaldson
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "source/reduce/structured_construct_to_block_reduction_opportunity_finder.h"
+
+#include <unordered_set>
+
+#include "source/reduce/structured_construct_to_block_reduction_opportunity.h"
+
+namespace spvtools {
+namespace reduce {
+
+std::vector<std::unique_ptr<ReductionOpportunity>>
+StructuredConstructToBlockReductionOpportunityFinder::GetAvailableOpportunities(
+    opt::IRContext* context, uint32_t target_function) const {
+  std::vector<std::unique_ptr<ReductionOpportunity>> result;
+
+  // Consider every function in the module.
+  for (auto* function : GetTargetFunctions(context, target_function)) {
+    // For every header block in the function, there is potentially a region of
+    // blocks that could be collapsed.
+    std::unordered_map<opt::BasicBlock*, std::unordered_set<opt::BasicBlock*>>
+        regions;
+
+    // Regions are identified using dominators and postdominators, so we compute
+    // those for the function.
+    auto* dominators = context->GetDominatorAnalysis(function);
+    auto* postdominators = context->GetPostDominatorAnalysis(function);
+
+    // Consider every block in the function.
+    for (auto& block : *function) {
+      // If a block has an unreachable predecessor then folding away a region in
+      // which that block is contained gets complicated, so we ignore regions
+      // that contain such blocks. We note whether this block suffers from this
+      // problem.
+      bool has_unreachable_predecessor =
+          HasUnreachablePredecessor(block, context);
+
+      // Look through all the regions we have identified so far to see whether
+      // this block is part of a region, or spoils a region (by having an
+      // unreachable predecessor).
+      for (auto entry = regions.begin(); entry != regions.end();) {
+        // |block| is in this region if it is dominated by the header,
+        // post-dominated by the merge, and different from the merge.
+        assert(&block != entry->first &&
+               "The block should not be the region's header because we only "
+               "make a region when we encounter its header.");
+        if (entry->first->MergeBlockId() != block.id() &&
+            dominators->Dominates(entry->first, &block) &&
+            postdominators->Dominates(
+                entry->first->GetMergeInst()->GetSingleWordInOperand(0),
+                block.id())) {
+          if (has_unreachable_predecessor) {
+            // The block would be in this region, but it has an unreachable
+            // predecessor. This spoils the region, so we remove it.
+            entry = regions.erase(entry);
+            continue;
+          } else {
+            // Add the block to the region.
+            entry->second.insert(&block);
+          }
+        }
+        ++entry;
+      }
+      if (block.MergeBlockIdIfAny() == 0) {
+        // The block isn't a header, so it doesn't constitute a new region.
+        continue;
+      }
+      if (!context->IsReachable(block)) {
+        // The block isn't reachable, so it doesn't constitute a new region.
+        continue;
+      }
+      auto* merge_block = context->cfg()->block(
+          block.GetMergeInst()->GetSingleWordInOperand(0));
+      if (!context->IsReachable(*merge_block)) {
+        // The block's merge is unreachable, so it doesn't constitute a new
+        // region.
+        continue;
+      }
+      assert(dominators->Dominates(&block, merge_block) &&
+             "The merge block is reachable, so the header must dominate it");
+      if (!postdominators->Dominates(merge_block, &block)) {
+        // The block is not post-dominated by its merge. This happens for
+        // instance when there is a break from a conditional, or an early exit.
+        // This also means that we don't add a region.
+        continue;
+      }
+      // We have a reachable header block with a reachable merge that
+      // postdominates the header: this means we have a new region.
+      regions.emplace(&block, std::unordered_set<opt::BasicBlock*>());
+    }
+
+    // Now that we have found all the regions and blocks within them, we check
+    // whether any region defines an id that is used outside the region. If this
+    // is *not* the case, then we have an opportunity to collapse the region
+    // down to its header block and merge block.
+    for (auto& entry : regions) {
+      if (DefinitionsRestrictedToRegion(*entry.first, entry.second, context)) {
+        result.emplace_back(
+            MakeUnique<StructuredConstructToBlockReductionOpportunity>(
+                context, entry.first->id()));
+      }
+    }
+  }
+  return result;
+}
+
+bool StructuredConstructToBlockReductionOpportunityFinder::
+    DefinitionsRestrictedToRegion(
+        const opt::BasicBlock& header,
+        const std::unordered_set<opt::BasicBlock*>& region,
+        opt::IRContext* context) {
+  // Consider every block in the region.
+  for (auto& block : region) {
+    // Consider every instruction in the block - this includes the label
+    // instruction
+    if (!block->WhileEachInst(
+            [context, &header, &region](opt::Instruction* inst) -> bool {
+              if (inst->result_id() == 0) {
+                // The instruction does not generate a result id, thus it cannot
+                // be referred to outside the region - this is fine.
+                return true;
+              }
+              // Consider every use of the instruction's result id.
+              if (!context->get_def_use_mgr()->WhileEachUse(
+                      inst->result_id(),
+                      [context, &header, &region](opt::Instruction* user,
+                                                  uint32_t) -> bool {
+                        auto user_block = context->get_instr_block(user);
+                        if (user == header.GetMergeInst() ||
+                            user == header.terminator()) {
+                          // We are going to delete the header's merge
+                          // instruction and rewrite its terminator, so it does
+                          // not matter if the user is one of these
+                          // instructions.
+                          return true;
+                        }
+                        if (user_block == nullptr ||
+                            region.count(user_block) == 0) {
+                          // The user is either a global instruction, or an
+                          // instruction in a block outside the region. Removing
+                          // the region would invalidate this user.
+                          return false;
+                        }
+                        return true;
+                      })) {
+                return false;
+              }
+              return true;
+            })) {
+      return false;
+    }
+  }
+  return true;
+}
+
+bool StructuredConstructToBlockReductionOpportunityFinder::
+    HasUnreachablePredecessor(const opt::BasicBlock& block,
+                              opt::IRContext* context) {
+  for (auto pred : context->cfg()->preds(block.id())) {
+    if (!context->IsReachable(*context->cfg()->block(pred))) {
+      return true;
+    }
+  }
+  return false;
+}
+
+std::string StructuredConstructToBlockReductionOpportunityFinder::GetName()
+    const {
+  return "StructuredConstructToBlockReductionOpportunityFinder";
+}
+
+}  // namespace reduce
+}  // namespace spvtools

+ 57 - 0
ThirdParty/Glslang/External/spirv-tools/source/reduce/structured_construct_to_block_reduction_opportunity_finder.h

@@ -0,0 +1,57 @@
+// Copyright (c) 2021 Alastair F. Donaldson
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SOURCE_REDUCE_STRUCTURED_CONSTRUCT_TO_BLOCK_REDUCTION_OPPORTUNITY_FINDER_H
+#define SOURCE_REDUCE_STRUCTURED_CONSTRUCT_TO_BLOCK_REDUCTION_OPPORTUNITY_FINDER_H
+
+#include "source/reduce/reduction_opportunity_finder.h"
+
+namespace spvtools {
+namespace reduce {
+
+// A finder for opportunities to replace a skeletal structured control flow
+// construct - that is, a construct that does not define anything that's used
+// outside the construct - into its header block.
+class StructuredConstructToBlockReductionOpportunityFinder
+    : public ReductionOpportunityFinder {
+ public:
+  StructuredConstructToBlockReductionOpportunityFinder() = default;
+
+  ~StructuredConstructToBlockReductionOpportunityFinder() override = default;
+
+  std::string GetName() const final;
+
+  std::vector<std::unique_ptr<ReductionOpportunity>> GetAvailableOpportunities(
+      opt::IRContext* context, uint32_t target_function) const final;
+
+ private:
+  // Returns true if and only if all instructions defined in |region| are used
+  // only inside |region|, with the exception that they may be used by the merge
+  // or terminator instruction of |header|, which must be the header block for
+  // the region.
+  static bool DefinitionsRestrictedToRegion(
+      const opt::BasicBlock& header,
+      const std::unordered_set<opt::BasicBlock*>& region,
+      opt::IRContext* context);
+
+  // Returns true if and only if |block| has at least one predecessor that is
+  // unreachable in the control flow graph of its function.
+  static bool HasUnreachablePredecessor(const opt::BasicBlock& block,
+                                        opt::IRContext* context);
+};
+
+}  // namespace reduce
+}  // namespace spvtools
+
+#endif  // SOURCE_REDUCE_STRUCTURED_CONSTRUCT_TO_BLOCK_REDUCTION_OPPORTUNITY_FINDER_H

+ 53 - 0
ThirdParty/Glslang/External/spirv-tools/source/util/hash_combine.h

@@ -0,0 +1,53 @@
+// Copyright (c) 2022 The Khronos Group Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SOURCE_UTIL_HASH_COMBINE_H_
+#define SOURCE_UTIL_HASH_COMBINE_H_
+
+#include <cstddef>
+#include <functional>
+#include <vector>
+
+namespace spvtools {
+namespace utils {
+
+// Helpers for incrementally computing hashes.
+// For reference, see
+// http://open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3876.pdf
+
+template <typename T>
+inline size_t hash_combine(std::size_t seed, const T& val) {
+  return seed ^ (std::hash<T>()(val) + 0x9e3779b9 + (seed << 6) + (seed >> 2));
+}
+
+template <typename T>
+inline size_t hash_combine(std::size_t hash, const std::vector<T>& vals) {
+  for (const T& val : vals) {
+    hash = hash_combine(hash, val);
+  }
+  return hash;
+}
+
+inline size_t hash_combine(std::size_t hash) { return hash; }
+
+template <typename T, typename... Types>
+inline size_t hash_combine(std::size_t hash, const T& val,
+                           const Types&... args) {
+  return hash_combine(hash_combine(hash, val), args...);
+}
+
+}  // namespace utils
+}  // namespace spvtools
+
+#endif  // SOURCE_UTIL_HASH_COMBINE_H_

+ 236 - 0
ThirdParty/Glslang/External/spirv-tools/source/util/pooled_linked_list.h

@@ -0,0 +1,236 @@
+// Copyright (c) 2021 The Khronos Group Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SOURCE_UTIL_POOLED_LINKED_LIST_H_
+#define SOURCE_UTIL_POOLED_LINKED_LIST_H_
+
+#include <cstdint>
+#include <vector>
+
+namespace spvtools {
+namespace utils {
+
+// Shared storage of nodes for PooledLinkedList.
+template <typename T>
+class PooledLinkedListNodes {
+ public:
+  struct Node {
+    Node(T e, int32_t n = -1) : element(e), next(n) {}
+
+    T element = {};
+    int32_t next = -1;
+  };
+
+  PooledLinkedListNodes() = default;
+  PooledLinkedListNodes(const PooledLinkedListNodes&) = delete;
+  PooledLinkedListNodes& operator=(const PooledLinkedListNodes&) = delete;
+
+  PooledLinkedListNodes(PooledLinkedListNodes&& that) {
+    *this = std::move(that);
+  }
+
+  PooledLinkedListNodes& operator=(PooledLinkedListNodes&& that) {
+    vec_ = std::move(that.vec_);
+    free_nodes_ = that.free_nodes_;
+    return *this;
+  }
+
+  size_t total_nodes() { return vec_.size(); }
+  size_t free_nodes() { return free_nodes_; }
+  size_t used_nodes() { return total_nodes() - free_nodes(); }
+
+ private:
+  template <typename ListT>
+  friend class PooledLinkedList;
+
+  Node& at(int32_t index) { return vec_[index]; }
+  const Node& at(int32_t index) const { return vec_[index]; }
+
+  int32_t insert(T element) {
+    int32_t index = int32_t(vec_.size());
+    vec_.emplace_back(element);
+    return index;
+  }
+
+  std::vector<Node> vec_;
+  size_t free_nodes_ = 0;
+};
+
+// Implements a linked-list where list nodes come from a shared pool. This is
+// meant to be used in scenarios where it is desirable to avoid many small
+// allocations.
+//
+// Instead of pointers, the list uses indices to allow the underlying storage
+// to be modified without needing to modify the list. When removing elements
+// from the list, nodes are not deleted or recycled: to reclaim unused space,
+// perform a sequence of |move_nodes| operations into a temporary pool, which
+// then is moved into the old pool.
+//
+// This does *not* attempt to implement a full stl-compatible interface.
+template <typename T>
+class PooledLinkedList {
+ public:
+  using NodePool = PooledLinkedListNodes<T>;
+  using Node = typename NodePool::Node;
+
+  PooledLinkedList() = delete;
+  PooledLinkedList(NodePool* nodes) : nodes_(nodes) {}
+
+  // Shared iterator implementation (for iterator and const_iterator).
+  template <typename ElementT, typename PoolT>
+  class iterator_base {
+   public:
+    iterator_base(const iterator_base& i)
+        : nodes_(i.nodes_), index_(i.index_) {}
+
+    iterator_base& operator++() {
+      index_ = nodes_->at(index_).next;
+      return *this;
+    }
+
+    iterator_base& operator=(const iterator_base& i) {
+      nodes_ = i.nodes_;
+      index_ = i.index_;
+      return *this;
+    }
+
+    ElementT& operator*() const { return nodes_->at(index_).element; }
+    ElementT* operator->() const { return &nodes_->at(index_).element; }
+
+    friend inline bool operator==(const iterator_base& lhs,
+                                  const iterator_base& rhs) {
+      return lhs.nodes_ == rhs.nodes_ && lhs.index_ == rhs.index_;
+    }
+    friend inline bool operator!=(const iterator_base& lhs,
+                                  const iterator_base& rhs) {
+      return lhs.nodes_ != rhs.nodes_ || lhs.index_ != rhs.index_;
+    }
+
+    // Define standard iterator types needs so this class can be
+    // used with <algorithms>.
+    using iterator_category = std::forward_iterator_tag;
+    using difference_type = std::ptrdiff_t;
+    using value_type = ElementT;
+    using pointer = ElementT*;
+    using const_pointer = const ElementT*;
+    using reference = ElementT&;
+    using const_reference = const ElementT&;
+    using size_type = size_t;
+
+   private:
+    friend PooledLinkedList;
+
+    iterator_base(PoolT* pool, int32_t index) : nodes_(pool), index_(index) {}
+
+    PoolT* nodes_;
+    int32_t index_ = -1;
+  };
+
+  using iterator = iterator_base<T, std::vector<Node>>;
+  using const_iterator = iterator_base<const T, const std::vector<Node>>;
+
+  bool empty() const { return head_ == -1; }
+
+  T& front() { return nodes_->at(head_).element; }
+  T& back() { return nodes_->at(tail_).element; }
+  const T& front() const { return nodes_->at(head_).element; }
+  const T& back() const { return nodes_->at(tail_).element; }
+
+  iterator begin() { return iterator(&nodes_->vec_, head_); }
+  iterator end() { return iterator(&nodes_->vec_, -1); }
+  const_iterator begin() const { return const_iterator(&nodes_->vec_, head_); }
+  const_iterator end() const { return const_iterator(&nodes_->vec_, -1); }
+
+  // Inserts |element| at the back of the list.
+  void push_back(T element) {
+    int32_t new_tail = nodes_->insert(element);
+    if (head_ == -1) {
+      head_ = new_tail;
+      tail_ = new_tail;
+    } else {
+      nodes_->at(tail_).next = new_tail;
+      tail_ = new_tail;
+    }
+  }
+
+  // Removes the first occurrence of |element| from the list.
+  // Returns if |element| was removed.
+  bool remove_first(T element) {
+    int32_t* prev_next = &head_;
+    for (int32_t prev_index = -1, index = head_; index != -1; /**/) {
+      auto& node = nodes_->at(index);
+      if (node.element == element) {
+        // Snip from of the list, optionally fixing up tail pointer.
+        if (tail_ == index) {
+          assert(node.next == -1);
+          tail_ = prev_index;
+        }
+        *prev_next = node.next;
+        nodes_->free_nodes_++;
+        return true;
+      } else {
+        prev_next = &node.next;
+      }
+      prev_index = index;
+      index = node.next;
+    }
+    return false;
+  }
+
+  // Returns the PooledLinkedListNodes that owns this list's nodes.
+  NodePool* pool() { return nodes_; }
+
+  // Moves the nodes in this list into |new_pool|, providing a way to compact
+  // storage and reclaim unused space.
+  //
+  // Upon completing a sequence of |move_nodes| calls, you must ensure you
+  // retain ownership of the new storage your lists point to. Example usage:
+  //
+  //    unique_ptr<NodePool> new_pool = ...;
+  //    for (PooledLinkedList& list : lists) {
+  //        list.move_to(new_pool);
+  //    }
+  //    my_pool_ = std::move(new_pool);
+  void move_nodes(NodePool* new_pool) {
+    // Be sure to construct the list in the same order, instead of simply
+    // doing a sequence of push_backs.
+    int32_t prev_entry = -1;
+    int32_t nodes_freed = 0;
+    for (int32_t index = head_; index != -1; nodes_freed++) {
+      const auto& node = nodes_->at(index);
+      int32_t this_entry = new_pool->insert(node.element);
+      index = node.next;
+      if (prev_entry == -1) {
+        head_ = this_entry;
+      } else {
+        new_pool->at(prev_entry).next = this_entry;
+      }
+      prev_entry = this_entry;
+    }
+    tail_ = prev_entry;
+    // Update our old pool's free count, now we're a member of the new pool.
+    nodes_->free_nodes_ += nodes_freed;
+    nodes_ = new_pool;
+  }
+
+ private:
+  NodePool* nodes_;
+  int32_t head_ = -1;
+  int32_t tail_ = -1;
+};
+
+}  // namespace utils
+}  // namespace spvtools
+
+#endif  // SOURCE_UTIL_POOLED_LINKED_LIST_H_

+ 43 - 0
ThirdParty/Glslang/External/spirv-tools/source/wasm/README.md

@@ -0,0 +1,43 @@
+# SPIRV-Tools
+
+Wasm (WebAssembly) build of https://github.com/KhronosGroup/SPIRV-Tools
+
+## Usage
+
+```js
+const spirvTools = require("spirv-tools");
+
+const test = async () => {
+  // Load the library
+  const spv = await spirvTools();
+
+  // assemble
+  const source = `
+             OpCapability Linkage 
+             OpCapability Shader 
+             OpMemoryModel Logical GLSL450 
+             OpSource GLSL 450 
+             OpDecorate %spec SpecId 1 
+      %int = OpTypeInt 32 1 
+     %spec = OpSpecConstant %int 0 
+    %const = OpConstant %int 42`;
+  const asResult = spv.as(
+    source,
+    spv.SPV_ENV_UNIVERSAL_1_3,
+    spv.SPV_TEXT_TO_BINARY_OPTION_NONE
+  );
+  console.log(`as returned ${asResult.byteLength} bytes`);
+
+  // re-disassemble
+  const disResult = spv.dis(
+    asResult,
+    spv.SPV_ENV_UNIVERSAL_1_3,
+    spv.SPV_BINARY_TO_TEXT_OPTION_INDENT |
+      spv.SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES |
+      spv.SPV_BINARY_TO_TEXT_OPTION_COLOR
+  );
+  console.log("dis:\n", disResult);
+};
+
+test();
+```

+ 78 - 0
ThirdParty/Glslang/External/spirv-tools/source/wasm/build.sh

@@ -0,0 +1,78 @@
+#!/bin/bash
+
+# Copyright (c) 2020 The Khronos Group Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -e
+
+NUM_CORES=$(nproc)
+echo "Detected $NUM_CORES cores for building"
+
+DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
+VERSION=$(sed -n '0,/^v20/ s/^v\(20[0-9.]*\).*/\1/p' $DIR/../../CHANGES).${GITHUB_RUN_NUMBER:-0}
+echo "Version: $VERSION"
+
+build() { 
+    type=$1
+    shift
+    args=$@
+    mkdir -p build/$type
+    pushd build/$type
+    echo $args
+    emcmake cmake \
+        -DCMAKE_BUILD_TYPE=Release \
+        $args \
+        ../..
+    emmake make -j $(( $NUM_CORES )) SPIRV-Tools-static
+
+    echo Building js interface
+    emcc \
+        --bind \
+        -I../../include \
+        -std=c++11 \
+        ../../source/wasm/spirv-tools.cpp \
+        source/libSPIRV-Tools.a \
+        -o spirv-tools.js \
+        -s MODULARIZE \
+        -Oz
+
+    popd
+    mkdir -p out/$type
+
+    # copy other js files
+    cp source/wasm/spirv-tools.d.ts out/$type/
+    sed -e 's/\("version"\s*:\s*\).*/\1"'$VERSION'",/' source/wasm/package.json > out/$type/package.json
+    cp source/wasm/README.md out/$type/
+    cp LICENSE out/$type/
+
+    cp build/$type/spirv-tools.js out/$type/
+    gzip -9 -k -f out/$type/spirv-tools.js
+    if [ -e build/$type/spirv-tools.wasm ] ; then
+       cp build/$type/spirv-tools.wasm out/$type/
+       gzip -9 -k -f out/$type/spirv-tools.wasm
+    fi
+}
+
+if [ ! -d external/spirv-headers ] ; then
+    echo "Fetching SPIRV-headers"
+    git clone https://github.com/KhronosGroup/SPIRV-Headers.git external/spirv-headers
+fi
+
+echo Building ${BASH_REMATCH[1]}
+build web\
+    -DSPIRV_COLOR_TERMINAL=OFF\
+    -DSPIRV_SKIP_TESTS=ON\
+    -DSPIRV_SKIP_EXECUTABLES=ON
+
+wc -c out/*/*

+ 17 - 0
ThirdParty/Glslang/External/spirv-tools/source/wasm/package.json

@@ -0,0 +1,17 @@
+{
+  "name": "spirv-tools",
+  "version": "VERSION",
+  "license": "Apache-2.0",
+  "main": "spirv-tools",
+  "types": "spirv-tools.d.ts",
+  "files": [
+    "*.wasm",
+    "*.js",
+    "*.d.ts"
+  ],
+  "repository": {
+    "type": "git",
+    "url": "https://github.com/KhronosGroup/SPIRV-Tools"
+  },
+  "homepage": "https://github.com/KhronosGroup/SPIRV-Tools"
+}

+ 94 - 0
ThirdParty/Glslang/External/spirv-tools/source/wasm/spirv-tools.cpp

@@ -0,0 +1,94 @@
+// Copyright (c) 2020 The Khronos Group Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "spirv-tools/libspirv.hpp"
+
+#include <iostream>
+#include <string>
+#include <vector>
+
+#include <emscripten/bind.h>
+#include <emscripten/val.h>
+using namespace emscripten;
+
+void print_msg_to_stderr (spv_message_level_t, const char*,
+                          const spv_position_t&, const char* m) {
+  std::cerr << "error: " << m << std::endl;
+};
+
+std::string dis(std::string const& buffer, uint32_t env, uint32_t options) {
+  spvtools::SpirvTools core(static_cast<spv_target_env>(env));
+  core.SetMessageConsumer(print_msg_to_stderr);
+
+  std::vector<uint32_t> spirv;
+  const uint32_t* ptr = reinterpret_cast<const uint32_t*>(buffer.data());
+  spirv.assign(ptr, ptr + buffer.size() / 4);
+  std::string disassembly;
+  if (!core.Disassemble(spirv, &disassembly, options)) return "Error";
+  return disassembly;
+}
+
+emscripten::val as(std::string const& source, uint32_t env, uint32_t options) {
+  spvtools::SpirvTools core(static_cast<spv_target_env>(env));
+  core.SetMessageConsumer(print_msg_to_stderr);
+
+  std::vector<uint32_t> spirv;
+  if (!core.Assemble(source, &spirv, options)) spirv.clear();
+  const uint8_t* ptr = reinterpret_cast<const uint8_t*>(spirv.data());
+  return emscripten::val(emscripten::typed_memory_view(spirv.size() * 4,
+    ptr));
+}
+
+EMSCRIPTEN_BINDINGS(my_module) {
+  function("dis", &dis);
+  function("as", &as);
+  
+  constant("SPV_ENV_UNIVERSAL_1_0", static_cast<uint32_t>(SPV_ENV_UNIVERSAL_1_0));
+  constant("SPV_ENV_VULKAN_1_0", static_cast<uint32_t>(SPV_ENV_VULKAN_1_0));
+  constant("SPV_ENV_UNIVERSAL_1_1", static_cast<uint32_t>(SPV_ENV_UNIVERSAL_1_1));
+  constant("SPV_ENV_OPENCL_2_1", static_cast<uint32_t>(SPV_ENV_OPENCL_2_1));
+  constant("SPV_ENV_OPENCL_2_2", static_cast<uint32_t>(SPV_ENV_OPENCL_2_2));
+  constant("SPV_ENV_OPENGL_4_0", static_cast<uint32_t>(SPV_ENV_OPENGL_4_0));
+  constant("SPV_ENV_OPENGL_4_1", static_cast<uint32_t>(SPV_ENV_OPENGL_4_1));
+  constant("SPV_ENV_OPENGL_4_2", static_cast<uint32_t>(SPV_ENV_OPENGL_4_2));
+  constant("SPV_ENV_OPENGL_4_3", static_cast<uint32_t>(SPV_ENV_OPENGL_4_3));
+  constant("SPV_ENV_OPENGL_4_5", static_cast<uint32_t>(SPV_ENV_OPENGL_4_5));
+  constant("SPV_ENV_UNIVERSAL_1_2", static_cast<uint32_t>(SPV_ENV_UNIVERSAL_1_2));
+  constant("SPV_ENV_OPENCL_1_2", static_cast<uint32_t>(SPV_ENV_OPENCL_1_2));
+  constant("SPV_ENV_OPENCL_EMBEDDED_1_2", static_cast<uint32_t>(SPV_ENV_OPENCL_EMBEDDED_1_2));
+  constant("SPV_ENV_OPENCL_2_0", static_cast<uint32_t>(SPV_ENV_OPENCL_2_0));
+  constant("SPV_ENV_OPENCL_EMBEDDED_2_0", static_cast<uint32_t>(SPV_ENV_OPENCL_EMBEDDED_2_0));
+  constant("SPV_ENV_OPENCL_EMBEDDED_2_1", static_cast<uint32_t>(SPV_ENV_OPENCL_EMBEDDED_2_1));
+  constant("SPV_ENV_OPENCL_EMBEDDED_2_2", static_cast<uint32_t>(SPV_ENV_OPENCL_EMBEDDED_2_2));
+  constant("SPV_ENV_UNIVERSAL_1_3", static_cast<uint32_t>(SPV_ENV_UNIVERSAL_1_3));
+  constant("SPV_ENV_VULKAN_1_1", static_cast<uint32_t>(SPV_ENV_VULKAN_1_1));
+  constant("SPV_ENV_WEBGPU_0", static_cast<uint32_t>(SPV_ENV_WEBGPU_0));
+  constant("SPV_ENV_UNIVERSAL_1_4", static_cast<uint32_t>(SPV_ENV_UNIVERSAL_1_4));
+  constant("SPV_ENV_VULKAN_1_1_SPIRV_1_4", static_cast<uint32_t>(SPV_ENV_VULKAN_1_1_SPIRV_1_4));
+  constant("SPV_ENV_UNIVERSAL_1_5", static_cast<uint32_t>(SPV_ENV_UNIVERSAL_1_5));
+  constant("SPV_ENV_VULKAN_1_2", static_cast<uint32_t>(SPV_ENV_VULKAN_1_2));
+  constant("SPV_ENV_UNIVERSAL_1_6",
+           static_cast<uint32_t>(SPV_ENV_UNIVERSAL_1_6));
+
+  constant("SPV_BINARY_TO_TEXT_OPTION_NONE", static_cast<uint32_t>(SPV_BINARY_TO_TEXT_OPTION_NONE));
+  constant("SPV_BINARY_TO_TEXT_OPTION_PRINT", static_cast<uint32_t>(SPV_BINARY_TO_TEXT_OPTION_PRINT));
+  constant("SPV_BINARY_TO_TEXT_OPTION_COLOR", static_cast<uint32_t>(SPV_BINARY_TO_TEXT_OPTION_COLOR));
+  constant("SPV_BINARY_TO_TEXT_OPTION_INDENT", static_cast<uint32_t>(SPV_BINARY_TO_TEXT_OPTION_INDENT));
+  constant("SPV_BINARY_TO_TEXT_OPTION_SHOW_BYTE_OFFSET", static_cast<uint32_t>(SPV_BINARY_TO_TEXT_OPTION_SHOW_BYTE_OFFSET));
+  constant("SPV_BINARY_TO_TEXT_OPTION_NO_HEADER", static_cast<uint32_t>(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER));
+  constant("SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES", static_cast<uint32_t>(SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES));
+
+  constant("SPV_TEXT_TO_BINARY_OPTION_NONE", static_cast<uint32_t>(SPV_TEXT_TO_BINARY_OPTION_NONE));
+  constant("SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS", static_cast<uint32_t>(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS));
+}

+ 57 - 0
ThirdParty/Glslang/External/spirv-tools/source/wasm/spirv-tools.d.ts

@@ -0,0 +1,57 @@
+// Copyright (c) 2020 The Khronos Group Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+declare interface SpirvTools {
+  as(input: string, env: number, options: number): Uint8Array;
+  dis(input: Uint8Array, env: number, options: number): string;
+
+  SPV_ENV_UNIVERSAL_1_0: number;
+  SPV_ENV_VULKAN_1_0: number;
+  SPV_ENV_UNIVERSAL_1_1: number;
+  SPV_ENV_OPENCL_2_1: number;
+  SPV_ENV_OPENCL_2_2: number;
+  SPV_ENV_OPENGL_4_0: number;
+  SPV_ENV_OPENGL_4_1: number;
+  SPV_ENV_OPENGL_4_2: number;
+  SPV_ENV_OPENGL_4_3: number;
+  SPV_ENV_OPENGL_4_5: number;
+  SPV_ENV_UNIVERSAL_1_2: number;
+  SPV_ENV_OPENCL_1_2: number;
+  SPV_ENV_OPENCL_EMBEDDED_1_2: number;
+  SPV_ENV_OPENCL_2_0: number;
+  SPV_ENV_OPENCL_EMBEDDED_2_0: number;
+  SPV_ENV_OPENCL_EMBEDDED_2_1: number;
+  SPV_ENV_OPENCL_EMBEDDED_2_2: number;
+  SPV_ENV_UNIVERSAL_1_3: number;
+  SPV_ENV_VULKAN_1_1: number;
+  SPV_ENV_WEBGPU_0: number;
+  SPV_ENV_UNIVERSAL_1_4: number;
+  SPV_ENV_VULKAN_1_1_SPIRV_1_4: number;
+  SPV_ENV_UNIVERSAL_1_5: number;
+  SPV_ENV_VULKAN_1_2: number;
+  SPV_ENV_UNIVERSAL_1_6: number;
+
+  SPV_TEXT_TO_BINARY_OPTION_NONE: number;
+  SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS: number;
+
+  SPV_BINARY_TO_TEXT_OPTION_NONE: number;
+  SPV_BINARY_TO_TEXT_OPTION_PRINT: number;
+  SPV_BINARY_TO_TEXT_OPTION_COLOR: number;
+  SPV_BINARY_TO_TEXT_OPTION_INDENT: number;
+  SPV_BINARY_TO_TEXT_OPTION_SHOW_BYTE_OFFSET: number;
+  SPV_BINARY_TO_TEXT_OPTION_NO_HEADER: number;
+  SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES: number;
+}
+
+export default function (): Promise<SpirvTools>;

+ 328 - 0
ThirdParty/Glslang/External/spirv-tools/test/fuzz/available_instructions_test.cpp

@@ -0,0 +1,328 @@
+// Copyright (c) 2021 Alastair F. Donaldson
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "source/fuzz/available_instructions.h"
+
+#include "gtest/gtest.h"
+#include "source/fuzz/fuzzer_util.h"
+#include "test/fuzz/fuzz_test_util.h"
+
+namespace spvtools {
+namespace fuzz {
+namespace {
+
+TEST(AvailableInstructionsTest, BasicTest) {
+  std::string shader = R"(
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %4 "main"
+               OpExecutionMode %4 OriginUpperLeft
+               OpSource ESSL 320
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeInt 32 1
+          %7 = OpTypePointer Function %6
+          %8 = OpTypeFloat 32
+          %9 = OpTypePointer Function %8
+         %10 = OpTypeFunction %6 %7 %9
+         %15 = OpTypeVector %8 2
+         %16 = OpTypePointer Private %15
+         %17 = OpVariable %16 Private
+         %18 = OpConstant %8 1
+         %19 = OpConstant %8 2
+         %20 = OpConstantComposite %15 %18 %19
+         %21 = OpTypeVector %8 4
+         %22 = OpTypePointer Private %21
+         %23 = OpVariable %22 Private
+         %24 = OpConstant %8 10
+         %25 = OpConstant %8 20
+         %26 = OpConstant %8 30
+         %27 = OpConstant %8 40
+         %28 = OpConstantComposite %21 %24 %25 %26 %27
+         %31 = OpTypeInt 32 0
+         %32 = OpConstant %31 0
+         %33 = OpTypePointer Private %8
+         %41 = OpTypeBool
+         %46 = OpConstant %6 1
+         %54 = OpConstant %6 10
+         %57 = OpConstant %31 3
+         %61 = OpConstant %6 0
+         %66 = OpConstant %6 3
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+         %55 = OpVariable %7 Function
+         %56 = OpVariable %9 Function
+         %65 = OpVariable %7 Function
+         %68 = OpVariable %7 Function
+               OpStore %17 %20
+               OpStore %23 %28
+               OpStore %55 %54
+         %58 = OpAccessChain %33 %23 %57
+         %59 = OpLoad %8 %58
+               OpStore %56 %59
+         %60 = OpFunctionCall %6 %13 %55 %56
+        %100 = OpCopyObject %21 %28
+         %62 = OpSGreaterThan %41 %60 %61
+               OpSelectionMerge %64 None
+               OpBranchConditional %62 %63 %67
+         %63 = OpLabel
+               OpStore %65 %66
+        %101 = OpCopyObject %21 %28
+               OpBranch %64
+         %67 = OpLabel
+               OpStore %68 %61
+               OpBranch %69
+         %69 = OpLabel
+               OpLoopMerge %71 %72 None
+               OpBranch %73
+         %73 = OpLabel
+         %74 = OpLoad %6 %68
+         %75 = OpSLessThan %41 %74 %54
+               OpBranchConditional %75 %70 %71
+         %70 = OpLabel
+         %76 = OpLoad %6 %65
+         %77 = OpIAdd %6 %76 %46
+               OpStore %65 %77
+               OpBranch %72
+         %72 = OpLabel
+         %78 = OpLoad %6 %68
+         %79 = OpIAdd %6 %78 %46
+               OpStore %68 %79
+               OpBranch %69
+         %71 = OpLabel
+        %102 = OpCopyObject %21 %28
+               OpBranch %64
+         %64 = OpLabel
+               OpReturn
+               OpFunctionEnd
+         %13 = OpFunction %6 None %10
+         %11 = OpFunctionParameter %7
+         %12 = OpFunctionParameter %9
+         %14 = OpLabel
+         %29 = OpVariable %7 Function
+         %30 = OpLoad %6 %11
+         %34 = OpAccessChain %33 %17 %32
+         %35 = OpLoad %8 %34
+         %36 = OpConvertFToS %6 %35
+         %37 = OpIAdd %6 %30 %36
+               OpStore %29 %37
+         %38 = OpLoad %6 %11
+         %39 = OpLoad %8 %12
+         %40 = OpConvertFToS %6 %39
+         %42 = OpSLessThan %41 %38 %40
+        %103 = OpCopyObject %21 %28
+               OpSelectionMerge %44 None
+               OpBranchConditional %42 %43 %48
+         %43 = OpLabel
+         %45 = OpLoad %6 %29
+         %47 = OpIAdd %6 %45 %46
+               OpStore %29 %47
+               OpBranch %44
+         %48 = OpLabel
+         %49 = OpLoad %6 %29
+         %50 = OpISub %6 %49 %46
+               OpStore %29 %50
+               OpBranch %44
+         %44 = OpLabel
+         %51 = OpLoad %6 %29
+               OpReturnValue %51
+               OpFunctionEnd
+  )";
+
+  const auto env = SPV_ENV_UNIVERSAL_1_3;
+  const auto consumer = nullptr;
+  const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
+  spvtools::ValidatorOptions validator_options;
+  ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
+                                               kConsoleMessageConsumer));
+
+  opt::Instruction* i1 = context->get_def_use_mgr()->GetDef(55);
+  opt::Instruction* i2 = context->get_def_use_mgr()->GetDef(101);
+  opt::Instruction* i3 = &*context->cfg()->block(67)->begin();
+  opt::Instruction* i4 = context->get_def_use_mgr()->GetDef(74);
+  opt::Instruction* i5 = context->get_def_use_mgr()->GetDef(102);
+  opt::Instruction* i6 = context->get_def_use_mgr()->GetDef(30);
+  opt::Instruction* i7 = context->get_def_use_mgr()->GetDef(47);
+  opt::Instruction* i8 = context->get_def_use_mgr()->GetDef(50);
+  opt::Instruction* i9 = context->get_def_use_mgr()->GetDef(51);
+
+  {
+    AvailableInstructions no_instructions(
+        context.get(),
+        [](opt::IRContext*, opt::Instruction*) -> bool { return false; });
+    for (auto i : {i1, i2, i3, i4, i5, i6, i7, i8, i9}) {
+      auto available = no_instructions.GetAvailableBeforeInstruction(i);
+      ASSERT_EQ(0, available.size());
+      ASSERT_TRUE(available.empty());
+    }
+  }
+  {
+    AvailableInstructions all_instructions(
+        context.get(),
+        [](opt::IRContext*, opt::Instruction*) -> bool { return true; });
+    {
+      auto available = all_instructions.GetAvailableBeforeInstruction(i1);
+      ASSERT_FALSE(available.empty());
+      ASSERT_EQ(30, available.size());
+      ASSERT_EQ(SpvOpTypeVoid, available[0]->opcode());
+      ASSERT_EQ(SpvOpVariable, available[15]->opcode());
+    }
+    {
+      auto available = all_instructions.GetAvailableBeforeInstruction(i2);
+      ASSERT_FALSE(available.empty());
+      ASSERT_EQ(46, available.size());
+      ASSERT_EQ(SpvOpTypeVoid, available[0]->opcode());
+      ASSERT_EQ(SpvOpTypePointer, available[3]->opcode());
+      ASSERT_EQ(SpvOpVariable, available[15]->opcode());
+      ASSERT_EQ(SpvOpFunctionCall, available[40]->opcode());
+      ASSERT_EQ(SpvOpStore, available[45]->opcode());
+    }
+    {
+      auto available = all_instructions.GetAvailableBeforeInstruction(i3);
+      ASSERT_FALSE(available.empty());
+      ASSERT_EQ(45, available.size());
+      ASSERT_EQ(SpvOpTypeVoid, available[0]->opcode());
+      ASSERT_EQ(SpvOpTypePointer, available[3]->opcode());
+      ASSERT_EQ(SpvOpVariable, available[15]->opcode());
+      ASSERT_EQ(SpvOpFunctionCall, available[40]->opcode());
+      ASSERT_EQ(SpvOpBranchConditional, available[44]->opcode());
+    }
+    {
+      auto available = all_instructions.GetAvailableBeforeInstruction(i6);
+      ASSERT_FALSE(available.empty());
+      ASSERT_EQ(33, available.size());
+      ASSERT_EQ(SpvOpTypeVoid, available[0]->opcode());
+      ASSERT_EQ(SpvOpTypeFloat, available[4]->opcode());
+      ASSERT_EQ(SpvOpTypePointer, available[8]->opcode());
+      ASSERT_EQ(SpvOpConstantComposite, available[12]->opcode());
+      ASSERT_EQ(SpvOpConstant, available[16]->opcode());
+      ASSERT_EQ(SpvOpFunctionParameter, available[30]->opcode());
+      ASSERT_EQ(SpvOpFunctionParameter, available[31]->opcode());
+      ASSERT_EQ(SpvOpVariable, available[32]->opcode());
+    }
+  }
+  {
+    AvailableInstructions vector_instructions(
+        context.get(),
+        [](opt::IRContext* ir_context, opt::Instruction* inst) -> bool {
+          return inst->type_id() != 0 && ir_context->get_type_mgr()
+                                                 ->GetType(inst->type_id())
+                                                 ->AsVector() != nullptr;
+        });
+    {
+      auto available = vector_instructions.GetAvailableBeforeInstruction(i4);
+      ASSERT_FALSE(available.empty());
+      ASSERT_EQ(3, available.size());
+      ASSERT_EQ(SpvOpConstantComposite, available[0]->opcode());
+      ASSERT_EQ(SpvOpConstantComposite, available[1]->opcode());
+      ASSERT_EQ(SpvOpCopyObject, available[2]->opcode());
+    }
+    {
+      auto available = vector_instructions.GetAvailableBeforeInstruction(i5);
+      ASSERT_FALSE(available.empty());
+      ASSERT_EQ(3, available.size());
+      ASSERT_EQ(SpvOpConstantComposite, available[0]->opcode());
+      ASSERT_EQ(SpvOpConstantComposite, available[1]->opcode());
+      ASSERT_EQ(SpvOpCopyObject, available[2]->opcode());
+    }
+    {
+      auto available = vector_instructions.GetAvailableBeforeInstruction(i6);
+      ASSERT_FALSE(available.empty());
+      ASSERT_EQ(2, available.size());
+      ASSERT_EQ(SpvOpConstantComposite, available[0]->opcode());
+      ASSERT_EQ(SpvOpConstantComposite, available[1]->opcode());
+    }
+  }
+  {
+    AvailableInstructions integer_add_instructions(
+        context.get(), [](opt::IRContext*, opt::Instruction* inst) -> bool {
+          return inst->opcode() == SpvOpIAdd;
+        });
+    {
+      auto available =
+          integer_add_instructions.GetAvailableBeforeInstruction(i7);
+      ASSERT_FALSE(available.empty());
+      ASSERT_EQ(1, available.size());
+      ASSERT_EQ(SpvOpIAdd, available[0]->opcode());
+    }
+    {
+      auto available =
+          integer_add_instructions.GetAvailableBeforeInstruction(i8);
+      ASSERT_FALSE(available.empty());
+      ASSERT_EQ(1, available.size());
+      ASSERT_EQ(SpvOpIAdd, available[0]->opcode());
+    }
+    {
+      auto available =
+          integer_add_instructions.GetAvailableBeforeInstruction(i9);
+      ASSERT_FALSE(available.empty());
+      ASSERT_EQ(1, available.size());
+      ASSERT_EQ(SpvOpIAdd, available[0]->opcode());
+    }
+  }
+}
+
+TEST(AvailableInstructionsTest, UnreachableBlock) {
+  std::string shader = R"(
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %4 "main"
+               OpExecutionMode %4 OriginUpperLeft
+               OpSource ESSL 320
+               OpName %4 "main"
+               OpName %8 "x"
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeInt 32 1
+          %7 = OpTypePointer Function %6
+          %9 = OpConstant %6 2
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+          %8 = OpVariable %7 Function
+               OpStore %8 %9
+         %12 = OpLoad %6 %8
+               OpReturn
+         %10 = OpLabel
+         %11 = OpLoad %6 %8
+               OpReturn
+               OpFunctionEnd
+  )";
+
+  const auto env = SPV_ENV_UNIVERSAL_1_3;
+  const auto consumer = nullptr;
+  const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
+  spvtools::ValidatorOptions validator_options;
+  ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
+                                               kConsoleMessageConsumer));
+
+  AvailableInstructions all_instructions(
+      context.get(),
+      [](opt::IRContext*, opt::Instruction*) -> bool { return true; });
+  ASSERT_EQ(7, all_instructions
+                   .GetAvailableBeforeInstruction(
+                       context->get_def_use_mgr()->GetDef(12))
+                   .size());
+
+#ifndef NDEBUG
+  ASSERT_DEATH(all_instructions.GetAvailableBeforeInstruction(
+                   context->get_def_use_mgr()->GetDef(11)),
+               "Availability can only be queried for reachable instructions.");
+#endif
+}
+
+}  // namespace
+}  // namespace fuzz
+}  // namespace spvtools

+ 1807 - 0
ThirdParty/Glslang/External/spirv-tools/test/fuzz/fuzzerutil_test.cpp

@@ -0,0 +1,1807 @@
+// Copyright (c) 2021 Shiyu Liu
+//
+// 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 "gtest/gtest.h"
+#include "source/fuzz/fuzzer_util.h"
+#include "test/fuzz/fuzz_test_util.h"
+
+namespace spvtools {
+namespace fuzz {
+namespace {
+
+TEST(FuzzerUtilMaybeFindBlockTest, BasicTest) {
+  std::string shader = R"(
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %4 "main"
+               OpExecutionMode %4 OriginUpperLeft
+               OpSource ESSL 310
+               OpDecorate %8 RelaxedPrecision
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeInt 32 1
+          %7 = OpTypePointer Function %6
+          %9 = OpConstant %6 1
+         %10 = OpConstant %6 2
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+          %8 = OpVariable %7 Function
+               OpBranch %11
+         %11 = OpLabel
+               OpStore %8 %9
+               OpBranch %12
+         %12 = OpLabel
+               OpStore %8 %10
+               OpReturn
+               OpFunctionEnd
+  )";
+
+  const auto env = SPV_ENV_UNIVERSAL_1_4;
+  const auto consumer = nullptr;
+  const std::unique_ptr<opt::IRContext> context =
+      BuildModule(env, consumer, shader, kFuzzAssembleOption);
+  spvtools::ValidatorOptions validator_options;
+  ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
+                                               kConsoleMessageConsumer));
+
+  // Only blocks with id 11 and 12 can be found.
+  // Should return nullptr when id is not a label or id was not found.
+  uint32_t block_id1 = 11;
+  uint32_t block_id2 = 12;
+  uint32_t block_id3 = 13;
+  uint32_t block_id4 = 8;
+
+  opt::IRContext* ir_context = context.get();
+  // Block with id 11 should be found.
+  ASSERT_TRUE(fuzzerutil::MaybeFindBlock(ir_context, block_id1) != nullptr);
+  // Block with id 12 should be found.
+  ASSERT_TRUE(fuzzerutil::MaybeFindBlock(ir_context, block_id2) != nullptr);
+  // Block with id 13 cannot be found.
+  ASSERT_FALSE(fuzzerutil::MaybeFindBlock(ir_context, block_id3) != nullptr);
+  // Block with id 8 exists but don't not of type OpLabel.
+  ASSERT_FALSE(fuzzerutil::MaybeFindBlock(ir_context, block_id4) != nullptr);
+}
+
+TEST(FuzzerutilTest, FuzzerUtilMaybeGetBoolConstantTest) {
+  std::string shader = R"(
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %4 "main" %36
+               OpExecutionMode %4 OriginUpperLeft
+               OpSource ESSL 310
+               OpName %4 "main"
+               OpName %8 "b1"
+               OpName %10 "b2"
+               OpName %12 "b3"
+               OpName %13 "b4"
+               OpName %16 "f1"
+               OpName %18 "f2"
+               OpName %20 "cf1"
+               OpName %22 "cf2"
+               OpName %26 "i1"
+               OpName %28 "i2"
+               OpName %30 "ci1"
+               OpName %32 "ci2"
+               OpName %36 "value"
+               OpDecorate %26 RelaxedPrecision
+               OpDecorate %28 RelaxedPrecision
+               OpDecorate %30 RelaxedPrecision
+               OpDecorate %32 RelaxedPrecision
+               OpDecorate %36 Location 0
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeBool
+          %7 = OpTypePointer Function %6
+          %9 = OpConstantTrue %6
+         %11 = OpConstantFalse %6
+         %14 = OpTypeFloat 32
+         %15 = OpTypePointer Function %14
+         %17 = OpConstant %14 1.23000002
+         %19 = OpConstant %14 1.11000001
+         %21 = OpConstant %14 2
+         %23 = OpConstant %14 3.29999995
+         %24 = OpTypeInt 32 1
+         %25 = OpTypePointer Function %24
+         %27 = OpConstant %24 1
+         %29 = OpConstant %24 100
+         %31 = OpConstant %24 123
+         %33 = OpConstant %24 1111
+         %35 = OpTypePointer Input %14
+         %36 = OpVariable %35 Input
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+          %8 = OpVariable %7 Function
+         %10 = OpVariable %7 Function
+         %12 = OpVariable %7 Function
+         %13 = OpVariable %7 Function
+         %16 = OpVariable %15 Function
+         %18 = OpVariable %15 Function
+         %20 = OpVariable %15 Function
+         %22 = OpVariable %15 Function
+         %26 = OpVariable %25 Function
+         %28 = OpVariable %25 Function
+         %30 = OpVariable %25 Function
+         %32 = OpVariable %25 Function
+               OpStore %8 %9
+               OpStore %10 %11
+               OpStore %12 %9
+               OpStore %13 %11
+               OpStore %16 %17
+               OpStore %18 %19
+               OpStore %20 %21
+               OpStore %22 %23
+               OpStore %26 %27
+               OpStore %28 %29
+               OpStore %30 %31
+               OpStore %32 %33
+               OpReturn
+               OpFunctionEnd
+  )";
+
+  const auto env = SPV_ENV_UNIVERSAL_1_4;
+  const auto consumer = nullptr;
+  const std::unique_ptr<opt::IRContext> context =
+      BuildModule(env, consumer, shader, kFuzzAssembleOption);
+  spvtools::ValidatorOptions validator_options;
+  ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
+                                               kConsoleMessageConsumer));
+  TransformationContext transformation_context(
+      MakeUnique<FactManager>(context.get()), validator_options);
+
+  opt::IRContext* ir_context = context.get();
+  // A bool constant with value false exists and the id is 11.
+  ASSERT_EQ(11, fuzzerutil::MaybeGetBoolConstant(
+                    ir_context, transformation_context, false, false));
+  // A bool constant with value true exists and the id is 9.
+  ASSERT_EQ(9, fuzzerutil::MaybeGetBoolConstant(
+                   ir_context, transformation_context, true, false));
+}
+
+TEST(FuzzerutilTest, FuzzerUtilMaybeGetBoolTypeTest) {
+  std::string shader = R"(
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %4 "main" %92 %52 %53
+               OpExecutionMode %4 OriginUpperLeft
+               OpSource ESSL 310
+               OpDecorate %92 BuiltIn FragCoord
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeInt 32 1
+          %7 = OpTypeFloat 32
+          %8 = OpTypeStruct %6 %7
+          %9 = OpTypePointer Function %8
+         %10 = OpTypeFunction %6 %9
+         %14 = OpConstant %6 0
+         %15 = OpTypePointer Function %6
+         %51 = OpTypePointer Private %6
+         %21 = OpConstant %6 2
+         %23 = OpConstant %6 1
+         %24 = OpConstant %7 1
+         %25 = OpTypePointer Function %7
+         %50 = OpTypePointer Private %7
+         %34 = OpTypeBool
+         %35 = OpConstantFalse %34
+         %52 = OpVariable %50 Private
+         %53 = OpVariable %51 Private
+         %80 = OpConstantComposite %8 %21 %24
+         %90 = OpTypeVector %7 4
+         %91 = OpTypePointer Input %90
+         %92 = OpVariable %91 Input
+         %93 = OpConstantComposite %90 %24 %24 %24 %24
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+         %20 = OpVariable %9 Function
+         %27 = OpVariable %9 Function
+         %22 = OpAccessChain %15 %20 %14
+         %44 = OpCopyObject %9 %20
+         %26 = OpAccessChain %25 %20 %23
+         %29 = OpFunctionCall %6 %12 %27
+         %30 = OpAccessChain %15 %20 %14
+         %45 = OpCopyObject %15 %30
+         %81 = OpCopyObject %9 %27
+         %33 = OpAccessChain %15 %20 %14
+               OpSelectionMerge %37 None
+               OpBranchConditional %35 %36 %37
+         %36 = OpLabel
+         %38 = OpAccessChain %15 %20 %14
+         %40 = OpAccessChain %15 %20 %14
+         %43 = OpAccessChain %15 %20 %14
+         %82 = OpCopyObject %9 %27
+               OpBranch %37
+         %37 = OpLabel
+               OpReturn
+               OpFunctionEnd
+         %12 = OpFunction %6 None %10
+         %11 = OpFunctionParameter %9
+         %13 = OpLabel
+         %46 = OpCopyObject %9 %11
+         %16 = OpAccessChain %15 %11 %14
+         %95 = OpCopyObject %8 %80
+               OpReturnValue %21
+        %100 = OpLabel
+               OpUnreachable
+               OpFunctionEnd
+  )";
+
+  const auto env = SPV_ENV_UNIVERSAL_1_4;
+  const auto consumer = nullptr;
+  const std::unique_ptr<opt::IRContext> context =
+      BuildModule(env, consumer, shader, kFuzzAssembleOption);
+  spvtools::ValidatorOptions validator_options;
+  ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
+                                               kConsoleMessageConsumer));
+
+  opt::IRContext* ir_context = context.get();
+  // A bool type with result id of 34 exists.
+  ASSERT_TRUE(fuzzerutil::MaybeGetBoolType(ir_context));
+}
+
+TEST(FuzzerutilTest, FuzzerUtilMaybeGetCompositeConstantTest) {
+  std::string shader = R"(
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %4 "main" %54
+               OpExecutionMode %4 OriginUpperLeft
+               OpSource ESSL 310
+               OpName %4 "main"
+               OpName %8 "b1"
+               OpName %10 "b2"
+               OpName %12 "b3"
+               OpName %13 "b4"
+               OpName %16 "f1"
+               OpName %18 "f2"
+               OpName %22 "zc"
+               OpName %24 "i1"
+               OpName %28 "i2"
+               OpName %30 "i3"
+               OpName %32 "i4"
+               OpName %37 "f_arr"
+               OpName %47 "i_arr"
+               OpName %54 "value"
+               OpDecorate %22 RelaxedPrecision
+               OpDecorate %24 RelaxedPrecision
+               OpDecorate %28 RelaxedPrecision
+               OpDecorate %30 RelaxedPrecision
+               OpDecorate %32 RelaxedPrecision
+               OpDecorate %47 RelaxedPrecision
+               OpDecorate %54 Location 0
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeBool
+          %7 = OpTypePointer Function %6
+          %9 = OpConstantTrue %6
+         %11 = OpConstantFalse %6
+         %14 = OpTypeFloat 32
+         %15 = OpTypePointer Function %14
+         %17 = OpConstant %14 1.23000002
+         %19 = OpConstant %14 1.11000001
+         %20 = OpTypeInt 32 1
+         %21 = OpTypePointer Function %20
+         %23 = OpConstant %20 0
+         %25 = OpConstant %20 1
+         %26 = OpTypeInt 32 0
+         %27 = OpTypePointer Function %26
+         %29 = OpConstant %26 100
+         %31 = OpConstant %20 -1
+         %33 = OpConstant %20 -99
+         %34 = OpConstant %26 5
+         %35 = OpTypeArray %14 %34
+         %36 = OpTypePointer Function %35
+         %38 = OpConstant %14 5.5
+         %39 = OpConstant %14 4.4000001
+         %40 = OpConstant %14 3.29999995
+         %41 = OpConstant %14 2.20000005
+         %42 = OpConstant %14 1.10000002
+         %43 = OpConstantComposite %35 %38 %39 %40 %41 %42
+         %44 = OpConstant %26 3
+         %45 = OpTypeArray %20 %44
+         %46 = OpTypePointer Function %45
+         %48 = OpConstant %20 3
+         %49 = OpConstant %20 7
+         %50 = OpConstant %20 9
+         %51 = OpConstantComposite %45 %48 %49 %50
+         %53 = OpTypePointer Input %14
+         %54 = OpVariable %53 Input
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+          %8 = OpVariable %7 Function
+         %10 = OpVariable %7 Function
+         %12 = OpVariable %7 Function
+         %13 = OpVariable %7 Function
+         %16 = OpVariable %15 Function
+         %18 = OpVariable %15 Function
+         %22 = OpVariable %21 Function
+         %24 = OpVariable %21 Function
+         %28 = OpVariable %27 Function
+         %30 = OpVariable %21 Function
+         %32 = OpVariable %21 Function
+         %37 = OpVariable %36 Function
+         %47 = OpVariable %46 Function
+               OpStore %8 %9
+               OpStore %10 %11
+               OpStore %12 %9
+               OpStore %13 %11
+               OpStore %16 %17
+               OpStore %18 %19
+               OpStore %22 %23
+               OpStore %24 %25
+               OpStore %28 %29
+               OpStore %30 %31
+               OpStore %32 %33
+               OpStore %37 %43
+               OpStore %47 %51
+               OpReturn
+               OpFunctionEnd
+  )";
+
+  const auto env = SPV_ENV_UNIVERSAL_1_4;
+  const auto consumer = nullptr;
+  const std::unique_ptr<opt::IRContext> context =
+      BuildModule(env, consumer, shader, kFuzzAssembleOption);
+  spvtools::ValidatorOptions validator_options;
+  ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
+                                               kConsoleMessageConsumer));
+  TransformationContext transformation_context(
+      MakeUnique<FactManager>(context.get()), validator_options);
+
+  opt::IRContext* ir_context = context.get();
+
+  //      %43 = OpConstantComposite %35 %38 %39 %40 %41 %42
+  //    %51 = OpConstantComposite %45 %48 %49 %50
+  // This should pass as a float array with 5 elements exist and its id is 43.
+  ASSERT_EQ(43, fuzzerutil::MaybeGetCompositeConstant(
+                    ir_context, transformation_context, {38, 39, 40, 41, 42},
+                    35, false));
+  // This should pass as an int array with 3 elements exist and its id is 51.
+  ASSERT_EQ(51,
+            fuzzerutil::MaybeGetCompositeConstant(
+                ir_context, transformation_context, {48, 49, 50}, 45, false));
+  // An int array with 2 elements does not exist.
+  ASSERT_EQ(0, fuzzerutil::MaybeGetCompositeConstant(
+                   ir_context, transformation_context, {48, 49}, 45, false));
+}
+
+TEST(FuzzerutilTest, FuzzerUtilMaybeGetFloatConstantTest) {
+  std::string shader = R"(
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %4 "main" %36
+               OpExecutionMode %4 OriginUpperLeft
+               OpSource ESSL 310
+               OpName %4 "main"
+               OpName %8 "b1"
+               OpName %10 "b2"
+               OpName %12 "b3"
+               OpName %13 "b4"
+               OpName %16 "f1"
+               OpName %18 "f2"
+               OpName %20 "cf1"
+               OpName %22 "cf2"
+               OpName %26 "i1"
+               OpName %28 "i2"
+               OpName %30 "ci1"
+               OpName %32 "ci2"
+               OpName %36 "value"
+               OpDecorate %26 RelaxedPrecision
+               OpDecorate %28 RelaxedPrecision
+               OpDecorate %30 RelaxedPrecision
+               OpDecorate %32 RelaxedPrecision
+               OpDecorate %36 Location 0
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeBool
+          %7 = OpTypePointer Function %6
+          %9 = OpConstantTrue %6
+         %11 = OpConstantFalse %6
+         %14 = OpTypeFloat 32
+         %15 = OpTypePointer Function %14
+         %17 = OpConstant %14 1.23000002
+         %19 = OpConstant %14 1.11000001
+         %21 = OpConstant %14 2
+         %23 = OpConstant %14 3.29999995
+         %24 = OpTypeInt 32 1
+         %25 = OpTypePointer Function %24
+         %27 = OpConstant %24 1
+         %29 = OpConstant %24 100
+         %31 = OpConstant %24 123
+         %33 = OpConstant %24 1111
+         %35 = OpTypePointer Input %14
+         %36 = OpVariable %35 Input
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+          %8 = OpVariable %7 Function
+         %10 = OpVariable %7 Function
+         %12 = OpVariable %7 Function
+         %13 = OpVariable %7 Function
+         %16 = OpVariable %15 Function
+         %18 = OpVariable %15 Function
+         %20 = OpVariable %15 Function
+         %22 = OpVariable %15 Function
+         %26 = OpVariable %25 Function
+         %28 = OpVariable %25 Function
+         %30 = OpVariable %25 Function
+         %32 = OpVariable %25 Function
+               OpStore %8 %9
+               OpStore %10 %11
+               OpStore %12 %9
+               OpStore %13 %11
+               OpStore %16 %17
+               OpStore %18 %19
+               OpStore %20 %21
+               OpStore %22 %23
+               OpStore %26 %27
+               OpStore %28 %29
+               OpStore %30 %31
+               OpStore %32 %33
+               OpReturn
+               OpFunctionEnd
+  )";
+
+  const auto env = SPV_ENV_UNIVERSAL_1_4;
+  const auto consumer = nullptr;
+  const std::unique_ptr<opt::IRContext> context =
+      BuildModule(env, consumer, shader, kFuzzAssembleOption);
+  spvtools::ValidatorOptions validator_options;
+  ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
+                                               kConsoleMessageConsumer));
+  TransformationContext transformation_context(
+      MakeUnique<FactManager>(context.get()), validator_options);
+
+  opt::IRContext* ir_context = context.get();
+
+  uint32_t word1 = fuzzerutil::FloatToWord(2);
+  uint32_t word2 = fuzzerutil::FloatToWord(1.23f);
+
+  // A 32 bit float constant of value 2 exists and its id is 21.
+  ASSERT_EQ(21, fuzzerutil::MaybeGetFloatConstant(
+                    ir_context, transformation_context,
+                    std::vector<uint32_t>{word1}, 32, false));
+  // A 32 bit float constant of value 1.23 exists and its id is 17.
+  ASSERT_EQ(17, fuzzerutil::MaybeGetFloatConstant(
+                    ir_context, transformation_context,
+                    std::vector<uint32_t>{word2}, 32, false));
+}
+
+TEST(FuzzerutilTest, FuzzerUtilMaybeGetFloatTypeTest) {
+  std::string shader = R"(
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %4 "main" %92 %52 %53
+               OpExecutionMode %4 OriginUpperLeft
+               OpSource ESSL 310
+               OpDecorate %92 BuiltIn FragCoord
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeInt 32 1
+          %7 = OpTypeFloat 32
+          %8 = OpTypeStruct %6 %7
+          %9 = OpTypePointer Function %8
+         %10 = OpTypeFunction %6 %9
+         %14 = OpConstant %6 0
+         %15 = OpTypePointer Function %6
+         %51 = OpTypePointer Private %6
+         %21 = OpConstant %6 2
+         %23 = OpConstant %6 1
+         %24 = OpConstant %7 1
+         %25 = OpTypePointer Function %7
+         %50 = OpTypePointer Private %7
+         %34 = OpTypeBool
+         %35 = OpConstantFalse %34
+         %52 = OpVariable %50 Private
+         %53 = OpVariable %51 Private
+         %80 = OpConstantComposite %8 %21 %24
+         %90 = OpTypeVector %7 4
+         %91 = OpTypePointer Input %90
+         %92 = OpVariable %91 Input
+         %93 = OpConstantComposite %90 %24 %24 %24 %24
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+         %20 = OpVariable %9 Function
+         %27 = OpVariable %9 Function
+         %22 = OpAccessChain %15 %20 %14
+         %44 = OpCopyObject %9 %20
+         %26 = OpAccessChain %25 %20 %23
+         %29 = OpFunctionCall %6 %12 %27
+         %30 = OpAccessChain %15 %20 %14
+         %45 = OpCopyObject %15 %30
+         %81 = OpCopyObject %9 %27
+         %33 = OpAccessChain %15 %20 %14
+               OpSelectionMerge %37 None
+               OpBranchConditional %35 %36 %37
+         %36 = OpLabel
+         %38 = OpAccessChain %15 %20 %14
+         %40 = OpAccessChain %15 %20 %14
+         %43 = OpAccessChain %15 %20 %14
+         %82 = OpCopyObject %9 %27
+               OpBranch %37
+         %37 = OpLabel
+               OpReturn
+               OpFunctionEnd
+         %12 = OpFunction %6 None %10
+         %11 = OpFunctionParameter %9
+         %13 = OpLabel
+         %46 = OpCopyObject %9 %11
+         %16 = OpAccessChain %15 %11 %14
+         %95 = OpCopyObject %8 %80
+               OpReturnValue %21
+        %100 = OpLabel
+               OpUnreachable
+               OpFunctionEnd
+  )";
+
+  const auto env = SPV_ENV_UNIVERSAL_1_4;
+  const auto consumer = nullptr;
+  const std::unique_ptr<opt::IRContext> context =
+      BuildModule(env, consumer, shader, kFuzzAssembleOption);
+  spvtools::ValidatorOptions validator_options;
+  ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
+                                               kConsoleMessageConsumer));
+
+  opt::IRContext* ir_context = context.get();
+  // A float type with width = 32 and result id of 7 exists.
+  ASSERT_EQ(7, fuzzerutil::MaybeGetFloatType(ir_context, 32));
+
+  // A float int type with width = 32 exists, but the id should be 7.
+  ASSERT_NE(5, fuzzerutil::MaybeGetFloatType(ir_context, 32));
+
+  // A float type with width 30 does not exist.
+  ASSERT_EQ(0, fuzzerutil::MaybeGetFloatType(ir_context, 30));
+}
+
+TEST(FuzzerutilTest, FuzzerUtilMaybeGetIntegerConstantFromValueAndTypeTest) {
+  std::string shader = R"(
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %4 "main" %36
+               OpExecutionMode %4 OriginUpperLeft
+               OpSource ESSL 310
+               OpName %4 "main"
+               OpName %8 "b1"
+               OpName %10 "b2"
+               OpName %12 "b3"
+               OpName %13 "b4"
+               OpName %16 "f1"
+               OpName %18 "f2"
+               OpName %22 "zc"
+               OpName %24 "i1"
+               OpName %28 "i2"
+               OpName %30 "i3"
+               OpName %32 "i4"
+               OpName %36 "value"
+               OpDecorate %22 RelaxedPrecision
+               OpDecorate %24 RelaxedPrecision
+               OpDecorate %28 RelaxedPrecision
+               OpDecorate %30 RelaxedPrecision
+               OpDecorate %32 RelaxedPrecision
+               OpDecorate %36 Location 0
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeBool
+          %7 = OpTypePointer Function %6
+          %9 = OpConstantTrue %6
+         %11 = OpConstantFalse %6
+         %14 = OpTypeFloat 32
+         %15 = OpTypePointer Function %14
+         %17 = OpConstant %14 1.23000002
+         %19 = OpConstant %14 1.11000001
+         %20 = OpTypeInt 32 1
+         %21 = OpTypePointer Function %20
+         %23 = OpConstant %20 0
+         %25 = OpConstant %20 1
+         %26 = OpTypeInt 32 0
+         %27 = OpTypePointer Function %26
+         %29 = OpConstant %26 100
+         %31 = OpConstant %20 -1
+         %33 = OpConstant %20 -99
+         %35 = OpTypePointer Input %14
+         %36 = OpVariable %35 Input
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+          %8 = OpVariable %7 Function
+         %10 = OpVariable %7 Function
+         %12 = OpVariable %7 Function
+         %13 = OpVariable %7 Function
+         %16 = OpVariable %15 Function
+         %18 = OpVariable %15 Function
+         %22 = OpVariable %21 Function
+         %24 = OpVariable %21 Function
+         %28 = OpVariable %27 Function
+         %30 = OpVariable %21 Function
+         %32 = OpVariable %21 Function
+               OpStore %8 %9
+               OpStore %10 %11
+               OpStore %12 %9
+               OpStore %13 %11
+               OpStore %16 %17
+               OpStore %18 %19
+               OpStore %22 %23
+               OpStore %24 %25
+               OpStore %28 %29
+               OpStore %30 %31
+               OpStore %32 %33
+               OpReturn
+               OpFunctionEnd
+  )";
+
+  const auto env = SPV_ENV_UNIVERSAL_1_4;
+  const auto consumer = nullptr;
+  const std::unique_ptr<opt::IRContext> context =
+      BuildModule(env, consumer, shader, kFuzzAssembleOption);
+  spvtools::ValidatorOptions validator_options;
+  ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
+                                               kConsoleMessageConsumer));
+
+  opt::IRContext* ir_context = context.get();
+
+  // A 32 bit signed int constant (with int type id 20) with value 1 exists and
+  // the id is 25.
+  ASSERT_EQ(25, fuzzerutil::MaybeGetIntegerConstantFromValueAndType(ir_context,
+                                                                    1, 20));
+  // A 32 bit unsigned int constant (with int type id 0) with value 100 exists
+  // and the id is 29.
+  ASSERT_EQ(29, fuzzerutil::MaybeGetIntegerConstantFromValueAndType(ir_context,
+                                                                    100, 26));
+  // A 32 bit unsigned int constant with value 50 does not exist.
+  ASSERT_EQ(0, fuzzerutil::MaybeGetIntegerConstantFromValueAndType(ir_context,
+                                                                   50, 26));
+}
+
+TEST(FuzzerutilTest, FuzzerUtilMaybeGetIntegerConstantTest) {
+  std::string shader = R"(
+OpCapability Shader
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %4 "main" %36
+               OpExecutionMode %4 OriginUpperLeft
+               OpSource ESSL 310
+               OpName %4 "main"
+               OpName %8 "b1"
+               OpName %10 "b2"
+               OpName %12 "b3"
+               OpName %13 "b4"
+               OpName %16 "f1"
+               OpName %18 "f2"
+               OpName %22 "zc"
+               OpName %24 "i1"
+               OpName %28 "i2"
+               OpName %30 "i3"
+               OpName %32 "i4"
+               OpName %36 "value"
+               OpDecorate %22 RelaxedPrecision
+               OpDecorate %24 RelaxedPrecision
+               OpDecorate %28 RelaxedPrecision
+               OpDecorate %30 RelaxedPrecision
+               OpDecorate %32 RelaxedPrecision
+               OpDecorate %36 Location 0
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeBool
+          %7 = OpTypePointer Function %6
+          %9 = OpConstantTrue %6
+         %11 = OpConstantFalse %6
+         %14 = OpTypeFloat 32
+         %15 = OpTypePointer Function %14
+         %17 = OpConstant %14 1.23000002
+         %19 = OpConstant %14 1.11000001
+         %20 = OpTypeInt 32 1
+         %21 = OpTypePointer Function %20
+         %23 = OpConstant %20 0
+         %25 = OpConstant %20 1
+         %26 = OpTypeInt 32 0
+         %27 = OpTypePointer Function %26
+         %29 = OpConstant %26 100
+         %31 = OpConstant %20 -1
+         %33 = OpConstant %20 -99
+         %35 = OpTypePointer Input %14
+         %36 = OpVariable %35 Input
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+          %8 = OpVariable %7 Function
+         %10 = OpVariable %7 Function
+         %12 = OpVariable %7 Function
+         %13 = OpVariable %7 Function
+         %16 = OpVariable %15 Function
+         %18 = OpVariable %15 Function
+         %22 = OpVariable %21 Function
+         %24 = OpVariable %21 Function
+         %28 = OpVariable %27 Function
+         %30 = OpVariable %21 Function
+         %32 = OpVariable %21 Function
+               OpStore %8 %9
+               OpStore %10 %11
+               OpStore %12 %9
+               OpStore %13 %11
+               OpStore %16 %17
+               OpStore %18 %19
+               OpStore %22 %23
+               OpStore %24 %25
+               OpStore %28 %29
+               OpStore %30 %31
+               OpStore %32 %33
+               OpReturn
+               OpFunctionEnd
+  )";
+
+  const auto env = SPV_ENV_UNIVERSAL_1_4;
+  const auto consumer = nullptr;
+  const std::unique_ptr<opt::IRContext> context =
+      BuildModule(env, consumer, shader, kFuzzAssembleOption);
+  spvtools::ValidatorOptions validator_options;
+  ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
+                                               kConsoleMessageConsumer));
+  TransformationContext transformation_context(
+      MakeUnique<FactManager>(context.get()), validator_options);
+
+  opt::IRContext* ir_context = context.get();
+
+  // A 32 bit unsigned int constant with value 1 exists and the id is 25.
+  ASSERT_EQ(25, fuzzerutil::MaybeGetIntegerConstant(
+                    ir_context, transformation_context,
+                    std::vector<uint32_t>{1}, 32, true, false));
+  // A 32 bit unsigned int constant with value 100 exists and the id is 29.
+  ASSERT_EQ(29, fuzzerutil::MaybeGetIntegerConstant(
+                    ir_context, transformation_context,
+                    std::vector<uint32_t>{100}, 32, false, false));
+  // A 32 bit signed int constant with value 99 doesn't not exist and should
+  // return 0.
+  ASSERT_EQ(0, fuzzerutil::MaybeGetIntegerConstant(
+                   ir_context, transformation_context,
+                   std::vector<uint32_t>{99}, 32, true, false));
+}
+
+TEST(FuzzerutilTest, FuzzerUtilMaybeGetIntegerTypeTest) {
+  std::string shader = R"(
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %4 "main" %92 %52 %53
+               OpExecutionMode %4 OriginUpperLeft
+               OpSource ESSL 310
+               OpDecorate %92 BuiltIn FragCoord
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeInt 32 1
+          %7 = OpTypeFloat 32
+          %8 = OpTypeStruct %6 %7
+          %9 = OpTypePointer Function %8
+         %10 = OpTypeFunction %6 %9
+         %14 = OpConstant %6 0
+         %15 = OpTypePointer Function %6
+         %51 = OpTypePointer Private %6
+         %21 = OpConstant %6 2
+         %23 = OpConstant %6 1
+         %24 = OpConstant %7 1
+         %25 = OpTypePointer Function %7
+         %50 = OpTypePointer Private %7
+         %34 = OpTypeBool
+         %35 = OpConstantFalse %34
+         %52 = OpVariable %50 Private
+         %53 = OpVariable %51 Private
+         %80 = OpConstantComposite %8 %21 %24
+         %90 = OpTypeVector %7 4
+         %91 = OpTypePointer Input %90
+         %92 = OpVariable %91 Input
+         %93 = OpConstantComposite %90 %24 %24 %24 %24
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+         %20 = OpVariable %9 Function
+         %27 = OpVariable %9 Function
+         %22 = OpAccessChain %15 %20 %14
+         %44 = OpCopyObject %9 %20
+         %26 = OpAccessChain %25 %20 %23
+         %29 = OpFunctionCall %6 %12 %27
+         %30 = OpAccessChain %15 %20 %14
+         %45 = OpCopyObject %15 %30
+         %81 = OpCopyObject %9 %27
+         %33 = OpAccessChain %15 %20 %14
+               OpSelectionMerge %37 None
+               OpBranchConditional %35 %36 %37
+         %36 = OpLabel
+         %38 = OpAccessChain %15 %20 %14
+         %40 = OpAccessChain %15 %20 %14
+         %43 = OpAccessChain %15 %20 %14
+         %82 = OpCopyObject %9 %27
+               OpBranch %37
+         %37 = OpLabel
+               OpReturn
+               OpFunctionEnd
+         %12 = OpFunction %6 None %10
+         %11 = OpFunctionParameter %9
+         %13 = OpLabel
+         %46 = OpCopyObject %9 %11
+         %16 = OpAccessChain %15 %11 %14
+         %95 = OpCopyObject %8 %80
+               OpReturnValue %21
+        %100 = OpLabel
+               OpUnreachable
+               OpFunctionEnd
+  )";
+
+  const auto env = SPV_ENV_UNIVERSAL_1_4;
+  const auto consumer = nullptr;
+  const std::unique_ptr<opt::IRContext> context =
+      BuildModule(env, consumer, shader, kFuzzAssembleOption);
+  spvtools::ValidatorOptions validator_options;
+  ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
+                                               kConsoleMessageConsumer));
+
+  opt::IRContext* ir_context = context.get();
+
+  // A signed int type with width = 32 and result id of 6 exists.
+  ASSERT_EQ(6, fuzzerutil::MaybeGetIntegerType(ir_context, 32, true));
+
+  // A signed int type with width = 32 exists, but the id should be 6.
+  ASSERT_FALSE(fuzzerutil::MaybeGetIntegerType(ir_context, 32, true) == 5);
+
+  // A int type with width = 32 and result id of 6 exists, but it should be a
+  // signed int.
+  ASSERT_EQ(0, fuzzerutil::MaybeGetIntegerType(ir_context, 32, false));
+  // A signed int type with width 30 does not exist.
+  ASSERT_EQ(0, fuzzerutil::MaybeGetIntegerType(ir_context, 30, true));
+  // An unsigned int type with width 22 does not exist.
+  ASSERT_EQ(0, fuzzerutil::MaybeGetIntegerType(ir_context, 22, false));
+}
+
+TEST(FuzzerutilTest, FuzzerUtilMaybeGetPointerTypeTest) {
+  std::string shader = R"(
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %4 "main" %92 %52 %53
+               OpExecutionMode %4 OriginUpperLeft
+               OpSource ESSL 310
+               OpDecorate %92 BuiltIn FragCoord
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeInt 32 1
+          %7 = OpTypeFloat 32
+          %8 = OpTypeStruct %6 %7
+          %9 = OpTypePointer Function %8
+         %10 = OpTypeFunction %6 %9
+         %14 = OpConstant %6 0
+         %15 = OpTypePointer Function %6
+         %51 = OpTypePointer Private %6
+         %21 = OpConstant %6 2
+         %23 = OpConstant %6 1
+         %24 = OpConstant %7 1
+         %25 = OpTypePointer Function %7
+         %50 = OpTypePointer Private %7
+         %34 = OpTypeBool
+         %35 = OpConstantFalse %34
+         %52 = OpVariable %50 Private
+         %53 = OpVariable %51 Private
+         %80 = OpConstantComposite %8 %21 %24
+         %90 = OpTypeVector %7 4
+         %91 = OpTypePointer Input %90
+         %92 = OpVariable %91 Input
+         %93 = OpConstantComposite %90 %24 %24 %24 %24
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+         %20 = OpVariable %9 Function
+         %27 = OpVariable %9 Function
+         %22 = OpAccessChain %15 %20 %14
+         %44 = OpCopyObject %9 %20
+         %26 = OpAccessChain %25 %20 %23
+         %29 = OpFunctionCall %6 %12 %27
+         %30 = OpAccessChain %15 %20 %14
+         %45 = OpCopyObject %15 %30
+         %81 = OpCopyObject %9 %27
+         %33 = OpAccessChain %15 %20 %14
+               OpSelectionMerge %37 None
+               OpBranchConditional %35 %36 %37
+         %36 = OpLabel
+         %38 = OpAccessChain %15 %20 %14
+         %40 = OpAccessChain %15 %20 %14
+         %43 = OpAccessChain %15 %20 %14
+         %82 = OpCopyObject %9 %27
+               OpBranch %37
+         %37 = OpLabel
+               OpReturn
+               OpFunctionEnd
+         %12 = OpFunction %6 None %10
+         %11 = OpFunctionParameter %9
+         %13 = OpLabel
+         %46 = OpCopyObject %9 %11
+         %16 = OpAccessChain %15 %11 %14
+         %95 = OpCopyObject %8 %80
+               OpReturnValue %21
+        %100 = OpLabel
+               OpUnreachable
+               OpFunctionEnd
+  )";
+
+  const auto env = SPV_ENV_UNIVERSAL_1_4;
+  const auto consumer = nullptr;
+  const std::unique_ptr<opt::IRContext> context =
+      BuildModule(env, consumer, shader, kFuzzAssembleOption);
+  spvtools::ValidatorOptions validator_options;
+  ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
+                                               kConsoleMessageConsumer));
+
+  opt::IRContext* ir_context = context.get();
+  auto private_storage_class = SpvStorageClassPrivate;
+  auto function_storage_class = SpvStorageClassFunction;
+  auto input_storage_class = SpvStorageClassInput;
+
+  // A valid pointer must have the correct |pointee_type_id| and |storageClass|.
+  // A function type pointer with id = 9 and pointee type id 8 should be found.
+  ASSERT_EQ(9, fuzzerutil::MaybeGetPointerType(ir_context, 8,
+                                               function_storage_class));
+  // A function type pointer with id = 15 and pointee type id 6 should be found.
+  ASSERT_EQ(15, fuzzerutil::MaybeGetPointerType(ir_context, 6,
+                                                function_storage_class));
+  // A function type pointer with id = 25 and pointee type id 7 should be found.
+  ASSERT_EQ(25, fuzzerutil::MaybeGetPointerType(ir_context, 7,
+                                                function_storage_class));
+
+  // A private type pointer with id=51 and pointee type id 6 should be found.
+  ASSERT_EQ(51, fuzzerutil::MaybeGetPointerType(ir_context, 6,
+                                                private_storage_class));
+  // A function pointer with id=50 and pointee type id 7 should be found.
+  ASSERT_EQ(50, fuzzerutil::MaybeGetPointerType(ir_context, 7,
+                                                private_storage_class));
+
+  // A input type pointer with id=91 and pointee type id 90 should be found.
+  ASSERT_EQ(
+      91, fuzzerutil::MaybeGetPointerType(ir_context, 90, input_storage_class));
+
+  // A pointer with id=91 and pointee type 90 exists, but the type should be
+  // input.
+  ASSERT_EQ(0, fuzzerutil::MaybeGetPointerType(ir_context, 90,
+                                               function_storage_class));
+  // A input type pointer with id=91 exists but the pointee id should be 90.
+  ASSERT_EQ(
+      0, fuzzerutil::MaybeGetPointerType(ir_context, 89, input_storage_class));
+  // A input type pointer with pointee id 90 exists but result id of the pointer
+  // should be 91.
+  ASSERT_NE(
+      58, fuzzerutil::MaybeGetPointerType(ir_context, 90, input_storage_class));
+}
+
+TEST(FuzzerutilTest, FuzzerUtilMaybeGetScalarConstantTest) {
+  std::string shader = R"(
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %4 "main" %56
+               OpExecutionMode %4 OriginUpperLeft
+               OpSource ESSL 310
+               OpName %4 "main"
+               OpName %8 "b1"
+               OpName %10 "b2"
+               OpName %12 "b3"
+               OpName %13 "b4"
+               OpName %16 "f1"
+               OpName %18 "f2"
+               OpName %22 "zc"
+               OpName %24 "i1"
+               OpName %28 "i2"
+               OpName %30 "i"
+               OpName %32 "i3"
+               OpName %34 "i4"
+               OpName %39 "f_arr"
+               OpName %49 "i_arr"
+               OpName %56 "value"
+               OpDecorate %22 RelaxedPrecision
+               OpDecorate %24 RelaxedPrecision
+               OpDecorate %28 RelaxedPrecision
+               OpDecorate %30 RelaxedPrecision
+               OpDecorate %32 RelaxedPrecision
+               OpDecorate %34 RelaxedPrecision
+               OpDecorate %49 RelaxedPrecision
+               OpDecorate %56 Location 0
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeBool
+          %7 = OpTypePointer Function %6
+          %9 = OpConstantTrue %6
+         %11 = OpConstantFalse %6
+         %14 = OpTypeFloat 32
+         %15 = OpTypePointer Function %14
+         %17 = OpConstant %14 1.23000002
+         %19 = OpConstant %14 1.11000001
+         %20 = OpTypeInt 32 1
+         %21 = OpTypePointer Function %20
+         %23 = OpConstant %20 0
+         %25 = OpConstant %20 1
+         %26 = OpTypeInt 32 0
+         %27 = OpTypePointer Function %26
+         %29 = OpConstant %26 100
+         %31 = OpConstant %26 0
+         %33 = OpConstant %20 -1
+         %35 = OpConstant %20 -99
+         %36 = OpConstant %26 5
+         %37 = OpTypeArray %14 %36
+         %38 = OpTypePointer Function %37
+         %40 = OpConstant %14 5.5
+         %41 = OpConstant %14 4.4000001
+         %42 = OpConstant %14 3.29999995
+         %43 = OpConstant %14 2.20000005
+         %44 = OpConstant %14 1.10000002
+         %45 = OpConstantComposite %37 %40 %41 %42 %43 %44
+         %46 = OpConstant %26 3
+         %47 = OpTypeArray %20 %46
+         %48 = OpTypePointer Function %47
+         %50 = OpConstant %20 3
+         %51 = OpConstant %20 7
+         %52 = OpConstant %20 9
+         %53 = OpConstantComposite %47 %50 %51 %52
+         %55 = OpTypePointer Input %14
+         %56 = OpVariable %55 Input
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+          %8 = OpVariable %7 Function
+         %10 = OpVariable %7 Function
+         %12 = OpVariable %7 Function
+         %13 = OpVariable %7 Function
+         %16 = OpVariable %15 Function
+         %18 = OpVariable %15 Function
+         %22 = OpVariable %21 Function
+         %24 = OpVariable %21 Function
+         %28 = OpVariable %27 Function
+         %30 = OpVariable %27 Function
+         %32 = OpVariable %21 Function
+         %34 = OpVariable %21 Function
+         %39 = OpVariable %38 Function
+         %49 = OpVariable %48 Function
+               OpStore %8 %9
+               OpStore %10 %11
+               OpStore %12 %9
+               OpStore %13 %11
+               OpStore %16 %17
+               OpStore %18 %19
+               OpStore %22 %23
+               OpStore %24 %25
+               OpStore %28 %29
+               OpStore %30 %31
+               OpStore %32 %33
+               OpStore %34 %35
+               OpStore %39 %45
+               OpStore %49 %53
+               OpReturn
+               OpFunctionEnd
+  )";
+
+  const auto env = SPV_ENV_UNIVERSAL_1_4;
+  const auto consumer = nullptr;
+  const std::unique_ptr<opt::IRContext> context =
+      BuildModule(env, consumer, shader, kFuzzAssembleOption);
+  spvtools::ValidatorOptions validator_options;
+  ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
+                                               kConsoleMessageConsumer));
+  TransformationContext transformation_context(
+      MakeUnique<FactManager>(context.get()), validator_options);
+
+  opt::IRContext* ir_context = context.get();
+
+  std::vector<uint32_t> uint_words1 = fuzzerutil::IntToWords(100, 32, false);
+  std::vector<uint32_t> uint_words2 = fuzzerutil::IntToWords(0, 32, false);
+  std::vector<uint32_t> int_words1 = fuzzerutil::IntToWords(-99, 32, true);
+  std::vector<uint32_t> int_words2 = fuzzerutil::IntToWords(1, 32, true);
+  uint32_t float_word1 = fuzzerutil::FloatToWord(1.11f);
+  uint32_t float_word2 = fuzzerutil::FloatToWord(4.4f);
+
+  // A unsigned int of value 100 that has a scalar type id of 26 exists and its
+  // id is 29.
+  ASSERT_EQ(
+      29, fuzzerutil::MaybeGetScalarConstant(ir_context, transformation_context,
+                                             uint_words1, 26, false));
+  // A unsigned int of value 0 that has a scalar type id of 26 exists and its id
+  // is 29.
+  ASSERT_EQ(
+      31, fuzzerutil::MaybeGetScalarConstant(ir_context, transformation_context,
+                                             uint_words2, 26, false));
+  // A signed int of value -99 that has a scalar type id of 20 exists and its id
+  // is 35.
+  ASSERT_EQ(35, fuzzerutil::MaybeGetScalarConstant(
+                    ir_context, transformation_context, int_words1, 20, false));
+  // A signed int of value 1 that has a scalar type id of 20 exists and its id
+  // is 25.
+  ASSERT_EQ(25, fuzzerutil::MaybeGetScalarConstant(
+                    ir_context, transformation_context, int_words2, 20, false));
+  // A float of value 1.11 that has a scalar type id of 14 exists and its id
+  // is 19.
+  ASSERT_EQ(19, fuzzerutil::MaybeGetScalarConstant(
+                    ir_context, transformation_context,
+                    std::vector<uint32_t>{float_word1}, 14, false));
+  // A signed int of value 1 that has a scalar type id of 20 exists and its id
+  // is 25.
+  ASSERT_EQ(41, fuzzerutil::MaybeGetScalarConstant(
+                    ir_context, transformation_context,
+                    std::vector<uint32_t>{float_word2}, 14, false));
+}
+
+TEST(FuzzerutilTest, FuzzerUtilMaybeGetStructTypeTest) {
+  std::string shader = R"(
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %4 "main" %92 %52 %53
+               OpExecutionMode %4 OriginUpperLeft
+               OpSource ESSL 310
+               OpDecorate %92 BuiltIn FragCoord
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeInt 32 1
+          %7 = OpTypeFloat 32
+          %8 = OpTypeStruct %6 %7
+          %9 = OpTypePointer Function %8
+         %10 = OpTypeFunction %6 %9
+         %14 = OpConstant %6 0
+         %15 = OpTypePointer Function %6
+         %51 = OpTypePointer Private %6
+         %21 = OpConstant %6 2
+         %23 = OpConstant %6 1
+         %24 = OpConstant %7 1
+         %25 = OpTypePointer Function %7
+         %50 = OpTypePointer Private %7
+         %34 = OpTypeBool
+         %35 = OpConstantFalse %34
+         %52 = OpVariable %50 Private
+         %53 = OpVariable %51 Private
+         %80 = OpConstantComposite %8 %21 %24
+         %90 = OpTypeVector %7 4
+         %91 = OpTypePointer Input %90
+         %92 = OpVariable %91 Input
+         %93 = OpConstantComposite %90 %24 %24 %24 %24
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+         %20 = OpVariable %9 Function
+         %27 = OpVariable %9 Function
+         %22 = OpAccessChain %15 %20 %14
+         %44 = OpCopyObject %9 %20
+         %26 = OpAccessChain %25 %20 %23
+         %29 = OpFunctionCall %6 %12 %27
+         %30 = OpAccessChain %15 %20 %14
+         %45 = OpCopyObject %15 %30
+         %81 = OpCopyObject %9 %27
+         %33 = OpAccessChain %15 %20 %14
+               OpSelectionMerge %37 None
+               OpBranchConditional %35 %36 %37
+         %36 = OpLabel
+         %38 = OpAccessChain %15 %20 %14
+         %40 = OpAccessChain %15 %20 %14
+         %43 = OpAccessChain %15 %20 %14
+         %82 = OpCopyObject %9 %27
+               OpBranch %37
+         %37 = OpLabel
+               OpReturn
+               OpFunctionEnd
+         %12 = OpFunction %6 None %10
+         %11 = OpFunctionParameter %9
+         %13 = OpLabel
+         %46 = OpCopyObject %9 %11
+         %16 = OpAccessChain %15 %11 %14
+         %95 = OpCopyObject %8 %80
+               OpReturnValue %21
+        %100 = OpLabel
+               OpUnreachable
+               OpFunctionEnd
+  )";
+
+  const auto env = SPV_ENV_UNIVERSAL_1_4;
+  const auto consumer = nullptr;
+  const std::unique_ptr<opt::IRContext> context =
+      BuildModule(env, consumer, shader, kFuzzAssembleOption);
+  spvtools::ValidatorOptions validator_options;
+  ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
+                                               kConsoleMessageConsumer));
+
+  opt::IRContext* ir_context = context.get();
+
+  // 6 and 7 are all valid ids from OpTypeInt and OpTypeFloat
+  // so the result id of 8 should be found.
+  ASSERT_EQ(8, fuzzerutil::MaybeGetStructType(ir_context,
+                                              std::vector<uint32_t>{6, 7}));
+
+  // |component_type_id| of 16 does not exist in the module, so such a struct
+  // type cannot be found.
+  ASSERT_EQ(0, fuzzerutil::MaybeGetStructType(ir_context,
+                                              std::vector<uint32_t>(6, 16)));
+
+  // |component_type_id| of 10 is of OpTypeFunction type and thus the struct
+  // cannot be found.
+  ASSERT_EQ(0, fuzzerutil::MaybeGetStructType(ir_context,
+                                              std::vector<uint32_t>(6, 10)));
+}
+
+TEST(FuzzerutilTest, FuzzerUtilMaybeGetVectorTypeTest) {
+  std::string shader = R"(
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %4 "main" %92 %52 %53
+               OpExecutionMode %4 OriginUpperLeft
+               OpSource ESSL 310
+               OpDecorate %92 BuiltIn FragCoord
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeInt 32 1
+          %7 = OpTypeFloat 32
+          %8 = OpTypeStruct %6 %7
+          %9 = OpTypePointer Function %8
+         %10 = OpTypeFunction %6 %9
+         %14 = OpConstant %6 0
+         %15 = OpTypePointer Function %6
+         %51 = OpTypePointer Private %6
+         %21 = OpConstant %6 2
+         %23 = OpConstant %6 1
+         %24 = OpConstant %7 1
+         %25 = OpTypePointer Function %7
+         %50 = OpTypePointer Private %7
+         %34 = OpTypeBool
+         %35 = OpConstantFalse %34
+         %52 = OpVariable %50 Private
+         %53 = OpVariable %51 Private
+         %80 = OpConstantComposite %8 %21 %24
+         %90 = OpTypeVector %7 4
+         %91 = OpTypePointer Input %90
+         %92 = OpVariable %91 Input
+         %93 = OpConstantComposite %90 %24 %24 %24 %24
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+         %20 = OpVariable %9 Function
+         %27 = OpVariable %9 Function
+         %22 = OpAccessChain %15 %20 %14
+         %44 = OpCopyObject %9 %20
+         %26 = OpAccessChain %25 %20 %23
+         %29 = OpFunctionCall %6 %12 %27
+         %30 = OpAccessChain %15 %20 %14
+         %45 = OpCopyObject %15 %30
+         %81 = OpCopyObject %9 %27
+         %33 = OpAccessChain %15 %20 %14
+               OpSelectionMerge %37 None
+               OpBranchConditional %35 %36 %37
+         %36 = OpLabel
+         %38 = OpAccessChain %15 %20 %14
+         %40 = OpAccessChain %15 %20 %14
+         %43 = OpAccessChain %15 %20 %14
+         %82 = OpCopyObject %9 %27
+               OpBranch %37
+         %37 = OpLabel
+               OpReturn
+               OpFunctionEnd
+         %12 = OpFunction %6 None %10
+         %11 = OpFunctionParameter %9
+         %13 = OpLabel
+         %46 = OpCopyObject %9 %11
+         %16 = OpAccessChain %15 %11 %14
+         %95 = OpCopyObject %8 %80
+               OpReturnValue %21
+        %100 = OpLabel
+               OpUnreachable
+               OpFunctionEnd
+  )";
+
+  const auto env = SPV_ENV_UNIVERSAL_1_4;
+  const auto consumer = nullptr;
+  const std::unique_ptr<opt::IRContext> context =
+      BuildModule(env, consumer, shader, kFuzzAssembleOption);
+  spvtools::ValidatorOptions validator_options;
+  ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
+                                               kConsoleMessageConsumer));
+
+  opt::IRContext* ir_context = context.get();
+  // The vector type with |element_count| 4 and |component_type_id| 7
+  // is present and has a result id of 90.
+  ASSERT_EQ(90, fuzzerutil::MaybeGetVectorType(ir_context, 7, 4));
+
+  // The vector type with |element_count| 3 and |component_type_id| 7
+  // is not present in the module.
+  ASSERT_EQ(0, fuzzerutil::MaybeGetVectorType(ir_context, 7, 3));
+
+#ifndef NDEBUG
+  // It should abort with |component_type_id| of 100
+  // |component_type_id| must be a valid result id of an OpTypeInt,
+  // OpTypeFloat or OpTypeBool instruction in the module.
+  ASSERT_DEATH(fuzzerutil::MaybeGetVectorType(ir_context, 100, 4),
+               "\\|component_type_id\\| is invalid");
+
+  // It should abort with |element_count| of 5.
+  // |element_count| must be in the range [2,4].
+  ASSERT_DEATH(fuzzerutil::MaybeGetVectorType(ir_context, 7, 5),
+               "Precondition: component count must be in range \\[2, 4\\].");
+#endif
+}
+
+TEST(FuzzerutilTest, FuzzerUtilMaybeGetVoidTypeTest) {
+  std::string shader = R"(
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %4 "main" %92 %52 %53
+               OpExecutionMode %4 OriginUpperLeft
+               OpSource ESSL 310
+               OpDecorate %92 BuiltIn FragCoord
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeInt 32 1
+          %7 = OpTypeFloat 32
+          %8 = OpTypeStruct %6 %7
+          %9 = OpTypePointer Function %8
+         %10 = OpTypeFunction %6 %9
+         %14 = OpConstant %6 0
+         %15 = OpTypePointer Function %6
+         %51 = OpTypePointer Private %6
+         %21 = OpConstant %6 2
+         %23 = OpConstant %6 1
+         %24 = OpConstant %7 1
+         %25 = OpTypePointer Function %7
+         %50 = OpTypePointer Private %7
+         %34 = OpTypeBool
+         %35 = OpConstantFalse %34
+         %52 = OpVariable %50 Private
+         %53 = OpVariable %51 Private
+         %80 = OpConstantComposite %8 %21 %24
+         %90 = OpTypeVector %7 4
+         %91 = OpTypePointer Input %90
+         %92 = OpVariable %91 Input
+         %93 = OpConstantComposite %90 %24 %24 %24 %24
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+         %20 = OpVariable %9 Function
+         %27 = OpVariable %9 Function
+         %22 = OpAccessChain %15 %20 %14
+         %44 = OpCopyObject %9 %20
+         %26 = OpAccessChain %25 %20 %23
+         %29 = OpFunctionCall %6 %12 %27
+         %30 = OpAccessChain %15 %20 %14
+         %45 = OpCopyObject %15 %30
+         %81 = OpCopyObject %9 %27
+         %33 = OpAccessChain %15 %20 %14
+               OpSelectionMerge %37 None
+               OpBranchConditional %35 %36 %37
+         %36 = OpLabel
+         %38 = OpAccessChain %15 %20 %14
+         %40 = OpAccessChain %15 %20 %14
+         %43 = OpAccessChain %15 %20 %14
+         %82 = OpCopyObject %9 %27
+               OpBranch %37
+         %37 = OpLabel
+               OpReturn
+               OpFunctionEnd
+         %12 = OpFunction %6 None %10
+         %11 = OpFunctionParameter %9
+         %13 = OpLabel
+         %46 = OpCopyObject %9 %11
+         %16 = OpAccessChain %15 %11 %14
+         %95 = OpCopyObject %8 %80
+               OpReturnValue %21
+        %100 = OpLabel
+               OpUnreachable
+               OpFunctionEnd
+  )";
+
+  const auto env = SPV_ENV_UNIVERSAL_1_4;
+  const auto consumer = nullptr;
+  const std::unique_ptr<opt::IRContext> context =
+      BuildModule(env, consumer, shader, kFuzzAssembleOption);
+  spvtools::ValidatorOptions validator_options;
+  ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
+                                               kConsoleMessageConsumer));
+
+  opt::IRContext* ir_context = context.get();
+  // A void type with a result id of 2 can be found.
+  ASSERT_EQ(2, fuzzerutil::MaybeGetVoidType(ir_context));
+}
+
+TEST(FuzzerutilTest, FuzzerUtilMaybeGetZeroConstantTest) {
+  std::string shader = R"(
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %4 "main" %56
+               OpExecutionMode %4 OriginUpperLeft
+               OpSource ESSL 310
+               OpName %4 "main"
+               OpName %8 "b1"
+               OpName %10 "b2"
+               OpName %12 "b3"
+               OpName %13 "b4"
+               OpName %16 "f1"
+               OpName %18 "f2"
+               OpName %22 "zc"
+               OpName %24 "i1"
+               OpName %28 "i2"
+               OpName %30 "i"
+               OpName %32 "i3"
+               OpName %34 "i4"
+               OpName %39 "f_arr"
+               OpName %49 "i_arr"
+               OpName %56 "value"
+               OpDecorate %22 RelaxedPrecision
+               OpDecorate %24 RelaxedPrecision
+               OpDecorate %28 RelaxedPrecision
+               OpDecorate %30 RelaxedPrecision
+               OpDecorate %32 RelaxedPrecision
+               OpDecorate %34 RelaxedPrecision
+               OpDecorate %49 RelaxedPrecision
+               OpDecorate %56 Location 0
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeBool
+          %7 = OpTypePointer Function %6
+          %9 = OpConstantTrue %6
+         %11 = OpConstantFalse %6
+         %14 = OpTypeFloat 32
+         %15 = OpTypePointer Function %14
+         %17 = OpConstant %14 1.23000002
+         %19 = OpConstant %14 1.11000001
+         %20 = OpTypeInt 32 1
+         %21 = OpTypePointer Function %20
+         %23 = OpConstant %20 0
+         %25 = OpConstant %20 1
+         %26 = OpTypeInt 32 0
+         %27 = OpTypePointer Function %26
+         %29 = OpConstant %26 100
+         %31 = OpConstant %26 0
+         %33 = OpConstant %20 -1
+         %35 = OpConstant %20 -99
+         %36 = OpConstant %26 5
+         %37 = OpTypeArray %14 %36
+         %38 = OpTypePointer Function %37
+         %40 = OpConstant %14 5.5
+         %41 = OpConstant %14 4.4000001
+         %42 = OpConstant %14 3.29999995
+         %43 = OpConstant %14 2.20000005
+         %44 = OpConstant %14 1.10000002
+         %45 = OpConstantComposite %37 %40 %41 %42 %43 %44
+         %46 = OpConstant %26 3
+         %47 = OpTypeArray %20 %46
+         %48 = OpTypePointer Function %47
+         %50 = OpConstant %20 3
+         %51 = OpConstant %20 7
+         %52 = OpConstant %20 9
+         %53 = OpConstantComposite %47 %50 %51 %52
+         %55 = OpTypePointer Input %14
+         %56 = OpVariable %55 Input
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+          %8 = OpVariable %7 Function
+         %10 = OpVariable %7 Function
+         %12 = OpVariable %7 Function
+         %13 = OpVariable %7 Function
+         %16 = OpVariable %15 Function
+         %18 = OpVariable %15 Function
+         %22 = OpVariable %21 Function
+         %24 = OpVariable %21 Function
+         %28 = OpVariable %27 Function
+         %30 = OpVariable %27 Function
+         %32 = OpVariable %21 Function
+         %34 = OpVariable %21 Function
+         %39 = OpVariable %38 Function
+         %49 = OpVariable %48 Function
+               OpStore %8 %9
+               OpStore %10 %11
+               OpStore %12 %9
+               OpStore %13 %11
+               OpStore %16 %17
+               OpStore %18 %19
+               OpStore %22 %23
+               OpStore %24 %25
+               OpStore %28 %29
+               OpStore %30 %31
+               OpStore %32 %33
+               OpStore %34 %35
+               OpStore %39 %45
+               OpStore %49 %53
+               OpReturn
+               OpFunctionEnd
+  )";
+
+  const auto env = SPV_ENV_UNIVERSAL_1_4;
+  const auto consumer = nullptr;
+  const std::unique_ptr<opt::IRContext> context =
+      BuildModule(env, consumer, shader, kFuzzAssembleOption);
+  spvtools::ValidatorOptions validator_options;
+  ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
+                                               kConsoleMessageConsumer));
+  TransformationContext transformation_context(
+      MakeUnique<FactManager>(context.get()), validator_options);
+
+  opt::IRContext* ir_context = context.get();
+
+  // The id of a boolean constant will be returned give boolean type id 6.
+  uint32_t maybe_bool_id = fuzzerutil::MaybeGetZeroConstant(
+      ir_context, transformation_context, 6, false);
+  // The id of a 32 bit float constant will be returned given the float type
+  // id 14.
+  uint32_t maybe_float_id = fuzzerutil::MaybeGetZeroConstant(
+      ir_context, transformation_context, 14, false);
+  uint32_t maybe_signed_int_id = fuzzerutil::MaybeGetZeroConstant(
+      ir_context, transformation_context, 20, false);
+  uint32_t maybe_unsigned_int_id = fuzzerutil::MaybeGetZeroConstant(
+      ir_context, transformation_context, 26, false);
+
+  // Lists of possible ids for float, signed int, unsigned int and array.
+  std::vector<uint32_t> float_ids{17, 19};
+  std::vector<uint32_t> signed_int_ids{23, 25, 31, 33};
+
+  ASSERT_TRUE(maybe_bool_id == 9 || maybe_bool_id == 11);
+  ASSERT_TRUE(std::find(signed_int_ids.begin(), signed_int_ids.end(),
+                        maybe_signed_int_id) != signed_int_ids.end());
+
+  // There is a unsigned int typed zero constant and its id is 31.
+  ASSERT_EQ(31, maybe_unsigned_int_id);
+
+  // There is no zero float constant.
+  ASSERT_TRUE(std::find(float_ids.begin(), float_ids.end(), maybe_float_id) ==
+              float_ids.end());
+}
+
+TEST(FuzzerutilTest, TypesAreCompatible) {
+  const std::string shader = R"(
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %4 "main"
+               OpExecutionMode %4 OriginUpperLeft
+               OpSource ESSL 320
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeInt 32 1
+          %9 = OpTypeInt 32 0
+          %8 = OpTypeStruct %6
+         %10 = OpTypePointer StorageBuffer %8
+         %11 = OpVariable %10 StorageBuffer
+         %86 = OpTypeStruct %9
+         %87 = OpTypePointer Workgroup %86
+         %88 = OpVariable %87 Workgroup
+         %89 = OpTypePointer Workgroup %9
+         %19 = OpConstant %9 0
+         %18 = OpConstant %9 1
+         %12 = OpConstant %6 0
+         %13 = OpTypePointer StorageBuffer %6
+         %15 = OpConstant %6 2
+         %16 = OpConstant %6 7
+         %20 = OpConstant %9 64
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+         %14 = OpAccessChain %13 %11 %12
+         %90 = OpAccessChain %89 %88 %19
+         %21 = OpAtomicLoad %6 %14 %15 %20
+         %22 = OpAtomicExchange %6 %14 %15 %20 %16
+         %23 = OpAtomicCompareExchange %6 %14 %15 %20 %12 %16 %15
+         %24 = OpAtomicIIncrement %6 %14 %15 %20
+         %25 = OpAtomicIDecrement %6 %14 %15 %20
+         %26 = OpAtomicIAdd %6  %14 %15 %20 %16
+         %27 = OpAtomicISub %6  %14 %15 %20 %16
+         %28 = OpAtomicSMin %6  %14 %15 %20 %16
+         %29 = OpAtomicUMin %9 %90 %15 %20 %18
+         %30 = OpAtomicSMax %6  %14 %15 %20 %15
+         %31 = OpAtomicUMax %9 %90 %15 %20 %18
+         %32 = OpAtomicAnd  %6  %14 %15 %20 %16
+         %33 = OpAtomicOr   %6  %14 %15 %20 %16
+         %34 = OpAtomicXor  %6  %14 %15 %20 %16
+               OpAtomicStore %14 %15 %20 %16
+               OpReturn
+               OpFunctionEnd
+  )";
+
+  const auto env = SPV_ENV_UNIVERSAL_1_3;
+  const auto consumer = nullptr;
+  const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
+  spvtools::ValidatorOptions validator_options;
+  ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
+                                               kConsoleMessageConsumer));
+
+  const uint32_t int_type = 6;   // The id of OpTypeInt 32 1
+  const uint32_t uint_type = 9;  // The id of OpTypeInt 32 0
+
+  // OpAtomicLoad
+#ifndef NDEBUG
+  ASSERT_DEATH(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicLoad, 0,
+                                              int_type, uint_type),
+               "Signedness check should not occur on a pointer operand.");
+#endif
+  ASSERT_TRUE(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicLoad, 1,
+                                             int_type, uint_type));
+  ASSERT_TRUE(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicLoad, 2,
+                                             int_type, uint_type));
+
+  // OpAtomicExchange
+#ifndef NDEBUG
+  ASSERT_DEATH(fuzzerutil::TypesAreCompatible(
+                   context.get(), SpvOpAtomicExchange, 0, int_type, uint_type),
+               "Signedness check should not occur on a pointer operand.");
+#endif
+  ASSERT_TRUE(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicExchange,
+                                             1, int_type, uint_type));
+  ASSERT_TRUE(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicExchange,
+                                             2, int_type, uint_type));
+  ASSERT_FALSE(fuzzerutil::TypesAreCompatible(
+      context.get(), SpvOpAtomicExchange, 3, int_type, uint_type));
+
+  // OpAtomicStore
+#ifndef NDEBUG
+  ASSERT_DEATH(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicStore,
+                                              0, int_type, uint_type),
+               "Signedness check should not occur on a pointer operand.");
+#endif
+  ASSERT_TRUE(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicStore, 1,
+                                             int_type, uint_type));
+  ASSERT_TRUE(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicStore, 2,
+                                             int_type, uint_type));
+  ASSERT_FALSE(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicStore,
+                                              3, int_type, uint_type));
+
+  // OpAtomicCompareExchange
+#ifndef NDEBUG
+  ASSERT_DEATH(
+      fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicCompareExchange,
+                                     0, int_type, uint_type),
+      "Signedness check should not occur on a pointer operand.");
+#endif
+  ASSERT_TRUE(fuzzerutil::TypesAreCompatible(
+      context.get(), SpvOpAtomicCompareExchange, 1, int_type, uint_type));
+  ASSERT_TRUE(fuzzerutil::TypesAreCompatible(
+      context.get(), SpvOpAtomicCompareExchange, 2, int_type, uint_type));
+  ASSERT_TRUE(fuzzerutil::TypesAreCompatible(
+      context.get(), SpvOpAtomicCompareExchange, 3, int_type, uint_type));
+  ASSERT_FALSE(fuzzerutil::TypesAreCompatible(
+      context.get(), SpvOpAtomicCompareExchange, 4, int_type, uint_type));
+
+  // OpAtomicIIncrement
+#ifndef NDEBUG
+  ASSERT_DEATH(
+      fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicIIncrement, 0,
+                                     int_type, uint_type),
+      "Signedness check should not occur on a pointer operand.");
+#endif
+  ASSERT_TRUE(fuzzerutil::TypesAreCompatible(
+      context.get(), SpvOpAtomicIIncrement, 1, int_type, uint_type));
+  ASSERT_TRUE(fuzzerutil::TypesAreCompatible(
+      context.get(), SpvOpAtomicIIncrement, 2, int_type, uint_type));
+
+// OpAtomicIDecrement
+#ifndef NDEBUG
+  ASSERT_DEATH(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicStore,
+                                              0, int_type, uint_type),
+               "Signedness check should not occur on a pointer operand.");
+#endif
+  ASSERT_TRUE(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicStore, 1,
+                                             int_type, uint_type));
+  ASSERT_TRUE(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicStore, 2,
+                                             int_type, uint_type));
+
+// OpAtomicIAdd
+#ifndef NDEBUG
+  ASSERT_DEATH(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicIAdd, 0,
+                                              int_type, uint_type),
+               "Signedness check should not occur on a pointer operand.");
+#endif
+  ASSERT_TRUE(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicIAdd, 1,
+                                             int_type, uint_type));
+  ASSERT_TRUE(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicIAdd, 2,
+                                             int_type, uint_type));
+  ASSERT_FALSE(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicIAdd, 3,
+                                              int_type, uint_type));
+
+// OpAtomicISub
+#ifndef NDEBUG
+  ASSERT_DEATH(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicISub, 0,
+                                              int_type, uint_type),
+               "Signedness check should not occur on a pointer operand.");
+#endif
+  ASSERT_TRUE(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicISub, 1,
+                                             int_type, uint_type));
+  ASSERT_TRUE(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicISub, 2,
+                                             int_type, uint_type));
+  ASSERT_FALSE(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicISub, 3,
+                                              int_type, uint_type));
+
+// OpAtomicSMin
+#ifndef NDEBUG
+  ASSERT_DEATH(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicSMin, 0,
+                                              int_type, uint_type),
+               "Signedness check should not occur on a pointer operand.");
+#endif
+  ASSERT_TRUE(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicSMin, 1,
+                                             int_type, uint_type));
+  ASSERT_TRUE(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicSMin, 2,
+                                             int_type, uint_type));
+  ASSERT_FALSE(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicSMin, 3,
+                                              int_type, uint_type));
+
+// OpAtomicUMin
+#ifndef NDEBUG
+  ASSERT_DEATH(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicUMin, 0,
+                                              int_type, uint_type),
+               "Signedness check should not occur on a pointer operand.");
+#endif
+  ASSERT_TRUE(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicUMin, 1,
+                                             int_type, uint_type));
+  ASSERT_TRUE(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicUMin, 2,
+                                             int_type, uint_type));
+  ASSERT_FALSE(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicUMin, 3,
+                                              int_type, uint_type));
+
+// OpAtomicSMax
+#ifndef NDEBUG
+  ASSERT_DEATH(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicSMax, 0,
+                                              int_type, uint_type),
+               "Signedness check should not occur on a pointer operand.");
+#endif
+  ASSERT_TRUE(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicSMax, 1,
+                                             int_type, uint_type));
+  ASSERT_TRUE(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicSMax, 2,
+                                             int_type, uint_type));
+  ASSERT_FALSE(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicSMax, 3,
+                                              int_type, uint_type));
+
+// OpAtomicUMax
+#ifndef NDEBUG
+  ASSERT_DEATH(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicUMax, 0,
+                                              int_type, uint_type),
+               "Signedness check should not occur on a pointer operand.");
+#endif
+  ASSERT_TRUE(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicUMax, 1,
+                                             int_type, uint_type));
+  ASSERT_TRUE(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicUMax, 2,
+                                             int_type, uint_type));
+  ASSERT_FALSE(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicUMax, 3,
+                                              int_type, uint_type));
+
+// OpAtomicAnd
+#ifndef NDEBUG
+  ASSERT_DEATH(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicAnd, 0,
+                                              int_type, uint_type),
+               "Signedness check should not occur on a pointer operand.");
+#endif
+  ASSERT_TRUE(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicAnd, 1,
+                                             int_type, uint_type));
+  ASSERT_TRUE(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicAnd, 2,
+                                             int_type, uint_type));
+  ASSERT_FALSE(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicAnd, 3,
+                                              int_type, uint_type));
+
+// OpAtomicOr
+#ifndef NDEBUG
+  ASSERT_DEATH(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicOr, 0,
+                                              int_type, uint_type),
+               "Signedness check should not occur on a pointer operand.");
+#endif
+  ASSERT_TRUE(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicOr, 1,
+                                             int_type, uint_type));
+  ASSERT_TRUE(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicOr, 2,
+                                             int_type, uint_type));
+  ASSERT_FALSE(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicOr, 3,
+                                              int_type, uint_type));
+
+// OpAtomicXor
+#ifndef NDEBUG
+  ASSERT_DEATH(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicXor, 0,
+                                              int_type, uint_type),
+               "Signedness check should not occur on a pointer operand.");
+#endif
+  ASSERT_TRUE(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicXor, 1,
+                                             int_type, uint_type));
+  ASSERT_TRUE(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicXor, 2,
+                                             int_type, uint_type));
+  ASSERT_FALSE(fuzzerutil::TypesAreCompatible(context.get(), SpvOpAtomicXor, 3,
+                                              int_type, uint_type));
+}
+
+}  // namespace
+}  // namespace fuzz
+}  // namespace spvtools

+ 288 - 0
ThirdParty/Glslang/External/spirv-tools/test/fuzz/transformation_swap_function_variables_test.cpp

@@ -0,0 +1,288 @@
+// Copyright (c) 2021 Mostafa Ashraf
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "source/fuzz/transformation_swap_function_variables.h"
+
+#include "gtest/gtest.h"
+#include "source/fuzz/fuzzer_util.h"
+#include "source/fuzz/instruction_descriptor.h"
+#include "test/fuzz/fuzz_test_util.h"
+
+namespace spvtools {
+namespace fuzz {
+namespace {
+
+TEST(TransformationSwapFunctionVariables, NotApplicable) {
+  std::string shader = R"(
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %4 "main"
+               OpExecutionMode %4 OriginUpperLeft
+               OpSource ESSL 320
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeInt 32 1
+          %7 = OpTypePointer Function %6
+          %8 = OpTypeFloat 32
+          %9 = OpTypePointer Function %8
+         %10 = OpTypeVector %8 2
+         %11 = OpTypePointer Function %10
+         %12 = OpTypeVector %8 3
+         %13 = OpTypeMatrix %12 3
+         %14 = OpTypePointer Function %13
+         %15 = OpTypeFunction %2 %7 %9 %11 %14 %7 %7
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+         %24 = OpVariable %7 Function
+         %25 = OpVariable %9 Function
+         %26 = OpVariable %11 Function
+         %27 = OpVariable %14 Function
+         %28 = OpVariable %7 Function
+         %29 = OpVariable %7 Function
+         %30 = OpVariable %7 Function
+         %32 = OpVariable %9 Function
+         %34 = OpVariable %11 Function
+         %36 = OpVariable %14 Function
+         %38 = OpVariable %7 Function
+         %40 = OpVariable %7 Function
+         %31 = OpLoad %6 %24
+               OpStore %30 %31
+         %33 = OpLoad %8 %25
+               OpStore %32 %33
+         %35 = OpLoad %10 %26
+               OpStore %34 %35
+         %37 = OpLoad %13 %27
+               OpStore %36 %37
+         %39 = OpLoad %6 %28
+               OpStore %38 %39
+         %41 = OpLoad %6 %29
+               OpStore %40 %41
+         %42 = OpFunctionCall %2 %22 %30 %32 %34 %36 %38 %40
+               OpReturn
+               OpFunctionEnd
+         %22 = OpFunction %2 None %15
+         %16 = OpFunctionParameter %7
+         %17 = OpFunctionParameter %9
+         %18 = OpFunctionParameter %11
+         %19 = OpFunctionParameter %14
+         %20 = OpFunctionParameter %7
+         %21 = OpFunctionParameter %7
+         %23 = OpLabel
+               OpReturn
+               OpFunctionEnd
+)";
+
+  const auto env = SPV_ENV_UNIVERSAL_1_5;
+  const auto consumer = nullptr;
+  const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
+  spvtools::ValidatorOptions validator_options;
+
+  ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
+                                               kConsoleMessageConsumer));
+  TransformationContext transformation_context(
+      MakeUnique<FactManager>(context.get()), validator_options);
+
+#ifndef NDEBUG
+  // Can't swap variable with itself.
+  ASSERT_DEATH(TransformationSwapFunctionVariables(7, 7).IsApplicable(
+                   context.get(), transformation_context),
+               "Two results ids are equal");
+#endif
+
+  // Invalid because 200 is not the id of an instruction.
+  ASSERT_FALSE(TransformationSwapFunctionVariables(1, 200).IsApplicable(
+      context.get(), transformation_context));
+  // Invalid because 5 is not the id of an instruction.
+  ASSERT_FALSE(TransformationSwapFunctionVariables(5, 24).IsApplicable(
+      context.get(), transformation_context));
+  // Can't swap two instructions from two different blocks.
+  ASSERT_FALSE(TransformationSwapFunctionVariables(16, 26).IsApplicable(
+      context.get(), transformation_context));
+}
+
+TEST(TransformationSwapFunctionVariables, IsApplicable) {
+  std::string shader = R"(
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %4 "main"
+               OpExecutionMode %4 OriginUpperLeft
+               OpSource ESSL 320
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeInt 32 1
+          %7 = OpTypePointer Function %6
+          %8 = OpTypeFloat 32
+          %9 = OpTypePointer Function %8
+         %10 = OpTypeVector %8 2
+         %11 = OpTypePointer Function %10
+         %12 = OpTypeVector %8 3
+         %13 = OpTypeMatrix %12 3
+         %14 = OpTypePointer Function %13
+         %15 = OpTypeFunction %2 %7 %9 %11 %14 %7 %7
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+         %24 = OpVariable %7 Function
+         %25 = OpVariable %9 Function
+         %26 = OpVariable %11 Function
+         %27 = OpVariable %14 Function
+         %28 = OpVariable %7 Function
+         %29 = OpVariable %7 Function
+         %30 = OpVariable %7 Function
+         %32 = OpVariable %9 Function
+         %34 = OpVariable %11 Function
+         %36 = OpVariable %14 Function
+         %38 = OpVariable %7 Function
+         %40 = OpVariable %7 Function
+         %31 = OpLoad %6 %24
+               OpStore %30 %31
+         %33 = OpLoad %8 %25
+               OpStore %32 %33
+         %35 = OpLoad %10 %26
+               OpStore %34 %35
+         %37 = OpLoad %13 %27
+               OpStore %36 %37
+         %39 = OpLoad %6 %28
+               OpStore %38 %39
+         %41 = OpLoad %6 %29
+               OpStore %40 %41
+         %42 = OpFunctionCall %2 %22 %30 %32 %34 %36 %38 %40
+               OpReturn
+               OpFunctionEnd
+         %22 = OpFunction %2 None %15
+         %16 = OpFunctionParameter %7
+         %17 = OpFunctionParameter %9
+         %18 = OpFunctionParameter %11
+         %19 = OpFunctionParameter %14
+         %20 = OpFunctionParameter %7
+         %21 = OpFunctionParameter %7
+         %23 = OpLabel
+               OpReturn
+               OpFunctionEnd
+)";
+
+  const auto env = SPV_ENV_UNIVERSAL_1_5;
+  const auto consumer = nullptr;
+  // Get Unique pointer of IRContext.
+  const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
+  spvtools::ValidatorOptions validator_options;
+
+  ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
+                                               kConsoleMessageConsumer));
+  TransformationContext transformation_context(
+      MakeUnique<FactManager>(context.get()), validator_options);
+
+  // Successful transformations
+  {
+    auto first_instruction = context->get_def_use_mgr()->GetDef(24);
+    auto second_instruction = context->get_def_use_mgr()->GetDef(28);
+    // Swap two OpVariable instructions in the same function.
+    TransformationSwapFunctionVariables transformation(24, 28);
+
+    ASSERT_TRUE(
+        transformation.IsApplicable(context.get(), transformation_context));
+
+    ApplyAndCheckFreshIds(transformation, context.get(),
+                          &transformation_context);
+
+    ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
+        context.get(), validator_options, kConsoleMessageConsumer));
+
+    ASSERT_EQ(first_instruction, context->get_def_use_mgr()->GetDef(24));
+    ASSERT_EQ(second_instruction, context->get_def_use_mgr()->GetDef(28));
+  }
+  {
+    auto first_instruction = context->get_def_use_mgr()->GetDef(38);
+    auto second_instruction = context->get_def_use_mgr()->GetDef(40);
+    // Swap two OpVariable instructions in the same function.
+    TransformationSwapFunctionVariables transformation(38, 40);
+
+    ASSERT_TRUE(
+        transformation.IsApplicable(context.get(), transformation_context));
+
+    ApplyAndCheckFreshIds(transformation, context.get(),
+                          &transformation_context);
+
+    ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
+        context.get(), validator_options, kConsoleMessageConsumer));
+
+    ASSERT_EQ(first_instruction, context->get_def_use_mgr()->GetDef(38));
+    ASSERT_EQ(second_instruction, context->get_def_use_mgr()->GetDef(40));
+  }
+  std::string after_transformation = R"(
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %4 "main"
+               OpExecutionMode %4 OriginUpperLeft
+               OpSource ESSL 320
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeInt 32 1
+          %7 = OpTypePointer Function %6
+          %8 = OpTypeFloat 32
+          %9 = OpTypePointer Function %8
+         %10 = OpTypeVector %8 2
+         %11 = OpTypePointer Function %10
+         %12 = OpTypeVector %8 3
+         %13 = OpTypeMatrix %12 3
+         %14 = OpTypePointer Function %13
+         %15 = OpTypeFunction %2 %7 %9 %11 %14 %7 %7
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+         %28 = OpVariable %7 Function
+         %25 = OpVariable %9 Function
+         %26 = OpVariable %11 Function
+         %27 = OpVariable %14 Function
+         %24 = OpVariable %7 Function
+         %29 = OpVariable %7 Function
+         %30 = OpVariable %7 Function
+         %32 = OpVariable %9 Function
+         %34 = OpVariable %11 Function
+         %36 = OpVariable %14 Function
+         %40 = OpVariable %7 Function
+         %38 = OpVariable %7 Function
+         %31 = OpLoad %6 %24
+               OpStore %30 %31
+         %33 = OpLoad %8 %25
+               OpStore %32 %33
+         %35 = OpLoad %10 %26
+               OpStore %34 %35
+         %37 = OpLoad %13 %27
+               OpStore %36 %37
+         %39 = OpLoad %6 %28
+               OpStore %38 %39
+         %41 = OpLoad %6 %29
+               OpStore %40 %41
+         %42 = OpFunctionCall %2 %22 %30 %32 %34 %36 %38 %40
+               OpReturn
+               OpFunctionEnd
+         %22 = OpFunction %2 None %15
+         %16 = OpFunctionParameter %7
+         %17 = OpFunctionParameter %9
+         %18 = OpFunctionParameter %11
+         %19 = OpFunctionParameter %14
+         %20 = OpFunctionParameter %7
+         %21 = OpFunctionParameter %7
+         %23 = OpLabel
+               OpReturn
+               OpFunctionEnd
+)";
+  ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
+}
+
+}  // namespace
+}  // namespace fuzz
+}  // namespace spvtools

+ 257 - 0
ThirdParty/Glslang/External/spirv-tools/test/fuzz/transformation_swap_two_functions_test.cpp

@@ -0,0 +1,257 @@
+// Copyright (c) 2021 Shiyu Liu
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "source/fuzz/transformation_swap_two_functions.h"
+
+#include "gtest/gtest.h"
+#include "source/fuzz/fuzzer_util.h"
+#include "test/fuzz/fuzz_test_util.h"
+
+namespace spvtools {
+namespace fuzz {
+namespace {
+
+TEST(TransformationSwapTwoFunctionsTest, SimpleTest) {
+  //   float multiplyBy2(in float value) {
+  //     return value*2.0;
+  //   }
+
+  //   float multiplyBy4(in float value) {
+  //     return multiplyBy2(value)*2.0;
+  //   }
+
+  //   float multiplyBy8(in float value) {
+  //     return multiplyBy2(value)*multiplyBy4(value);
+  //   }
+
+  //   layout(location=0) in float value;
+  //   void main() { //4
+  //     multiplyBy2(3.7); //10
+  //     multiplyBy4(3.9); //13
+  //     multiplyBy8(5.0); //16
+  //   }
+
+  std::string shader = R"(
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %4 "main" %48
+               OpExecutionMode %4 OriginUpperLeft
+               OpSource ESSL 310
+               OpName %4 "main"
+               OpName %10 "multiplyBy2(f1;"
+               OpName %9 "value"
+               OpName %13 "multiplyBy4(f1;"
+               OpName %12 "value"
+               OpName %16 "multiplyBy8(f1;"
+               OpName %15 "value"
+               OpName %23 "param"
+               OpName %29 "param"
+               OpName %32 "param"
+               OpName %39 "param"
+               OpName %42 "param"
+               OpName %45 "param"
+               OpName %48 "value"
+               OpDecorate %48 Location 0
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeFloat 32
+          %7 = OpTypePointer Function %6
+          %8 = OpTypeFunction %6 %7
+         %19 = OpConstant %6 2
+         %38 = OpConstant %6 3.70000005
+         %41 = OpConstant %6 3.9000001
+         %44 = OpConstant %6 5
+         %47 = OpTypePointer Input %6
+         %48 = OpVariable %47 Input
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+         %39 = OpVariable %7 Function
+         %42 = OpVariable %7 Function
+         %45 = OpVariable %7 Function
+               OpStore %39 %38
+         %40 = OpFunctionCall %6 %10 %39
+               OpStore %42 %41
+         %43 = OpFunctionCall %6 %13 %42
+               OpStore %45 %44
+         %46 = OpFunctionCall %6 %16 %45
+               OpReturn
+               OpFunctionEnd
+         %10 = OpFunction %6 None %8
+          %9 = OpFunctionParameter %7
+         %11 = OpLabel
+         %18 = OpLoad %6 %9
+         %20 = OpFMul %6 %18 %19
+               OpReturnValue %20
+               OpFunctionEnd
+         %13 = OpFunction %6 None %8
+         %12 = OpFunctionParameter %7
+         %14 = OpLabel
+         %23 = OpVariable %7 Function
+         %24 = OpLoad %6 %12
+               OpStore %23 %24
+         %25 = OpFunctionCall %6 %10 %23
+         %26 = OpFMul %6 %25 %19
+               OpReturnValue %26
+               OpFunctionEnd
+         %16 = OpFunction %6 None %8
+         %15 = OpFunctionParameter %7
+         %17 = OpLabel
+         %29 = OpVariable %7 Function
+         %32 = OpVariable %7 Function
+         %30 = OpLoad %6 %15
+               OpStore %29 %30
+         %31 = OpFunctionCall %6 %10 %29
+         %33 = OpLoad %6 %15
+               OpStore %32 %33
+         %34 = OpFunctionCall %6 %13 %32
+         %35 = OpFMul %6 %31 %34
+               OpReturnValue %35
+               OpFunctionEnd
+  )";
+  const auto env = SPV_ENV_UNIVERSAL_1_3;
+  const auto consumer = nullptr;
+  const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
+  spvtools::ValidatorOptions validator_options;
+
+  // Check context validity.
+  ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
+                                               kConsoleMessageConsumer));
+
+  TransformationContext transformation_context(
+      MakeUnique<FactManager>(context.get()), validator_options);
+
+#ifndef NDEBUG
+  // Function should not swap with itself.
+  ASSERT_DEATH(TransformationSwapTwoFunctions(4, 4).IsApplicable(
+                   context.get(), transformation_context),
+               "The two function ids cannot be the same.");
+#endif
+
+  // Function with id 29 does not exist.
+  ASSERT_FALSE(TransformationSwapTwoFunctions(10, 29).IsApplicable(
+      context.get(), transformation_context));
+
+  // Function with id 30 does not exist.
+  ASSERT_FALSE(TransformationSwapTwoFunctions(30, 13).IsApplicable(
+      context.get(), transformation_context));
+
+  // Both functions with id 5 and 6 do not exist.
+  ASSERT_FALSE(TransformationSwapTwoFunctions(5, 6).IsApplicable(
+      context.get(), transformation_context));
+
+  // Function with result_id 10 and 13 should swap successfully.
+  auto swap_test5 = TransformationSwapTwoFunctions(10, 13);
+  ASSERT_TRUE(swap_test5.IsApplicable(context.get(), transformation_context));
+
+  // Get the definitions of functions 10 and 13, as recorded by the def-use
+  // manager.
+  auto def_use_manager = context->get_def_use_mgr();
+  auto function_10_inst = def_use_manager->GetDef(10);
+  auto function_13_inst = def_use_manager->GetDef(13);
+
+  ApplyAndCheckFreshIds(swap_test5, context.get(), &transformation_context);
+
+  // Check that def-use information for functions 10 and 13 has been preserved
+  // by the transformation.
+  ASSERT_EQ(function_10_inst, def_use_manager->GetDef(10));
+  ASSERT_EQ(function_13_inst, def_use_manager->GetDef(13));
+
+  ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
+                                               kConsoleMessageConsumer));
+
+  std::string after_transformation = R"(
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %4 "main" %48
+               OpExecutionMode %4 OriginUpperLeft
+               OpSource ESSL 310
+               OpName %4 "main"
+               OpName %10 "multiplyBy2(f1;"
+               OpName %9 "value"
+               OpName %13 "multiplyBy4(f1;"
+               OpName %12 "value"
+               OpName %16 "multiplyBy8(f1;"
+               OpName %15 "value"
+               OpName %23 "param"
+               OpName %29 "param"
+               OpName %32 "param"
+               OpName %39 "param"
+               OpName %42 "param"
+               OpName %45 "param"
+               OpName %48 "value"
+               OpDecorate %48 Location 0
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeFloat 32
+          %7 = OpTypePointer Function %6
+          %8 = OpTypeFunction %6 %7
+         %19 = OpConstant %6 2
+         %38 = OpConstant %6 3.70000005
+         %41 = OpConstant %6 3.9000001
+         %44 = OpConstant %6 5
+         %47 = OpTypePointer Input %6
+         %48 = OpVariable %47 Input
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+         %39 = OpVariable %7 Function
+         %42 = OpVariable %7 Function
+         %45 = OpVariable %7 Function
+               OpStore %39 %38
+         %40 = OpFunctionCall %6 %10 %39
+               OpStore %42 %41
+         %43 = OpFunctionCall %6 %13 %42
+               OpStore %45 %44
+         %46 = OpFunctionCall %6 %16 %45
+               OpReturn
+               OpFunctionEnd
+         %13 = OpFunction %6 None %8
+         %12 = OpFunctionParameter %7
+         %14 = OpLabel
+         %23 = OpVariable %7 Function
+         %24 = OpLoad %6 %12
+               OpStore %23 %24
+         %25 = OpFunctionCall %6 %10 %23
+         %26 = OpFMul %6 %25 %19
+               OpReturnValue %26
+               OpFunctionEnd
+         %10 = OpFunction %6 None %8
+         %9 = OpFunctionParameter %7
+         %11 = OpLabel
+         %18 = OpLoad %6 %9
+         %20 = OpFMul %6 %18 %19
+               OpReturnValue %20
+               OpFunctionEnd
+         %16 = OpFunction %6 None %8
+         %15 = OpFunctionParameter %7
+         %17 = OpLabel
+         %29 = OpVariable %7 Function
+         %32 = OpVariable %7 Function
+         %30 = OpLoad %6 %15
+               OpStore %29 %30
+         %31 = OpFunctionCall %6 %10 %29
+         %33 = OpLoad %6 %15
+               OpStore %32 %33
+         %34 = OpFunctionCall %6 %13 %32
+         %35 = OpFMul %6 %31 %34
+               OpReturnValue %35
+               OpFunctionEnd
+  )";
+  ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
+}
+
+}  // namespace
+}  // namespace fuzz
+}  // namespace spvtools

+ 1553 - 0
ThirdParty/Glslang/External/spirv-tools/test/fuzz/transformation_wrap_vector_synonym_test.cpp

@@ -0,0 +1,1553 @@
+// Copyright (c) 2021 Shiyu Liu
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "source/fuzz/transformation_wrap_vector_synonym.h"
+
+#include "gtest/gtest.h"
+#include "source/fuzz/fuzzer_util.h"
+#include "source/fuzz/instruction_descriptor.h"
+#include "test/fuzz/fuzz_test_util.h"
+
+namespace spvtools {
+namespace fuzz {
+namespace {
+
+TEST(TransformationWrapVectorSynonym, BasicTest) {
+  std::string shader = R"(
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %4 "main" %97
+               OpExecutionMode %4 OriginUpperLeft
+               OpSource ESSL 310
+               OpName %4 "main"
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeInt 32 1
+          %7 = OpTypePointer Function %6
+          %9 = OpConstant %6 10
+         %11 = OpConstant %6 -5
+         %12 = OpTypeVector %6 2
+         %13 = OpTypePointer Function %12
+         %18 = OpTypeInt 32 0
+         %19 = OpTypePointer Function %18
+         %21 = OpConstant %18 8
+         %23 = OpConstant %18 2
+         %24 = OpTypeVector %18 3
+         %25 = OpTypePointer Function %24
+         %31 = OpTypeFloat 32
+         %32 = OpTypePointer Function %31
+         %34 = OpConstant %31 3.29999995
+         %36 = OpConstant %31 1.10000002
+         %37 = OpTypeVector %31 4
+         %38 = OpTypePointer Function %37
+         %96 = OpTypePointer Input %31
+         %97 = OpVariable %96 Input
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+          %8 = OpVariable %7 Function
+         %10 = OpVariable %7 Function
+         %14 = OpVariable %13 Function
+         %20 = OpVariable %19 Function
+         %22 = OpVariable %19 Function
+         %26 = OpVariable %25 Function
+         %33 = OpVariable %32 Function
+         %35 = OpVariable %32 Function
+         %39 = OpVariable %38 Function
+         %47 = OpVariable %7 Function
+         %51 = OpVariable %7 Function
+         %55 = OpVariable %7 Function
+         %59 = OpVariable %7 Function
+         %63 = OpVariable %19 Function
+         %67 = OpVariable %19 Function
+         %71 = OpVariable %19 Function
+         %75 = OpVariable %19 Function
+         %79 = OpVariable %32 Function
+         %83 = OpVariable %32 Function
+         %87 = OpVariable %32 Function
+         %91 = OpVariable %32 Function
+               OpStore %8 %9
+               OpStore %10 %11
+         %15 = OpLoad %6 %8
+         %16 = OpLoad %6 %10
+         %17 = OpCompositeConstruct %12 %15 %16
+               OpStore %14 %17
+               OpStore %20 %21
+               OpStore %22 %23
+         %27 = OpLoad %18 %20
+         %28 = OpLoad %18 %20
+         %29 = OpLoad %18 %22
+         %30 = OpCompositeConstruct %24 %27 %28 %29
+               OpStore %26 %30
+               OpStore %33 %34
+               OpStore %35 %36
+         %40 = OpLoad %31 %33
+         %41 = OpLoad %31 %33
+         %42 = OpLoad %31 %35
+         %43 = OpLoad %31 %35
+         %44 = OpCompositeConstruct %37 %40 %41 %42 %43
+         %45 = OpLoad %37 %39
+         %46 = OpVectorShuffle %37 %45 %44 5 6 7 4
+               OpStore %39 %46
+         %48 = OpLoad %6 %8
+         %49 = OpLoad %6 %10
+        %100 = OpCompositeConstruct %12 %48 %48
+        %101 = OpCompositeConstruct %12 %49 %49
+         %50 = OpIAdd %6 %48 %49
+               OpStore %47 %50
+         %52 = OpLoad %6 %8
+         %53 = OpLoad %6 %10
+         %54 = OpISub %6 %52 %53
+               OpStore %51 %54
+         %56 = OpLoad %6 %8
+         %57 = OpLoad %6 %10
+         %58 = OpIMul %6 %56 %57
+               OpStore %55 %58
+         %60 = OpLoad %6 %8
+         %61 = OpLoad %6 %10
+         %62 = OpSDiv %6 %60 %61
+               OpStore %59 %62
+         %64 = OpLoad %18 %20
+         %65 = OpLoad %18 %22
+         %66 = OpIAdd %18 %64 %65
+               OpStore %63 %66
+         %68 = OpLoad %18 %20
+         %69 = OpLoad %18 %22
+         %70 = OpISub %18 %68 %69
+               OpStore %67 %70
+         %72 = OpLoad %18 %20
+         %73 = OpLoad %18 %22
+         %74 = OpIMul %18 %72 %73
+               OpStore %71 %74
+         %76 = OpLoad %18 %20
+         %77 = OpLoad %18 %22
+         %78 = OpUDiv %18 %76 %77
+               OpStore %75 %78
+         %80 = OpLoad %31 %33
+         %81 = OpLoad %31 %35
+         %82 = OpFAdd %31 %80 %81
+               OpStore %79 %82
+         %84 = OpLoad %31 %33
+         %85 = OpLoad %31 %35
+         %86 = OpFSub %31 %84 %85
+               OpStore %83 %86
+         %88 = OpLoad %31 %33
+         %89 = OpLoad %31 %35
+         %90 = OpFMul %31 %88 %89
+               OpStore %87 %90
+         %92 = OpLoad %31 %33
+         %93 = OpLoad %31 %35
+         %94 = OpFDiv %31 %92 %93
+               OpStore %91 %94
+               OpReturn
+               OpFunctionEnd
+  )";
+  const auto env = SPV_ENV_UNIVERSAL_1_3;
+  const auto consumer = nullptr;
+  const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
+  spvtools::ValidatorOptions validator_options;
+
+  // Check context validity.
+  ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
+                                               kConsoleMessageConsumer));
+
+  TransformationContext transformation_context(
+      MakeUnique<FactManager>(context.get()), validator_options);
+
+  // Vec Type Id |   Vector Type  |  Element Type id |   Element Type  |
+  // ------------+----------------+------------------+-----------------+
+  //     12      |      vec2      |         6        |      int32      |
+  //     24      |      vec3      |        18        |     uint32      |
+  //     37      |      vec4      |        31        |      float      |
+
+  // Instruction Id | Opcode  | Type Id | constant id 1 | constant id 2 |
+  // ---------------+---------+---------+---------------+---------------+
+  //       50       | OpIAdd  |    6    |      48       |      49       |
+  //       54       | OpISub  |    6    |      52       |      53       |
+  //       58       | OpIMul  |    6    |      56       |      57       |
+  //       62       | OpSDiv  |    6    |      60       |      61       |
+  //       66       | OpIAdd  |    18   |      64       |      65       |
+  //       70       | OpISub  |    18   |      68       |      69       |
+  //       74       | OpIMul  |    18   |      72       |      73       |
+  //       78       | OpUDiv  |    18   |      76       |      77       |
+  //       82       | OpFAdd  |    31   |      80       |      81       |
+  //       86       | OpFSub  |    31   |      84       |      85       |
+  //       90       | OpFMul  |    31   |      88       |      89       |
+  //       94       | OpFDiv  |    31   |      92       |      93       |
+
+  // Assert that the target scalar instruction result id is relevant.
+  ASSERT_FALSE(transformation_context.GetFactManager()->IdIsIrrelevant(50));
+  transformation_context.GetFactManager()->AddFactDataSynonym(
+      MakeDataDescriptor(100, {1}), MakeDataDescriptor(48, {}));
+  transformation_context.GetFactManager()->AddFactDataSynonym(
+      MakeDataDescriptor(101, {1}), MakeDataDescriptor(49, {}));
+
+  // The following are all invalid use.
+  {
+    // Bad: Instruction id does not exist.
+    TransformationWrapVectorSynonym wrap_add_int_bad1(103, 100, 101, 102, 1);
+    ASSERT_FALSE(
+        wrap_add_int_bad1.IsApplicable(context.get(), transformation_context));
+
+    // Bad: Instruction id given is not of a valid arithmetic operation typed
+    // instruction.
+    TransformationWrapVectorSynonym wrap_add_int_bad2(80, 100, 101, 102, 1);
+    ASSERT_FALSE(
+        wrap_add_int_bad1.IsApplicable(context.get(), transformation_context));
+
+    // Bad: the id for the first vector does not exist.
+    TransformationWrapVectorSynonym wrap_add_int_bad3(50, 105, 101, 102, 1);
+    ASSERT_FALSE(
+        wrap_add_int_bad3.IsApplicable(context.get(), transformation_context));
+
+    // Bad: the id for the second vector does not exist.
+    TransformationWrapVectorSynonym wrap_add_int_bad4(50, 100, 105, 102, 1);
+    ASSERT_FALSE(
+        wrap_add_int_bad4.IsApplicable(context.get(), transformation_context));
+
+    // Bad: vector id is not fresh.
+    TransformationWrapVectorSynonym wrap_add_int_bad6(50, 100, 101, 94, 1);
+    ASSERT_FALSE(
+        wrap_add_int_bad6.IsApplicable(context.get(), transformation_context));
+
+    // Bad: The position goes out of bound for the given vector type.
+    TransformationWrapVectorSynonym wrap_add_int_bad8(50, 100, 101, 102, 2);
+    ASSERT_FALSE(
+        wrap_add_int_bad8.IsApplicable(context.get(), transformation_context));
+
+    // Bad: The original instruction is not a valid scalar operation
+    // instruction.
+    TransformationWrapVectorSynonym wrap_add_int(27, 100, 101, 102, 1);
+    ASSERT_FALSE(
+        wrap_add_int.IsApplicable(context.get(), transformation_context));
+  }
+
+  // Good: The following transformation should be applicable.
+  TransformationWrapVectorSynonym wrap_add_int(50, 100, 101, 102, 1);
+  ASSERT_TRUE(wrap_add_int.IsApplicable(context.get(), transformation_context));
+  // Insert an arithmetic instruction of the same type to add two vectors.
+  ApplyAndCheckFreshIds(wrap_add_int, context.get(), &transformation_context);
+
+  // |instruction_id| and id at |scalar_position of the result vector should be
+  // synonyms.
+  ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
+      MakeDataDescriptor(102, {1}), MakeDataDescriptor(50, {})));
+
+  // After applying transformations, the instruction:
+  //
+  // %102 = OpIAdd %12 %100 %101
+  //
+  // should be added before:
+  //
+  // %50 = OpIAdd %6 %48 %49
+  std::string after_transformation = R"(
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %4 "main" %97
+               OpExecutionMode %4 OriginUpperLeft
+               OpSource ESSL 310
+               OpName %4 "main"
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeInt 32 1
+          %7 = OpTypePointer Function %6
+          %9 = OpConstant %6 10
+         %11 = OpConstant %6 -5
+         %12 = OpTypeVector %6 2
+         %13 = OpTypePointer Function %12
+         %18 = OpTypeInt 32 0
+         %19 = OpTypePointer Function %18
+         %21 = OpConstant %18 8
+         %23 = OpConstant %18 2
+         %24 = OpTypeVector %18 3
+         %25 = OpTypePointer Function %24
+         %31 = OpTypeFloat 32
+         %32 = OpTypePointer Function %31
+         %34 = OpConstant %31 3.29999995
+         %36 = OpConstant %31 1.10000002
+         %37 = OpTypeVector %31 4
+         %38 = OpTypePointer Function %37
+         %96 = OpTypePointer Input %31
+         %97 = OpVariable %96 Input
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+          %8 = OpVariable %7 Function
+         %10 = OpVariable %7 Function
+         %14 = OpVariable %13 Function
+         %20 = OpVariable %19 Function
+         %22 = OpVariable %19 Function
+         %26 = OpVariable %25 Function
+         %33 = OpVariable %32 Function
+         %35 = OpVariable %32 Function
+         %39 = OpVariable %38 Function
+         %47 = OpVariable %7 Function
+         %51 = OpVariable %7 Function
+         %55 = OpVariable %7 Function
+         %59 = OpVariable %7 Function
+         %63 = OpVariable %19 Function
+         %67 = OpVariable %19 Function
+         %71 = OpVariable %19 Function
+         %75 = OpVariable %19 Function
+         %79 = OpVariable %32 Function
+         %83 = OpVariable %32 Function
+         %87 = OpVariable %32 Function
+         %91 = OpVariable %32 Function
+               OpStore %8 %9
+               OpStore %10 %11
+         %15 = OpLoad %6 %8
+         %16 = OpLoad %6 %10
+         %17 = OpCompositeConstruct %12 %15 %16
+               OpStore %14 %17
+               OpStore %20 %21
+               OpStore %22 %23
+         %27 = OpLoad %18 %20
+         %28 = OpLoad %18 %20
+         %29 = OpLoad %18 %22
+         %30 = OpCompositeConstruct %24 %27 %28 %29
+               OpStore %26 %30
+               OpStore %33 %34
+               OpStore %35 %36
+         %40 = OpLoad %31 %33
+         %41 = OpLoad %31 %33
+         %42 = OpLoad %31 %35
+         %43 = OpLoad %31 %35
+         %44 = OpCompositeConstruct %37 %40 %41 %42 %43
+         %45 = OpLoad %37 %39
+         %46 = OpVectorShuffle %37 %45 %44 5 6 7 4
+               OpStore %39 %46
+         %48 = OpLoad %6 %8
+         %49 = OpLoad %6 %10
+        %100 = OpCompositeConstruct %12 %48 %48
+        %101 = OpCompositeConstruct %12 %49 %49
+        %102 = OpIAdd %12 %100 %101
+         %50 = OpIAdd %6 %48 %49
+               OpStore %47 %50
+         %52 = OpLoad %6 %8
+         %53 = OpLoad %6 %10
+         %54 = OpISub %6 %52 %53
+               OpStore %51 %54
+         %56 = OpLoad %6 %8
+         %57 = OpLoad %6 %10
+         %58 = OpIMul %6 %56 %57
+               OpStore %55 %58
+         %60 = OpLoad %6 %8
+         %61 = OpLoad %6 %10
+         %62 = OpSDiv %6 %60 %61
+               OpStore %59 %62
+         %64 = OpLoad %18 %20
+         %65 = OpLoad %18 %22
+         %66 = OpIAdd %18 %64 %65
+               OpStore %63 %66
+         %68 = OpLoad %18 %20
+         %69 = OpLoad %18 %22
+         %70 = OpISub %18 %68 %69
+               OpStore %67 %70
+         %72 = OpLoad %18 %20
+         %73 = OpLoad %18 %22
+         %74 = OpIMul %18 %72 %73
+               OpStore %71 %74
+         %76 = OpLoad %18 %20
+         %77 = OpLoad %18 %22
+         %78 = OpUDiv %18 %76 %77
+               OpStore %75 %78
+         %80 = OpLoad %31 %33
+         %81 = OpLoad %31 %35
+         %82 = OpFAdd %31 %80 %81
+               OpStore %79 %82
+         %84 = OpLoad %31 %33
+         %85 = OpLoad %31 %35
+         %86 = OpFSub %31 %84 %85
+               OpStore %83 %86
+         %88 = OpLoad %31 %33
+         %89 = OpLoad %31 %35
+         %90 = OpFMul %31 %88 %89
+               OpStore %87 %90
+         %92 = OpLoad %31 %33
+         %93 = OpLoad %31 %35
+         %94 = OpFDiv %31 %92 %93
+               OpStore %91 %94
+               OpReturn
+               OpFunctionEnd
+  )";
+  ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
+}
+
+TEST(TransformationWrapVectorSynonym, OperationSupportTest) {
+  std::string shader = R"(
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %4 "main" %97
+               OpExecutionMode %4 OriginUpperLeft
+               OpSource ESSL 310
+               OpName %4 "main"
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeInt 32 1
+          %7 = OpTypePointer Function %6
+          %9 = OpConstant %6 10
+         %11 = OpConstant %6 -5
+         %12 = OpTypeVector %6 2
+         %13 = OpTypePointer Function %12
+         %18 = OpTypeInt 32 0
+         %19 = OpTypePointer Function %18
+         %21 = OpConstant %18 8
+         %23 = OpConstant %18 2
+         %24 = OpTypeVector %18 3
+         %25 = OpTypePointer Function %24
+         %31 = OpTypeFloat 32
+         %32 = OpTypePointer Function %31
+         %34 = OpConstant %31 3.29999995
+         %36 = OpConstant %31 1.10000002
+         %37 = OpTypeVector %31 4
+         %38 = OpTypePointer Function %37
+         %96 = OpTypePointer Input %31
+         %97 = OpVariable %96 Input
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+          %8 = OpVariable %7 Function
+         %10 = OpVariable %7 Function
+         %14 = OpVariable %13 Function
+         %20 = OpVariable %19 Function
+         %22 = OpVariable %19 Function
+         %26 = OpVariable %25 Function
+         %33 = OpVariable %32 Function
+         %35 = OpVariable %32 Function
+         %39 = OpVariable %38 Function
+         %47 = OpVariable %7 Function
+         %51 = OpVariable %7 Function
+         %55 = OpVariable %7 Function
+         %59 = OpVariable %7 Function
+         %63 = OpVariable %19 Function
+         %67 = OpVariable %19 Function
+         %71 = OpVariable %19 Function
+         %75 = OpVariable %19 Function
+         %79 = OpVariable %32 Function
+         %83 = OpVariable %32 Function
+         %87 = OpVariable %32 Function
+         %91 = OpVariable %32 Function
+               OpStore %8 %9
+               OpStore %10 %11
+         %15 = OpLoad %6 %8
+         %16 = OpLoad %6 %10
+         %17 = OpCompositeConstruct %12 %15 %16
+               OpStore %14 %17
+               OpStore %20 %21
+               OpStore %22 %23
+         %27 = OpLoad %18 %20
+         %28 = OpLoad %18 %20
+         %29 = OpLoad %18 %22
+         %30 = OpCompositeConstruct %24 %27 %28 %29
+               OpStore %26 %30
+               OpStore %33 %34
+               OpStore %35 %36
+         %40 = OpLoad %31 %33
+         %41 = OpLoad %31 %33
+         %42 = OpLoad %31 %35
+         %43 = OpLoad %31 %35
+         %44 = OpCompositeConstruct %37 %40 %41 %42 %43
+         %45 = OpLoad %37 %39
+         %46 = OpVectorShuffle %37 %45 %44 5 6 7 4
+               OpStore %39 %46
+         %48 = OpLoad %6 %8
+         %49 = OpLoad %6 %10
+         %50 = OpIAdd %6 %48 %49
+               OpStore %47 %50
+         %52 = OpLoad %6 %8
+         %53 = OpLoad %6 %10
+        %100 = OpCompositeConstruct %12 %52 %52
+        %101 = OpCompositeConstruct %12 %53 %53
+         %54 = OpISub %6 %52 %53
+               OpStore %51 %54
+         %56 = OpLoad %6 %8
+         %57 = OpLoad %6 %10
+        %103 = OpCompositeConstruct %12 %56 %56
+        %104 = OpCompositeConstruct %12 %57 %57
+         %58 = OpIMul %6 %56 %57
+               OpStore %55 %58
+         %60 = OpLoad %6 %8
+         %61 = OpLoad %6 %10
+         %62 = OpSDiv %6 %60 %61
+               OpStore %59 %62
+         %64 = OpLoad %18 %20
+         %65 = OpLoad %18 %22
+        %106 = OpCompositeConstruct %24 %64 %64 %64
+        %107 = OpCompositeConstruct %24 %65 %65 %65
+         %66 = OpIAdd %18 %64 %65
+               OpStore %63 %66
+         %68 = OpLoad %18 %20
+         %69 = OpLoad %18 %22
+        %109 = OpCompositeConstruct %24 %68 %68 %68
+        %110 = OpCompositeConstruct %24 %69 %69 %69
+         %70 = OpISub %18 %68 %69
+               OpStore %67 %70
+         %72 = OpLoad %18 %20
+         %73 = OpLoad %18 %22
+        %112 = OpCompositeConstruct %24 %72 %72 %72
+        %113 = OpCompositeConstruct %24 %73 %73 %73
+         %74 = OpIMul %18 %72 %73
+               OpStore %71 %74
+         %76 = OpLoad %18 %20
+         %77 = OpLoad %18 %22
+         %78 = OpUDiv %18 %76 %77
+               OpStore %75 %78
+         %80 = OpLoad %31 %33
+         %81 = OpLoad %31 %35
+        %115 = OpCompositeConstruct %37 %80 %80 %80 %80
+        %116 = OpCompositeConstruct %37 %81 %81 %81 %81
+         %82 = OpFAdd %31 %80 %81
+               OpStore %79 %82
+         %84 = OpLoad %31 %33
+         %85 = OpLoad %31 %35
+        %118 = OpCompositeConstruct %37 %84 %84 %84 %84
+        %119 = OpCompositeConstruct %37 %85 %85 %85 %85
+         %86 = OpFSub %31 %84 %85
+               OpStore %83 %86
+         %88 = OpLoad %31 %33
+         %89 = OpLoad %31 %35
+        %121 = OpCompositeConstruct %37 %88 %88 %88 %88
+        %122 = OpCompositeConstruct %37 %89 %89 %89 %89
+         %90 = OpFMul %31 %88 %89
+               OpStore %87 %90
+         %92 = OpLoad %31 %33
+         %93 = OpLoad %31 %35
+         %94 = OpFDiv %31 %92 %93
+               OpStore %91 %94
+               OpReturn
+               OpFunctionEnd
+  )";
+  const auto env = SPV_ENV_UNIVERSAL_1_3;
+  const auto consumer = nullptr;
+  const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
+  spvtools::ValidatorOptions validator_options;
+
+  ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
+                                               kConsoleMessageConsumer));
+
+  TransformationContext transformation_context(
+      MakeUnique<FactManager>(context.get()), validator_options);
+
+  {
+    // Add synonym facts between the vector operands at pos and the operands to
+    // the scalar instruction.
+    transformation_context.GetFactManager()->AddFactDataSynonym(
+        MakeDataDescriptor(100, {1}), MakeDataDescriptor(52, {}));
+    transformation_context.GetFactManager()->AddFactDataSynonym(
+        MakeDataDescriptor(101, {1}), MakeDataDescriptor(53, {}));
+
+    transformation_context.GetFactManager()->AddFactDataSynonym(
+        MakeDataDescriptor(103, {0}), MakeDataDescriptor(56, {}));
+    transformation_context.GetFactManager()->AddFactDataSynonym(
+        MakeDataDescriptor(104, {0}), MakeDataDescriptor(57, {}));
+
+    transformation_context.GetFactManager()->AddFactDataSynonym(
+        MakeDataDescriptor(106, {2}), MakeDataDescriptor(64, {}));
+    transformation_context.GetFactManager()->AddFactDataSynonym(
+        MakeDataDescriptor(107, {2}), MakeDataDescriptor(65, {}));
+
+    transformation_context.GetFactManager()->AddFactDataSynonym(
+        MakeDataDescriptor(109, {2}), MakeDataDescriptor(68, {}));
+    transformation_context.GetFactManager()->AddFactDataSynonym(
+        MakeDataDescriptor(110, {2}), MakeDataDescriptor(69, {}));
+
+    transformation_context.GetFactManager()->AddFactDataSynonym(
+        MakeDataDescriptor(112, {1}), MakeDataDescriptor(72, {}));
+    transformation_context.GetFactManager()->AddFactDataSynonym(
+        MakeDataDescriptor(113, {1}), MakeDataDescriptor(73, {}));
+
+    transformation_context.GetFactManager()->AddFactDataSynonym(
+        MakeDataDescriptor(115, {2}), MakeDataDescriptor(80, {}));
+    transformation_context.GetFactManager()->AddFactDataSynonym(
+        MakeDataDescriptor(116, {2}), MakeDataDescriptor(81, {}));
+
+    transformation_context.GetFactManager()->AddFactDataSynonym(
+        MakeDataDescriptor(118, {3}), MakeDataDescriptor(84, {}));
+    transformation_context.GetFactManager()->AddFactDataSynonym(
+        MakeDataDescriptor(119, {3}), MakeDataDescriptor(85, {}));
+
+    transformation_context.GetFactManager()->AddFactDataSynonym(
+        MakeDataDescriptor(121, {1}), MakeDataDescriptor(88, {}));
+    transformation_context.GetFactManager()->AddFactDataSynonym(
+        MakeDataDescriptor(122, {1}), MakeDataDescriptor(89, {}));
+  }
+
+  // Test OpISub for signed integer.
+  {
+    // Good: The following transformation should be applicable.
+    TransformationWrapVectorSynonym wrap_sub_int(54, 100, 101, 102, 1);
+    ASSERT_TRUE(
+        wrap_sub_int.IsApplicable(context.get(), transformation_context));
+    ApplyAndCheckFreshIds(wrap_sub_int, context.get(), &transformation_context);
+
+    // |instruction_id| and id at |scalar_position of the result vector should
+    // be synonyms.
+    ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
+        MakeDataDescriptor(102, {1}), MakeDataDescriptor(54, {})));
+  }
+
+  // Test OpIMul for signed integer.
+  {
+    // Good: The following transformation should be applicable.
+    TransformationWrapVectorSynonym wrap_mul_int(58, 103, 104, 105, 0);
+    ASSERT_TRUE(
+        wrap_mul_int.IsApplicable(context.get(), transformation_context));
+    ApplyAndCheckFreshIds(wrap_mul_int, context.get(), &transformation_context);
+
+    // |instruction_id| and id at |scalar_position of the result vector should
+    // be synonyms.
+    ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
+        MakeDataDescriptor(105, {0}), MakeDataDescriptor(58, {})));
+  }
+
+  // Test OpIAdd for unsigned integer.
+  {
+    // Good: The following transformation should be applicable.
+    TransformationWrapVectorSynonym wrap_add_uint(66, 106, 107, 108, 2);
+    ASSERT_TRUE(
+        wrap_add_uint.IsApplicable(context.get(), transformation_context));
+    ApplyAndCheckFreshIds(wrap_add_uint, context.get(),
+                          &transformation_context);
+
+    // |instruction_id| and id at |scalar_position of the result vector should
+    // be synonyms.
+    ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
+        MakeDataDescriptor(108, {2}), MakeDataDescriptor(66, {})));
+  }
+
+  // Test OpISub for signed integer.
+  {
+    // Good: The following transformation should be applicable.
+    TransformationWrapVectorSynonym wrap_sub_uint(70, 109, 110, 111, 2);
+    ASSERT_TRUE(
+        wrap_sub_uint.IsApplicable(context.get(), transformation_context));
+    ApplyAndCheckFreshIds(wrap_sub_uint, context.get(),
+                          &transformation_context);
+
+    // |instruction_id| and id at |scalar_position of the result vector should
+    // be synonyms.
+    ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
+        MakeDataDescriptor(111, {2}), MakeDataDescriptor(70, {})));
+  }
+
+  // Test OpIMul for signed integer.
+  {
+    // Good: The following transformation should be applicable.
+    TransformationWrapVectorSynonym wrap_mul_uint(74, 112, 113, 114, 1);
+    ASSERT_TRUE(
+        wrap_mul_uint.IsApplicable(context.get(), transformation_context));
+    ApplyAndCheckFreshIds(wrap_mul_uint, context.get(),
+                          &transformation_context);
+
+    // |instruction_id| and id at |scalar_position of the result vector should
+    // be synonyms.
+    ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
+        MakeDataDescriptor(114, {1}), MakeDataDescriptor(74, {})));
+  }
+
+  // Test OpFAdd for float.
+  {
+    // Good: The following transformation should be applicable.
+    TransformationWrapVectorSynonym wrap_add_float(82, 115, 116, 117, 2);
+    ASSERT_TRUE(
+        wrap_add_float.IsApplicable(context.get(), transformation_context));
+    ApplyAndCheckFreshIds(wrap_add_float, context.get(),
+                          &transformation_context);
+
+    // |instruction_id| and id at |scalar_position of the result vector should
+    // be synonyms.
+    ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
+        MakeDataDescriptor(117, {2}), MakeDataDescriptor(82, {})));
+  }
+
+  // Test OpFSub for float.
+  {
+    // Good: The following transformation should be applicable.
+    TransformationWrapVectorSynonym wrap_add_float(86, 118, 119, 120, 3);
+    ASSERT_TRUE(
+        wrap_add_float.IsApplicable(context.get(), transformation_context));
+    ApplyAndCheckFreshIds(wrap_add_float, context.get(),
+                          &transformation_context);
+
+    // |instruction_id| and id at |scalar_position of the result vector should
+    // be synonyms.
+    ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
+        MakeDataDescriptor(120, {3}), MakeDataDescriptor(86, {})));
+  }
+
+  // Test OpFMul for float.
+  {
+    // Good: The following transformation should be applicable.
+    TransformationWrapVectorSynonym wrap_mul_float(90, 121, 122, 123, 1);
+    ASSERT_TRUE(
+        wrap_mul_float.IsApplicable(context.get(), transformation_context));
+    ApplyAndCheckFreshIds(wrap_mul_float, context.get(),
+                          &transformation_context);
+
+    // |instruction_id| and id at |scalar_position of the result vector should
+    // be synonyms.
+    ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
+        MakeDataDescriptor(123, {1}), MakeDataDescriptor(90, {})));
+  }
+
+  std::string after_transformation = R"(
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %4 "main" %97
+               OpExecutionMode %4 OriginUpperLeft
+               OpSource ESSL 310
+               OpName %4 "main"
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeInt 32 1
+          %7 = OpTypePointer Function %6
+          %9 = OpConstant %6 10
+         %11 = OpConstant %6 -5
+         %12 = OpTypeVector %6 2
+         %13 = OpTypePointer Function %12
+         %18 = OpTypeInt 32 0
+         %19 = OpTypePointer Function %18
+         %21 = OpConstant %18 8
+         %23 = OpConstant %18 2
+         %24 = OpTypeVector %18 3
+         %25 = OpTypePointer Function %24
+         %31 = OpTypeFloat 32
+         %32 = OpTypePointer Function %31
+         %34 = OpConstant %31 3.29999995
+         %36 = OpConstant %31 1.10000002
+         %37 = OpTypeVector %31 4
+         %38 = OpTypePointer Function %37
+         %96 = OpTypePointer Input %31
+         %97 = OpVariable %96 Input
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+          %8 = OpVariable %7 Function
+         %10 = OpVariable %7 Function
+         %14 = OpVariable %13 Function
+         %20 = OpVariable %19 Function
+         %22 = OpVariable %19 Function
+         %26 = OpVariable %25 Function
+         %33 = OpVariable %32 Function
+         %35 = OpVariable %32 Function
+         %39 = OpVariable %38 Function
+         %47 = OpVariable %7 Function
+         %51 = OpVariable %7 Function
+         %55 = OpVariable %7 Function
+         %59 = OpVariable %7 Function
+         %63 = OpVariable %19 Function
+         %67 = OpVariable %19 Function
+         %71 = OpVariable %19 Function
+         %75 = OpVariable %19 Function
+         %79 = OpVariable %32 Function
+         %83 = OpVariable %32 Function
+         %87 = OpVariable %32 Function
+         %91 = OpVariable %32 Function
+               OpStore %8 %9
+               OpStore %10 %11
+         %15 = OpLoad %6 %8
+         %16 = OpLoad %6 %10
+         %17 = OpCompositeConstruct %12 %15 %16
+               OpStore %14 %17
+               OpStore %20 %21
+               OpStore %22 %23
+         %27 = OpLoad %18 %20
+         %28 = OpLoad %18 %20
+         %29 = OpLoad %18 %22
+         %30 = OpCompositeConstruct %24 %27 %28 %29
+               OpStore %26 %30
+               OpStore %33 %34
+               OpStore %35 %36
+         %40 = OpLoad %31 %33
+         %41 = OpLoad %31 %33
+         %42 = OpLoad %31 %35
+         %43 = OpLoad %31 %35
+         %44 = OpCompositeConstruct %37 %40 %41 %42 %43
+         %45 = OpLoad %37 %39
+         %46 = OpVectorShuffle %37 %45 %44 5 6 7 4
+               OpStore %39 %46
+         %48 = OpLoad %6 %8
+         %49 = OpLoad %6 %10
+         %50 = OpIAdd %6 %48 %49
+               OpStore %47 %50
+         %52 = OpLoad %6 %8
+         %53 = OpLoad %6 %10
+        %100 = OpCompositeConstruct %12 %52 %52
+        %101 = OpCompositeConstruct %12 %53 %53
+        %102 = OpISub %12 %100 %101
+         %54 = OpISub %6 %52 %53
+               OpStore %51 %54
+         %56 = OpLoad %6 %8
+         %57 = OpLoad %6 %10
+        %103 = OpCompositeConstruct %12 %56 %56
+        %104 = OpCompositeConstruct %12 %57 %57
+        %105 = OpIMul %12 %103 %104
+         %58 = OpIMul %6 %56 %57
+               OpStore %55 %58
+         %60 = OpLoad %6 %8
+         %61 = OpLoad %6 %10
+         %62 = OpSDiv %6 %60 %61
+               OpStore %59 %62
+         %64 = OpLoad %18 %20
+         %65 = OpLoad %18 %22
+        %106 = OpCompositeConstruct %24 %64 %64 %64
+        %107 = OpCompositeConstruct %24 %65 %65 %65
+        %108 = OpIAdd %24 %106 %107
+         %66 = OpIAdd %18 %64 %65
+               OpStore %63 %66
+         %68 = OpLoad %18 %20
+         %69 = OpLoad %18 %22
+        %109 = OpCompositeConstruct %24 %68 %68 %68
+        %110 = OpCompositeConstruct %24 %69 %69 %69
+        %111 = OpISub %24 %109 %110
+         %70 = OpISub %18 %68 %69
+               OpStore %67 %70
+         %72 = OpLoad %18 %20
+         %73 = OpLoad %18 %22
+        %112 = OpCompositeConstruct %24 %72 %72 %72
+        %113 = OpCompositeConstruct %24 %73 %73 %73
+        %114 = OpIMul %24 %112 %113
+         %74 = OpIMul %18 %72 %73
+               OpStore %71 %74
+         %76 = OpLoad %18 %20
+         %77 = OpLoad %18 %22
+         %78 = OpUDiv %18 %76 %77
+               OpStore %75 %78
+         %80 = OpLoad %31 %33
+         %81 = OpLoad %31 %35
+        %115 = OpCompositeConstruct %37 %80 %80 %80 %80
+        %116 = OpCompositeConstruct %37 %81 %81 %81 %81
+        %117 = OpFAdd %37 %115 %116
+         %82 = OpFAdd %31 %80 %81
+               OpStore %79 %82
+         %84 = OpLoad %31 %33
+         %85 = OpLoad %31 %35
+        %118 = OpCompositeConstruct %37 %84 %84 %84 %84
+        %119 = OpCompositeConstruct %37 %85 %85 %85 %85
+        %120 = OpFSub %37 %118 %119
+         %86 = OpFSub %31 %84 %85
+               OpStore %83 %86
+         %88 = OpLoad %31 %33
+         %89 = OpLoad %31 %35
+        %121 = OpCompositeConstruct %37 %88 %88 %88 %88
+        %122 = OpCompositeConstruct %37 %89 %89 %89 %89
+        %123 = OpFMul %37 %121 %122
+         %90 = OpFMul %31 %88 %89
+               OpStore %87 %90
+         %92 = OpLoad %31 %33
+         %93 = OpLoad %31 %35
+         %94 = OpFDiv %31 %92 %93
+               OpStore %91 %94
+               OpReturn
+               OpFunctionEnd
+  )";
+  ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
+}
+
+TEST(TransformationWrapVectorSynonym, DivSupportTest) {
+  std::string shader = R"(
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %4 "main" %97
+               OpExecutionMode %4 OriginUpperLeft
+               OpSource ESSL 310
+               OpName %4 "main"
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeInt 32 1
+          %7 = OpTypePointer Function %6
+          %9 = OpConstant %6 10
+         %11 = OpConstant %6 -5
+         %12 = OpTypeVector %6 2
+         %13 = OpTypePointer Function %12
+         %18 = OpTypeInt 32 0
+         %19 = OpTypePointer Function %18
+         %21 = OpConstant %18 8
+         %23 = OpConstant %18 2
+         %24 = OpTypeVector %18 3
+         %25 = OpTypePointer Function %24
+         %31 = OpTypeFloat 32
+         %32 = OpTypePointer Function %31
+         %34 = OpConstant %31 3.29999995
+         %36 = OpConstant %31 1.10000002
+         %37 = OpTypeVector %31 4
+         %38 = OpTypePointer Function %37
+         %96 = OpTypePointer Input %31
+         %97 = OpVariable %96 Input
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+          %8 = OpVariable %7 Function
+         %10 = OpVariable %7 Function
+         %14 = OpVariable %13 Function
+         %20 = OpVariable %19 Function
+         %22 = OpVariable %19 Function
+         %26 = OpVariable %25 Function
+         %33 = OpVariable %32 Function
+         %35 = OpVariable %32 Function
+         %39 = OpVariable %38 Function
+         %47 = OpVariable %7 Function
+         %51 = OpVariable %7 Function
+         %55 = OpVariable %7 Function
+         %59 = OpVariable %7 Function
+         %63 = OpVariable %19 Function
+         %67 = OpVariable %19 Function
+         %71 = OpVariable %19 Function
+         %75 = OpVariable %19 Function
+         %79 = OpVariable %32 Function
+         %83 = OpVariable %32 Function
+         %87 = OpVariable %32 Function
+         %91 = OpVariable %32 Function
+               OpStore %8 %9
+               OpStore %10 %11
+         %15 = OpLoad %6 %8
+         %16 = OpLoad %6 %10
+         %17 = OpCompositeConstruct %12 %15 %16
+               OpStore %14 %17
+               OpStore %20 %21
+               OpStore %22 %23
+         %27 = OpLoad %18 %20
+         %28 = OpLoad %18 %20
+         %29 = OpLoad %18 %22
+         %30 = OpCompositeConstruct %24 %27 %28 %29
+               OpStore %26 %30
+               OpStore %33 %34
+               OpStore %35 %36
+         %40 = OpLoad %31 %33
+         %41 = OpLoad %31 %33
+         %42 = OpLoad %31 %35
+         %43 = OpLoad %31 %35
+         %44 = OpCompositeConstruct %37 %40 %41 %42 %43
+         %45 = OpLoad %37 %39
+         %46 = OpVectorShuffle %37 %45 %44 5 6 7 4
+               OpStore %39 %46
+         %48 = OpLoad %6 %8
+         %49 = OpLoad %6 %10
+         %50 = OpIAdd %6 %48 %49
+               OpStore %47 %50
+         %52 = OpLoad %6 %8
+         %53 = OpLoad %6 %10
+         %54 = OpISub %6 %52 %53
+               OpStore %51 %54
+         %56 = OpLoad %6 %8
+         %57 = OpLoad %6 %10
+         %58 = OpIMul %6 %56 %57
+               OpStore %55 %58
+         %60 = OpLoad %6 %8
+         %61 = OpLoad %6 %10
+        %100 = OpCompositeConstruct %12 %60 %60
+        %101 = OpCompositeConstruct %12 %61 %61
+         %62 = OpSDiv %6 %60 %61
+               OpStore %59 %62
+         %64 = OpLoad %18 %20
+         %65 = OpLoad %18 %22
+         %66 = OpIAdd %18 %64 %65
+               OpStore %63 %66
+         %68 = OpLoad %18 %20
+         %69 = OpLoad %18 %22
+         %70 = OpISub %18 %68 %69
+               OpStore %67 %70
+         %72 = OpLoad %18 %20
+         %73 = OpLoad %18 %22
+         %74 = OpIMul %18 %72 %73
+               OpStore %71 %74
+         %76 = OpLoad %18 %20
+         %77 = OpLoad %18 %22
+        %102 = OpCompositeConstruct %24 %76 %76 %76
+        %103 = OpCompositeConstruct %24 %77 %77 %77
+         %78 = OpUDiv %18 %76 %77
+               OpStore %75 %78
+         %80 = OpLoad %31 %33
+         %81 = OpLoad %31 %35
+         %82 = OpFAdd %31 %80 %81
+               OpStore %79 %82
+         %84 = OpLoad %31 %33
+         %85 = OpLoad %31 %35
+         %86 = OpFSub %31 %84 %85
+               OpStore %83 %86
+         %88 = OpLoad %31 %33
+         %89 = OpLoad %31 %35
+         %90 = OpFMul %31 %88 %89
+               OpStore %87 %90
+         %92 = OpLoad %31 %33
+         %93 = OpLoad %31 %35
+        %104 = OpCompositeConstruct %37 %92 %92 %92 %92
+        %105 = OpCompositeConstruct %37 %93 %93 %93 %93
+         %94 = OpFDiv %31 %92 %93
+               OpStore %91 %94
+               OpReturn
+               OpFunctionEnd
+  )";
+  const auto env = SPV_ENV_UNIVERSAL_1_3;
+  const auto consumer = nullptr;
+  const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
+  spvtools::ValidatorOptions validator_options;
+
+  ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
+                                               kConsoleMessageConsumer));
+
+  TransformationContext transformation_context(
+      MakeUnique<FactManager>(context.get()), validator_options);
+
+  transformation_context.GetFactManager()->AddFactDataSynonym(
+      MakeDataDescriptor(100, {1}), MakeDataDescriptor(60, {}));
+  transformation_context.GetFactManager()->AddFactDataSynonym(
+      MakeDataDescriptor(101, {1}), MakeDataDescriptor(61, {}));
+
+  transformation_context.GetFactManager()->AddFactDataSynonym(
+      MakeDataDescriptor(102, {1}), MakeDataDescriptor(76, {}));
+  transformation_context.GetFactManager()->AddFactDataSynonym(
+      MakeDataDescriptor(103, {1}), MakeDataDescriptor(77, {}));
+
+  transformation_context.GetFactManager()->AddFactDataSynonym(
+      MakeDataDescriptor(104, {1}), MakeDataDescriptor(92, {}));
+  transformation_context.GetFactManager()->AddFactDataSynonym(
+      MakeDataDescriptor(105, {1}), MakeDataDescriptor(93, {}));
+
+  // Div operations are not currently supported.
+  {
+    TransformationWrapVectorSynonym wrap_div_bad1(62, 100, 101, 106, 1);
+    ASSERT_FALSE(
+        wrap_div_bad1.IsApplicable(context.get(), transformation_context));
+
+    TransformationWrapVectorSynonym wrap_div_bad2(78, 102, 103, 106, 1);
+    ASSERT_FALSE(
+        wrap_div_bad2.IsApplicable(context.get(), transformation_context));
+
+    TransformationWrapVectorSynonym wrap_div_bad3(94, 104, 105, 106, 1);
+    ASSERT_FALSE(
+        wrap_div_bad3.IsApplicable(context.get(), transformation_context));
+  }
+}
+
+TEST(TransformationWrapVectorSynonym, AdditionalWidthSupportTest) {
+  std::string shader = R"(
+               OpCapability Shader
+               OpCapability Int64
+               OpCapability Float64
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %4 "main" %97
+               OpExecutionMode %4 OriginUpperLeft
+               OpSource ESSL 310
+               OpName %4 "main"
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeInt 64 1
+          %7 = OpTypePointer Function %6
+          %9 = OpConstant %6 10
+         %11 = OpConstant %6 -5
+         %12 = OpTypeVector %6 2
+         %13 = OpTypePointer Function %12
+         %18 = OpTypeInt 64 0
+         %19 = OpTypePointer Function %18
+         %21 = OpConstant %18 8
+         %23 = OpConstant %18 2
+         %24 = OpTypeVector %18 3
+         %25 = OpTypePointer Function %24
+         %31 = OpTypeFloat 64
+         %32 = OpTypePointer Function %31
+         %34 = OpConstant %31 3.29999995
+         %36 = OpConstant %31 1.10000002
+         %37 = OpTypeVector %31 4
+         %38 = OpTypePointer Function %37
+         %96 = OpTypePointer Input %31
+         %97 = OpVariable %96 Input
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+          %8 = OpVariable %7 Function
+         %10 = OpVariable %7 Function
+         %14 = OpVariable %13 Function
+         %20 = OpVariable %19 Function
+         %22 = OpVariable %19 Function
+         %26 = OpVariable %25 Function
+         %33 = OpVariable %32 Function
+         %35 = OpVariable %32 Function
+         %39 = OpVariable %38 Function
+         %47 = OpVariable %7 Function
+         %51 = OpVariable %7 Function
+         %55 = OpVariable %7 Function
+         %59 = OpVariable %7 Function
+         %63 = OpVariable %19 Function
+         %67 = OpVariable %19 Function
+         %71 = OpVariable %19 Function
+         %75 = OpVariable %19 Function
+         %79 = OpVariable %32 Function
+         %83 = OpVariable %32 Function
+         %87 = OpVariable %32 Function
+         %91 = OpVariable %32 Function
+               OpStore %8 %9
+               OpStore %10 %11
+         %15 = OpLoad %6 %8
+         %16 = OpLoad %6 %10
+         %17 = OpCompositeConstruct %12 %15 %16
+               OpStore %14 %17
+               OpStore %20 %21
+               OpStore %22 %23
+         %27 = OpLoad %18 %20
+         %28 = OpLoad %18 %20
+         %29 = OpLoad %18 %22
+         %30 = OpCompositeConstruct %24 %27 %28 %29
+               OpStore %26 %30
+               OpStore %33 %34
+               OpStore %35 %36
+         %40 = OpLoad %31 %33
+         %41 = OpLoad %31 %33
+         %42 = OpLoad %31 %35
+         %43 = OpLoad %31 %35
+         %44 = OpCompositeConstruct %37 %40 %41 %42 %43
+         %45 = OpLoad %37 %39
+         %46 = OpVectorShuffle %37 %45 %44 5 6 7 4
+               OpStore %39 %46
+         %48 = OpLoad %6 %8
+         %49 = OpLoad %6 %10
+        %100 = OpCompositeConstruct %12 %48 %48
+        %101 = OpCompositeConstruct %12 %49 %49
+         %50 = OpIAdd %6 %48 %49
+               OpStore %47 %50
+         %52 = OpLoad %6 %8
+         %53 = OpLoad %6 %10
+         %54 = OpISub %6 %52 %53
+               OpStore %51 %54
+         %56 = OpLoad %6 %8
+         %57 = OpLoad %6 %10
+         %58 = OpIMul %6 %56 %57
+               OpStore %55 %58
+         %60 = OpLoad %6 %8
+         %61 = OpLoad %6 %10
+         %62 = OpSDiv %6 %60 %61
+               OpStore %59 %62
+         %64 = OpLoad %18 %20
+         %65 = OpLoad %18 %22
+         %66 = OpIAdd %18 %64 %65
+               OpStore %63 %66
+         %68 = OpLoad %18 %20
+         %69 = OpLoad %18 %22
+        %103 = OpCompositeConstruct %24 %68 %68 %68
+        %104 = OpCompositeConstruct %24 %69 %69 %69
+         %70 = OpISub %18 %68 %69
+               OpStore %67 %70
+         %72 = OpLoad %18 %20
+         %73 = OpLoad %18 %22
+         %74 = OpIMul %18 %72 %73
+               OpStore %71 %74
+         %76 = OpLoad %18 %20
+         %77 = OpLoad %18 %22
+         %78 = OpUDiv %18 %76 %77
+               OpStore %75 %78
+         %80 = OpLoad %31 %33
+         %81 = OpLoad %31 %35
+         %82 = OpFAdd %31 %80 %81
+               OpStore %79 %82
+         %84 = OpLoad %31 %33
+         %85 = OpLoad %31 %35
+         %86 = OpFSub %31 %84 %85
+               OpStore %83 %86
+         %88 = OpLoad %31 %33
+         %89 = OpLoad %31 %35
+        %106 = OpCompositeConstruct %37 %88 %88 %88 %88
+        %107 = OpCompositeConstruct %37 %89 %89 %89 %89
+         %90 = OpFMul %31 %88 %89
+               OpStore %87 %90
+         %92 = OpLoad %31 %33
+         %93 = OpLoad %31 %35
+         %94 = OpFDiv %31 %92 %93
+               OpStore %91 %94
+               OpReturn
+               OpFunctionEnd
+  )";
+  const auto env = SPV_ENV_UNIVERSAL_1_3;
+  const auto consumer = nullptr;
+  const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
+  spvtools::ValidatorOptions validator_options;
+
+  // Check context validity.
+  ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
+                                               kConsoleMessageConsumer));
+
+  TransformationContext transformation_context(
+      MakeUnique<FactManager>(context.get()), validator_options);
+
+  // Vec Type Id |   Vector Type  |  Element Type id |   Element Type  |
+  // ------------+----------------+------------------+-----------------+
+  //     12      |      vec2      |         6        |      int64      |
+  //     24      |      vec3      |        18        |     uint64      |
+  //     37      |      vec4      |        31        |    float64      |
+
+  // Test support for 64-bit signed int.
+  {
+    // Assert that the target scalar instruction result id is relevant.
+    ASSERT_FALSE(transformation_context.GetFactManager()->IdIsIrrelevant(50));
+    transformation_context.GetFactManager()->AddFactDataSynonym(
+        MakeDataDescriptor(100, {1}), MakeDataDescriptor(48, {}));
+    transformation_context.GetFactManager()->AddFactDataSynonym(
+        MakeDataDescriptor(101, {1}), MakeDataDescriptor(49, {}));
+
+    // Good: The following transformation should be applicable.
+    TransformationWrapVectorSynonym wrap_add_int64(50, 100, 101, 102, 1);
+    ASSERT_TRUE(
+        wrap_add_int64.IsApplicable(context.get(), transformation_context));
+    // Insert an arithmetic instruction of the same type to add two vectors.
+    ApplyAndCheckFreshIds(wrap_add_int64, context.get(),
+                          &transformation_context);
+
+    // |instruction_id| and id at |scalar_position of the result vector should
+    // be synonyms.
+    ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
+        MakeDataDescriptor(102, {1}), MakeDataDescriptor(50, {})));
+  }
+
+  // Test support for 64-bit unsigned int.
+  {
+    ASSERT_FALSE(transformation_context.GetFactManager()->IdIsIrrelevant(70));
+    transformation_context.GetFactManager()->AddFactDataSynonym(
+        MakeDataDescriptor(103, {2}), MakeDataDescriptor(68, {}));
+    transformation_context.GetFactManager()->AddFactDataSynonym(
+        MakeDataDescriptor(104, {2}), MakeDataDescriptor(69, {}));
+
+    // Good: The following transformation should be applicable.
+    TransformationWrapVectorSynonym wrap_sub_uint64(70, 103, 104, 105, 2);
+    ASSERT_TRUE(
+        wrap_sub_uint64.IsApplicable(context.get(), transformation_context));
+
+    ApplyAndCheckFreshIds(wrap_sub_uint64, context.get(),
+                          &transformation_context);
+
+    ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
+        MakeDataDescriptor(105, {2}), MakeDataDescriptor(70, {})));
+  }
+
+  // Test support for 64-bit float.
+  {
+    ASSERT_FALSE(transformation_context.GetFactManager()->IdIsIrrelevant(90));
+    transformation_context.GetFactManager()->AddFactDataSynonym(
+        MakeDataDescriptor(106, {3}), MakeDataDescriptor(88, {}));
+    transformation_context.GetFactManager()->AddFactDataSynonym(
+        MakeDataDescriptor(107, {3}), MakeDataDescriptor(89, {}));
+
+    // Good: The following transformation should be applicable.
+    TransformationWrapVectorSynonym wrap_mul_float64(90, 106, 107, 108, 3);
+    ASSERT_TRUE(
+        wrap_mul_float64.IsApplicable(context.get(), transformation_context));
+
+    ApplyAndCheckFreshIds(wrap_mul_float64, context.get(),
+                          &transformation_context);
+
+    ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
+        MakeDataDescriptor(108, {3}), MakeDataDescriptor(90, {})));
+  }
+
+  std::string after_transformation = R"(
+               OpCapability Shader
+               OpCapability Int64
+               OpCapability Float64
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %4 "main" %97
+               OpExecutionMode %4 OriginUpperLeft
+               OpSource ESSL 310
+               OpName %4 "main"
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeInt 64 1
+          %7 = OpTypePointer Function %6
+          %9 = OpConstant %6 10
+         %11 = OpConstant %6 -5
+         %12 = OpTypeVector %6 2
+         %13 = OpTypePointer Function %12
+         %18 = OpTypeInt 64 0
+         %19 = OpTypePointer Function %18
+         %21 = OpConstant %18 8
+         %23 = OpConstant %18 2
+         %24 = OpTypeVector %18 3
+         %25 = OpTypePointer Function %24
+         %31 = OpTypeFloat 64
+         %32 = OpTypePointer Function %31
+         %34 = OpConstant %31 3.29999995
+         %36 = OpConstant %31 1.10000002
+         %37 = OpTypeVector %31 4
+         %38 = OpTypePointer Function %37
+         %96 = OpTypePointer Input %31
+         %97 = OpVariable %96 Input
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+          %8 = OpVariable %7 Function
+         %10 = OpVariable %7 Function
+         %14 = OpVariable %13 Function
+         %20 = OpVariable %19 Function
+         %22 = OpVariable %19 Function
+         %26 = OpVariable %25 Function
+         %33 = OpVariable %32 Function
+         %35 = OpVariable %32 Function
+         %39 = OpVariable %38 Function
+         %47 = OpVariable %7 Function
+         %51 = OpVariable %7 Function
+         %55 = OpVariable %7 Function
+         %59 = OpVariable %7 Function
+         %63 = OpVariable %19 Function
+         %67 = OpVariable %19 Function
+         %71 = OpVariable %19 Function
+         %75 = OpVariable %19 Function
+         %79 = OpVariable %32 Function
+         %83 = OpVariable %32 Function
+         %87 = OpVariable %32 Function
+         %91 = OpVariable %32 Function
+               OpStore %8 %9
+               OpStore %10 %11
+         %15 = OpLoad %6 %8
+         %16 = OpLoad %6 %10
+         %17 = OpCompositeConstruct %12 %15 %16
+               OpStore %14 %17
+               OpStore %20 %21
+               OpStore %22 %23
+         %27 = OpLoad %18 %20
+         %28 = OpLoad %18 %20
+         %29 = OpLoad %18 %22
+         %30 = OpCompositeConstruct %24 %27 %28 %29
+               OpStore %26 %30
+               OpStore %33 %34
+               OpStore %35 %36
+         %40 = OpLoad %31 %33
+         %41 = OpLoad %31 %33
+         %42 = OpLoad %31 %35
+         %43 = OpLoad %31 %35
+         %44 = OpCompositeConstruct %37 %40 %41 %42 %43
+         %45 = OpLoad %37 %39
+         %46 = OpVectorShuffle %37 %45 %44 5 6 7 4
+               OpStore %39 %46
+         %48 = OpLoad %6 %8
+         %49 = OpLoad %6 %10
+        %100 = OpCompositeConstruct %12 %48 %48
+        %101 = OpCompositeConstruct %12 %49 %49
+        %102 = OpIAdd %12 %100 %101
+         %50 = OpIAdd %6 %48 %49
+               OpStore %47 %50
+         %52 = OpLoad %6 %8
+         %53 = OpLoad %6 %10
+         %54 = OpISub %6 %52 %53
+               OpStore %51 %54
+         %56 = OpLoad %6 %8
+         %57 = OpLoad %6 %10
+         %58 = OpIMul %6 %56 %57
+               OpStore %55 %58
+         %60 = OpLoad %6 %8
+         %61 = OpLoad %6 %10
+         %62 = OpSDiv %6 %60 %61
+               OpStore %59 %62
+         %64 = OpLoad %18 %20
+         %65 = OpLoad %18 %22
+         %66 = OpIAdd %18 %64 %65
+               OpStore %63 %66
+         %68 = OpLoad %18 %20
+         %69 = OpLoad %18 %22
+        %103 = OpCompositeConstruct %24 %68 %68 %68
+        %104 = OpCompositeConstruct %24 %69 %69 %69
+        %105 = OpISub %24 %103 %104
+         %70 = OpISub %18 %68 %69
+               OpStore %67 %70
+         %72 = OpLoad %18 %20
+         %73 = OpLoad %18 %22
+         %74 = OpIMul %18 %72 %73
+               OpStore %71 %74
+         %76 = OpLoad %18 %20
+         %77 = OpLoad %18 %22
+         %78 = OpUDiv %18 %76 %77
+               OpStore %75 %78
+         %80 = OpLoad %31 %33
+         %81 = OpLoad %31 %35
+         %82 = OpFAdd %31 %80 %81
+               OpStore %79 %82
+         %84 = OpLoad %31 %33
+         %85 = OpLoad %31 %35
+         %86 = OpFSub %31 %84 %85
+               OpStore %83 %86
+         %88 = OpLoad %31 %33
+         %89 = OpLoad %31 %35
+        %106 = OpCompositeConstruct %37 %88 %88 %88 %88
+        %107 = OpCompositeConstruct %37 %89 %89 %89 %89
+        %108 = OpFMul %37 %106 %107
+         %90 = OpFMul %31 %88 %89
+               OpStore %87 %90
+         %92 = OpLoad %31 %33
+         %93 = OpLoad %31 %35
+         %94 = OpFDiv %31 %92 %93
+               OpStore %91 %94
+               OpReturn
+               OpFunctionEnd
+  )";
+  ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
+}
+
+TEST(TransformationWrapVectorSynonym, DifferentVectorSignedness) {
+  std::string shader = R"(
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %4 "main"
+               OpExecutionMode %4 OriginUpperLeft
+               OpSource ESSL 320
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeInt 32 1
+          %7 = OpTypeVector %6 2
+          %8 = OpTypePointer Function %7
+         %10 = OpConstant %6 1
+         %11 = OpConstant %6 0
+         %12 = OpConstantComposite %7 %10 %11
+         %14 = OpTypeInt 32 0
+         %15 = OpTypeVector %14 2
+         %18 = OpConstant %14 3
+         %19 = OpConstant %14 0
+         %20 = OpConstantComposite %15 %18 %19
+         %21 = OpConstantComposite %15 %19 %18
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+        %100 = OpIAdd %14 %10 %18
+        %101 = OpIAdd %6 %10 %18
+        %102 = OpIAdd %6 %18 %19
+               OpReturn
+               OpFunctionEnd
+  )";
+  const auto env = SPV_ENV_UNIVERSAL_1_3;
+  const auto consumer = nullptr;
+  const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
+  spvtools::ValidatorOptions validator_options;
+
+  // Check context validity.
+  ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
+                                               kConsoleMessageConsumer));
+
+  TransformationContext transformation_context(
+      MakeUnique<FactManager>(context.get()), validator_options);
+
+  transformation_context.GetFactManager()->AddFactDataSynonym(
+      MakeDataDescriptor(10, {}), MakeDataDescriptor(12, {0}));
+  transformation_context.GetFactManager()->AddFactDataSynonym(
+      MakeDataDescriptor(18, {}), MakeDataDescriptor(20, {0}));
+  transformation_context.GetFactManager()->AddFactDataSynonym(
+      MakeDataDescriptor(19, {}), MakeDataDescriptor(21, {0}));
+
+  {
+    TransformationWrapVectorSynonym transformation1(100, 12, 20, 200, 0);
+    ASSERT_TRUE(
+        transformation1.IsApplicable(context.get(), transformation_context));
+    ApplyAndCheckFreshIds(transformation1, context.get(),
+                          &transformation_context);
+    ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
+        MakeDataDescriptor(200, {0}), MakeDataDescriptor(100, {})));
+  }
+
+  {
+    TransformationWrapVectorSynonym transformation2(101, 12, 20, 201, 0);
+    ASSERT_TRUE(
+        transformation2.IsApplicable(context.get(), transformation_context));
+    ApplyAndCheckFreshIds(transformation2, context.get(),
+                          &transformation_context);
+    ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
+        MakeDataDescriptor(201, {0}), MakeDataDescriptor(101, {})));
+  }
+
+  {
+    TransformationWrapVectorSynonym transformation3(102, 20, 21, 202, 0);
+    ASSERT_TRUE(
+        transformation3.IsApplicable(context.get(), transformation_context));
+    ApplyAndCheckFreshIds(transformation3, context.get(),
+                          &transformation_context);
+    ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
+        MakeDataDescriptor(202, {0}), MakeDataDescriptor(102, {})));
+  }
+
+  std::string after_transformation = R"(
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %4 "main"
+               OpExecutionMode %4 OriginUpperLeft
+               OpSource ESSL 320
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeInt 32 1
+          %7 = OpTypeVector %6 2
+          %8 = OpTypePointer Function %7
+         %10 = OpConstant %6 1
+         %11 = OpConstant %6 0
+         %12 = OpConstantComposite %7 %10 %11
+         %14 = OpTypeInt 32 0
+         %15 = OpTypeVector %14 2
+         %18 = OpConstant %14 3
+         %19 = OpConstant %14 0
+         %20 = OpConstantComposite %15 %18 %19
+         %21 = OpConstantComposite %15 %19 %18
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+        %200 = OpIAdd %15 %12 %20
+        %100 = OpIAdd %14 %10 %18
+        %201 = OpIAdd %7 %12 %20
+        %101 = OpIAdd %6 %10 %18
+        %202 = OpIAdd %7 %20 %21
+        %102 = OpIAdd %6 %18 %19
+               OpReturn
+               OpFunctionEnd
+  )";
+  ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
+}
+
+TEST(TransformationWrapVectorSynonym, SignednessDoesNotMatchResultType) {
+  std::string shader = R"(
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %4 "main"
+               OpExecutionMode %4 OriginUpperLeft
+               OpSource ESSL 320
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeInt 32 1
+          %7 = OpTypeVector %6 2
+          %8 = OpTypePointer Function %7
+         %10 = OpConstant %6 1
+         %11 = OpConstant %6 0
+         %12 = OpConstantComposite %7 %10 %11
+         %13 = OpConstantComposite %7 %11 %10
+         %14 = OpTypeInt 32 0
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+        %100 = OpIAdd %14 %10 %11
+               OpReturn
+               OpFunctionEnd
+  )";
+  const auto env = SPV_ENV_UNIVERSAL_1_3;
+  const auto consumer = nullptr;
+  const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
+  spvtools::ValidatorOptions validator_options;
+
+  // Check context validity.
+  ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
+                                               kConsoleMessageConsumer));
+
+  TransformationContext transformation_context(
+      MakeUnique<FactManager>(context.get()), validator_options);
+
+  transformation_context.GetFactManager()->AddFactDataSynonym(
+      MakeDataDescriptor(10, {}), MakeDataDescriptor(12, {0}));
+  transformation_context.GetFactManager()->AddFactDataSynonym(
+      MakeDataDescriptor(11, {}), MakeDataDescriptor(13, {0}));
+
+  ASSERT_FALSE(TransformationWrapVectorSynonym(100, 12, 13, 200, 0)
+                   .IsApplicable(context.get(), transformation_context));
+}
+
+}  // namespace
+}  // namespace fuzz
+}  // namespace spvtools

+ 56 - 0
ThirdParty/Glslang/External/spirv-tools/test/fuzzers/CMakeLists.txt

@@ -0,0 +1,56 @@
+# Copyright (c) 2021 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.
+
+function(add_spvtools_libfuzzer_target)
+  set(one_value_args TARGET)
+  set(multi_value_args SRCS LIBS)
+  cmake_parse_arguments(
+    ARG "" "${one_value_args}" "${multi_value_args}" ${ARGN})
+
+  add_executable(${ARG_TARGET} ${ARG_SRCS})
+  spvtools_default_compile_options(${ARG_TARGET})
+  target_link_libraries(${ARG_TARGET} PRIVATE ${ARG_LIBS})
+  target_include_directories(${ARG_TARGET} PRIVATE
+    ${spirv-tools_SOURCE_DIR}
+    ${spirv-tools_BINARY_DIR}
+  )
+  set_property(TARGET ${ARG_TARGET} PROPERTY FOLDER "SPIRV-Tools libFuzzer targets")
+  if(NOT ${SPIRV_LIB_FUZZING_ENGINE_LINK_OPTIONS} STREQUAL "")
+    # This is set when the fuzzers are being built by OSS-Fuzz. In this case the
+    # variable provides the necessary linker flags, and OSS-Fuzz will take care
+    # of passing suitable compiler flags.
+    target_link_options(${ARG_TARGET} PRIVATE ${SPIRV_LIB_FUZZING_ENGINE_LINK_OPTIONS})
+  else()
+    # When the fuzzers are being built outside of OSS-Fuzz, standard libFuzzer
+    # arguments to enable fuzzing are used.
+    target_compile_options(${ARG_TARGET} PRIVATE "-fsanitize=fuzzer")
+    target_link_options(${ARG_TARGET} PRIVATE "-fsanitize=fuzzer")    
+  endif()
+endfunction()
+
+if (${SPIRV_BUILD_LIBFUZZER_TARGETS})
+  if(NOT "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
+    message(FATAL_ERROR "The libFuzzer targets are only supported with the Clang compiler. Compiler '${CMAKE_CXX_COMPILER_ID}' is not supported!")
+  endif()
+  add_spvtools_libfuzzer_target(TARGET spvtools_as_fuzzer SRCS spvtools_as_fuzzer.cpp random_generator.cpp LIBS ${SPIRV_TOOLS_FULL_VISIBILITY})
+  add_spvtools_libfuzzer_target(TARGET spvtools_binary_parser_fuzzer SRCS spvtools_binary_parser_fuzzer.cpp random_generator.cpp LIBS ${SPIRV_TOOLS_FULL_VISIBILITY})
+  add_spvtools_libfuzzer_target(TARGET spvtools_dis_fuzzer SRCS spvtools_dis_fuzzer.cpp random_generator.cpp LIBS ${SPIRV_TOOLS_FULL_VISIBILITY})
+  add_spvtools_libfuzzer_target(TARGET spvtools_opt_legalization_fuzzer SRCS spvtools_opt_legalization_fuzzer.cpp spvtools_opt_fuzzer_common.cpp random_generator.cpp LIBS SPIRV-Tools-opt ${SPIRV_TOOLS_FULL_VISIBILITY})
+  add_spvtools_libfuzzer_target(TARGET spvtools_opt_performance_fuzzer SRCS spvtools_opt_performance_fuzzer.cpp spvtools_opt_fuzzer_common.cpp random_generator.cpp LIBS SPIRV-Tools-opt ${SPIRV_TOOLS_FULL_VISIBILITY})
+  add_spvtools_libfuzzer_target(TARGET spvtools_opt_size_fuzzer SRCS spvtools_opt_size_fuzzer.cpp spvtools_opt_fuzzer_common.cpp random_generator.cpp LIBS SPIRV-Tools-opt ${SPIRV_TOOLS_FULL_VISIBILITY})
+  add_spvtools_libfuzzer_target(TARGET spvtools_val_fuzzer SRCS spvtools_val_fuzzer.cpp random_generator.cpp LIBS ${SPIRV_TOOLS_FULL_VISIBILITY})
+  if (${SPIRV_BUILD_FUZZER})
+    add_spvtools_libfuzzer_target(TARGET spvtools_fuzz_fuzzer SRCS spvtools_fuzz_fuzzer.cpp random_generator.cpp LIBS SPIRV-Tools-fuzz ${SPIRV_TOOLS_FULL_VISIBILITY})
+  endif()
+endif()

BIN
ThirdParty/Glslang/External/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_000.spv


BIN
ThirdParty/Glslang/External/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_001.spv


BIN
ThirdParty/Glslang/External/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_002.spv


BIN
ThirdParty/Glslang/External/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_003.spv


BIN
ThirdParty/Glslang/External/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_004.spv


BIN
ThirdParty/Glslang/External/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_005.spv


BIN
ThirdParty/Glslang/External/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_006.spv


BIN
ThirdParty/Glslang/External/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_007.spv


BIN
ThirdParty/Glslang/External/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_008.spv


BIN
ThirdParty/Glslang/External/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_009.spv


BIN
ThirdParty/Glslang/External/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_010.spv


BIN
ThirdParty/Glslang/External/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_011.spv


BIN
ThirdParty/Glslang/External/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_012.spv


BIN
ThirdParty/Glslang/External/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_013.spv


BIN
ThirdParty/Glslang/External/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_014.spv


BIN
ThirdParty/Glslang/External/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_015.spv


BIN
ThirdParty/Glslang/External/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_016.spv


BIN
ThirdParty/Glslang/External/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_017.spv


BIN
ThirdParty/Glslang/External/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_018.spv


BIN
ThirdParty/Glslang/External/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_019.spv


BIN
ThirdParty/Glslang/External/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_020.spv


BIN
ThirdParty/Glslang/External/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_021.spv


BIN
ThirdParty/Glslang/External/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_022.spv


BIN
ThirdParty/Glslang/External/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_023.spv


BIN
ThirdParty/Glslang/External/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_024.spv


BIN
ThirdParty/Glslang/External/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_025.spv


BIN
ThirdParty/Glslang/External/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_026.spv


BIN
ThirdParty/Glslang/External/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_027.spv


BIN
ThirdParty/Glslang/External/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_028.spv


BIN
ThirdParty/Glslang/External/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_029.spv


BIN
ThirdParty/Glslang/External/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_030.spv


BIN
ThirdParty/Glslang/External/spirv-tools/test/fuzzers/corpora/spv/graphicsfuzz_031.spv


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