Browse Source

Add missing files. Damn gitignore

Panagiotis Christopoulos Charitos 3 years ago
parent
commit
bb6f5ea3cf
92 changed files with 21578 additions and 1 deletions
  1. 0 1
      .gitignore
  2. 54 0
      ThirdParty/Glslang/External/spirv-tools/source/diff/CMakeLists.txt
  3. 2862 0
      ThirdParty/Glslang/External/spirv-tools/source/diff/diff.cpp
  4. 48 0
      ThirdParty/Glslang/External/spirv-tools/source/diff/diff.h
  5. 224 0
      ThirdParty/Glslang/External/spirv-tools/source/diff/lcs.h
  6. 26 0
      ThirdParty/Glslang/External/spirv-tools/test/diff/CMakeLists.txt
  7. 242 0
      ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/OpExtInst_in_dst_only_autogen.cpp
  8. 33 0
      ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/OpExtInst_in_dst_only_dst.spvasm
  9. 33 0
      ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/OpExtInst_in_dst_only_src.spvasm
  10. 242 0
      ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/OpExtInst_in_src_only_autogen.cpp
  11. 30 0
      ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/OpExtInst_in_src_only_dst.spvasm
  12. 36 0
      ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/OpExtInst_in_src_only_src.spvasm
  13. 136 0
      ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/OpTypeForwardPointer_basic_autogen.cpp
  14. 15 0
      ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/OpTypeForwardPointer_basic_dst.spvasm
  15. 13 0
      ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/OpTypeForwardPointer_basic_src.spvasm
  16. 138 0
      ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/OpTypeForwardPointer_intertwined_autogen.cpp
  17. 13 0
      ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/OpTypeForwardPointer_intertwined_dst.spvasm
  18. 15 0
      ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/OpTypeForwardPointer_intertwined_src.spvasm
  19. 116 0
      ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/OpTypeForwardPointer_mismatching_class_autogen.cpp
  20. 9 0
      ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/OpTypeForwardPointer_mismatching_class_dst.spvasm
  21. 11 0
      ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/OpTypeForwardPointer_mismatching_class_src.spvasm
  22. 111 0
      ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/OpTypeForwardPointer_mismatching_type_autogen.cpp
  23. 8 0
      ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/OpTypeForwardPointer_mismatching_type_dst.spvasm
  24. 10 0
      ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/OpTypeForwardPointer_mismatching_type_src.spvasm
  25. 127 0
      ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/OpTypeForwardPointer_nested_autogen.cpp
  26. 11 0
      ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/OpTypeForwardPointer_nested_dst.spvasm
  27. 13 0
      ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/OpTypeForwardPointer_nested_src.spvasm
  28. 124 0
      ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/OpTypeForwardPointer_onesided_debug_autogen.cpp
  29. 11 0
      ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/OpTypeForwardPointer_onesided_debug_dst.spvasm
  30. 14 0
      ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/OpTypeForwardPointer_onesided_debug_src.spvasm
  31. 17 0
      ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/README.md
  32. 407 0
      ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/basic_autogen.cpp
  33. 49 0
      ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/basic_dst.spvasm
  34. 50 0
      ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/basic_src.spvasm
  35. 306 0
      ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/constant_array_size_autogen.cpp
  36. 47 0
      ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/constant_array_size_dst.spvasm
  37. 48 0
      ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/constant_array_size_src.spvasm
  38. 45 0
      ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/diff_test_files_autogen.cmake
  39. 1626 0
      ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/different_decorations_fragment_autogen.cpp
  40. 199 0
      ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/different_decorations_fragment_dst.spvasm
  41. 198 0
      ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/different_decorations_fragment_src.spvasm
  42. 1322 0
      ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/different_decorations_vertex_autogen.cpp
  43. 159 0
      ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/different_decorations_vertex_dst.spvasm
  44. 155 0
      ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/different_decorations_vertex_src.spvasm
  45. 339 0
      ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/different_function_parameter_count_autogen.cpp
  46. 52 0
      ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/different_function_parameter_count_dst.spvasm
  47. 46 0
      ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/different_function_parameter_count_src.spvasm
  48. 867 0
      ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/extra_if_block_autogen.cpp
  49. 136 0
      ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/extra_if_block_dst.spvasm
  50. 137 0
      ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/extra_if_block_src.spvasm
  51. 304 0
      ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/generate_tests.py
  52. 733 0
      ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/index_signedness_autogen.cpp
  53. 110 0
      ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/index_signedness_dst.spvasm
  54. 111 0
      ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/index_signedness_src.spvasm
  55. 396 0
      ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/int_vs_uint_constants_autogen.cpp
  56. 46 0
      ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/int_vs_uint_constants_dst.spvasm
  57. 49 0
      ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/int_vs_uint_constants_src.spvasm
  58. 1534 0
      ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/large_functions_large_diffs_autogen.cpp
  59. 213 0
      ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/large_functions_large_diffs_dst.spvasm
  60. 230 0
      ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/large_functions_large_diffs_src.spvasm
  61. 1364 0
      ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/large_functions_small_diffs_autogen.cpp
  62. 229 0
      ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/large_functions_small_diffs_dst.spvasm
  63. 226 0
      ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/large_functions_small_diffs_src.spvasm
  64. 330 0
      ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/multiple_different_entry_points_autogen.cpp
  65. 49 0
      ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/multiple_different_entry_points_dst.spvasm
  66. 51 0
      ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/multiple_different_entry_points_src.spvasm
  67. 375 0
      ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/multiple_same_entry_points_autogen.cpp
  68. 45 0
      ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/multiple_same_entry_points_dst.spvasm
  69. 46 0
      ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/multiple_same_entry_points_src.spvasm
  70. 568 0
      ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/reordered_if_blocks_autogen.cpp
  71. 87 0
      ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/reordered_if_blocks_dst.spvasm
  72. 87 0
      ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/reordered_if_blocks_src.spvasm
  73. 582 0
      ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/reordered_switch_blocks_autogen.cpp
  74. 91 0
      ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/reordered_switch_blocks_dst.spvasm
  75. 92 0
      ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/reordered_switch_blocks_src.spvasm
  76. 747 0
      ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/small_functions_small_diffs_autogen.cpp
  77. 92 0
      ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/small_functions_small_diffs_dst.spvasm
  78. 93 0
      ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/small_functions_small_diffs_src.spvasm
  79. 310 0
      ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/spec_constant_array_size_autogen.cpp
  80. 47 0
      ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/spec_constant_array_size_dst.spvasm
  81. 48 0
      ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/spec_constant_array_size_src.spvasm
  82. 186 0
      ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/spec_constant_composite_autogen.cpp
  83. 22 0
      ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/spec_constant_composite_dst.spvasm
  84. 23 0
      ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/spec_constant_composite_src.spvasm
  85. 230 0
      ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/unrelated_shaders_autogen.cpp
  86. 31 0
      ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/unrelated_shaders_dst.spvasm
  87. 25 0
      ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/unrelated_shaders_src.spvasm
  88. 228 0
      ThirdParty/Glslang/External/spirv-tools/test/diff/diff_test.cpp
  89. 58 0
      ThirdParty/Glslang/External/spirv-tools/test/diff/diff_test_utils.cpp
  90. 30 0
      ThirdParty/Glslang/External/spirv-tools/test/diff/diff_test_utils.h
  91. 329 0
      ThirdParty/Glslang/External/spirv-tools/test/diff/lcs_test.cpp
  92. 201 0
      ThirdParty/Glslang/External/spirv-tools/tools/diff/diff.cpp

+ 0 - 1
.gitignore

@@ -4,4 +4,3 @@ out/*
 CMakeSettings.json
 *.TMP
 AndroidProject_*
-*diff*

+ 54 - 0
ThirdParty/Glslang/External/spirv-tools/source/diff/CMakeLists.txt

@@ -0,0 +1,54 @@
+# 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.
+set(SPIRV_TOOLS_DIFF_SOURCES
+  diff.h
+  lcs.h
+
+  diff.cpp
+)
+
+add_library(SPIRV-Tools-diff ${SPIRV_TOOLS_LIBRARY_TYPE} ${SPIRV_TOOLS_DIFF_SOURCES})
+
+spvtools_default_compile_options(SPIRV-Tools-diff)
+target_include_directories(SPIRV-Tools-diff
+  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-diff
+  PUBLIC ${SPIRV_TOOLS_FULL_VISIBILITY})
+# We need the internals of spirv-opt.
+target_link_libraries(SPIRV-Tools-diff
+  PUBLIC SPIRV-Tools-opt)
+
+set_property(TARGET SPIRV-Tools-diff PROPERTY FOLDER "SPIRV-Tools libraries")
+spvtools_check_symbol_exports(SPIRV-Tools-diff)
+
+if(ENABLE_SPIRV_TOOLS_INSTALL)
+  install(TARGETS SPIRV-Tools-diff EXPORT SPIRV-Tools-diffTargets
+    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+    ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
+  export(EXPORT SPIRV-Tools-diffTargets FILE SPIRV-Tools-diffTargets.cmake)
+
+  spvtools_config_package_dir(SPIRV-Tools-diff PACKAGE_DIR)
+  install(EXPORT SPIRV-Tools-diffTargets FILE SPIRV-Tools-diffTargets.cmake
+  	DESTINATION ${PACKAGE_DIR})
+
+  spvtools_generate_config_file(SPIRV-Tools-diff)
+  install(FILES ${CMAKE_BINARY_DIR}/SPIRV-Tools-diffConfig.cmake DESTINATION ${PACKAGE_DIR})
+endif(ENABLE_SPIRV_TOOLS_INSTALL)

+ 2862 - 0
ThirdParty/Glslang/External/spirv-tools/source/diff/diff.cpp

@@ -0,0 +1,2862 @@
+// 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/diff/diff.h"
+
+#include "source/diff/lcs.h"
+#include "source/disassemble.h"
+#include "source/ext_inst.h"
+#include "source/latest_version_spirv_header.h"
+#include "source/print.h"
+#include "spirv-tools/libspirv.hpp"
+
+namespace spvtools {
+namespace diff {
+
+namespace {
+
+// A map from an id to the instruction that defines it.
+using IdToInstructionMap = std::vector<const opt::Instruction*>;
+// A map from an id to the instructions that decorate it, or name it, etc.
+using IdToInfoMap = std::vector<std::vector<const opt::Instruction*>>;
+// A map from an instruction to another, used for instructions without id.
+using InstructionToInstructionMap =
+    std::unordered_map<const opt::Instruction*, const opt::Instruction*>;
+// A flat list of instructions in a function for easier iteration.
+using InstructionList = std::vector<const opt::Instruction*>;
+// A map from a function to its list of instructions.
+using FunctionInstMap = std::map<uint32_t, InstructionList>;
+// A list of ids with some similar property, for example functions with the same
+// name.
+using IdGroup = std::vector<uint32_t>;
+// A map of names to ids with the same name.  This is an ordered map so
+// different implementations produce identical results.
+using IdGroupMapByName = std::map<std::string, IdGroup>;
+using IdGroupMapByTypeId = std::map<uint32_t, IdGroup>;
+using IdGroupMapByOp = std::map<SpvOp, IdGroup>;
+using IdGroupMapByStorageClass = std::map<SpvStorageClass, IdGroup>;
+
+// A set of potential id mappings that haven't been resolved yet.  Any id in src
+// may map in any id in dst.  Note that ids are added in the same order as they
+// appear in src and dst to facilitate matching dependent instructions.  For
+// example, this guarantees that when matching OpTypeVector, the basic type of
+// the vector is already (potentially) matched.
+struct PotentialIdMap {
+  std::vector<uint32_t> src_ids;
+  std::vector<uint32_t> dst_ids;
+};
+
+void CompactIds(std::vector<uint32_t>& ids) {
+  size_t write_index = 0;
+  for (size_t i = 0; i < ids.size(); ++i) {
+    if (ids[i] != 0) {
+      ids[write_index++] = ids[i];
+    }
+  }
+  ids.resize(write_index);
+}
+
+// A mapping between src and dst ids.
+class IdMap {
+ public:
+  IdMap(size_t id_bound) { id_map_.resize(id_bound, 0); }
+
+  void MapIds(uint32_t from, uint32_t to) {
+    assert(from != 0);
+    assert(to != 0);
+    assert(from < id_map_.size());
+    assert(id_map_[from] == 0);
+
+    id_map_[from] = to;
+  }
+
+  uint32_t MappedId(uint32_t from) const {
+    assert(from != 0);
+    return from < id_map_.size() ? id_map_[from] : 0;
+  }
+  const opt::Instruction* MappedInst(const opt::Instruction* from_inst) const {
+    assert(from_inst != nullptr);
+    assert(!from_inst->HasResultId());
+
+    auto mapped = inst_map_.find(from_inst);
+    if (mapped == inst_map_.end()) {
+      return nullptr;
+    }
+    return mapped->second;
+  }
+
+  bool IsMapped(uint32_t from) const {
+    assert(from != 0);
+    return from < id_map_.size() && id_map_[from] != 0;
+  }
+
+  // Map any ids in src and dst that have not been mapped to new ids in dst and
+  // src respectively.
+  void MapUnmatchedIds(IdMap& other_way);
+
+  // Some instructions don't have result ids.  Those are mapped by pointer.
+  void MapInsts(const opt::Instruction* from_inst,
+                const opt::Instruction* to_inst) {
+    assert(from_inst != nullptr);
+    assert(to_inst != nullptr);
+    assert(inst_map_.find(from_inst) == inst_map_.end());
+
+    inst_map_[from_inst] = to_inst;
+  }
+
+  uint32_t IdBound() const { return static_cast<uint32_t>(id_map_.size()); }
+
+ private:
+  // Given an id, returns the corresponding id in the other module, or 0 if not
+  // matched yet.
+  std::vector<uint32_t> id_map_;
+
+  // Same for instructions that don't have an id.
+  InstructionToInstructionMap inst_map_;
+};
+
+// Two way mapping of ids.
+class SrcDstIdMap {
+ public:
+  SrcDstIdMap(size_t src_id_bound, size_t dst_id_bound)
+      : src_to_dst_(src_id_bound), dst_to_src_(dst_id_bound) {}
+
+  void MapIds(uint32_t src, uint32_t dst) {
+    src_to_dst_.MapIds(src, dst);
+    dst_to_src_.MapIds(dst, src);
+  }
+
+  uint32_t MappedDstId(uint32_t src) {
+    uint32_t dst = src_to_dst_.MappedId(src);
+    assert(dst == 0 || dst_to_src_.MappedId(dst) == src);
+    return dst;
+  }
+  uint32_t MappedSrcId(uint32_t dst) {
+    uint32_t src = dst_to_src_.MappedId(dst);
+    assert(src == 0 || src_to_dst_.MappedId(src) == dst);
+    return src;
+  }
+
+  bool IsSrcMapped(uint32_t src) { return src_to_dst_.IsMapped(src); }
+  bool IsDstMapped(uint32_t dst) { return dst_to_src_.IsMapped(dst); }
+
+  // Map any ids in src and dst that have not been mapped to new ids in dst and
+  // src respectively.
+  void MapUnmatchedIds();
+
+  // Some instructions don't have result ids.  Those are mapped by pointer.
+  void MapInsts(const opt::Instruction* src_inst,
+                const opt::Instruction* dst_inst) {
+    assert(src_inst->HasResultId() == dst_inst->HasResultId());
+    if (src_inst->HasResultId()) {
+      MapIds(src_inst->result_id(), dst_inst->result_id());
+    } else {
+      src_to_dst_.MapInsts(src_inst, dst_inst);
+      dst_to_src_.MapInsts(dst_inst, src_inst);
+    }
+  }
+
+  const IdMap& SrcToDstMap() const { return src_to_dst_; }
+  const IdMap& DstToSrcMap() const { return dst_to_src_; }
+
+ private:
+  IdMap src_to_dst_;
+  IdMap dst_to_src_;
+};
+
+struct IdInstructions {
+  IdInstructions(const opt::Module* module)
+      : inst_map_(module->IdBound(), nullptr),
+        name_map_(module->IdBound()),
+        decoration_map_(module->IdBound()),
+        forward_pointer_map_(module->IdBound()) {
+    // Map ids from all sections to instructions that define them.
+    MapIdsToInstruction(module->ext_inst_imports());
+    MapIdsToInstruction(module->types_values());
+    for (const opt::Function& function : *module) {
+      function.ForEachInst(
+          [this](const opt::Instruction* inst) {
+            if (inst->HasResultId()) {
+              MapIdToInstruction(inst->result_id(), inst);
+            }
+          },
+          true, true);
+    }
+
+    // Gather decorations applied to ids that could be useful in matching them
+    // between src and dst modules.
+    MapIdsToInfos(module->debugs2());
+    MapIdsToInfos(module->annotations());
+    MapIdsToInfos(module->types_values());
+  }
+
+  void MapIdToInstruction(uint32_t id, const opt::Instruction* inst);
+
+  void MapIdsToInstruction(
+      opt::IteratorRange<opt::Module::const_inst_iterator> section);
+  void MapIdsToInfos(
+      opt::IteratorRange<opt::Module::const_inst_iterator> section);
+
+  IdToInstructionMap inst_map_;
+  IdToInfoMap name_map_;
+  IdToInfoMap decoration_map_;
+  IdToInstructionMap forward_pointer_map_;
+};
+
+class Differ {
+ public:
+  Differ(opt::IRContext* src, opt::IRContext* dst, std::ostream& out,
+         Options options)
+      : src_context_(src),
+        dst_context_(dst),
+        src_(src->module()),
+        dst_(dst->module()),
+        options_(options),
+        out_(out),
+        src_id_to_(src_),
+        dst_id_to_(dst_),
+        id_map_(src_->IdBound(), dst_->IdBound()) {
+    // Cache function bodies in canonicalization order.
+    GetFunctionBodies(src_context_, &src_funcs_, &src_func_insts_);
+    GetFunctionBodies(dst_context_, &dst_funcs_, &dst_func_insts_);
+  }
+
+  // Match ids or instructions of different sections.
+  void MatchCapabilities();
+  void MatchExtensions();
+  void MatchExtInstImportIds();
+  void MatchMemoryModel();
+  void MatchEntryPointIds();
+  void MatchExecutionModes();
+  void MatchTypeForwardPointers();
+  void MatchTypeIds();
+  void MatchConstants();
+  void MatchVariableIds();
+  void MatchFunctions();
+
+  // Debug info and annotations are matched only after ids are matched.
+  void MatchDebugs1();
+  void MatchDebugs2();
+  void MatchDebugs3();
+  void MatchExtInstDebugInfo();
+  void MatchAnnotations();
+
+  // Output the diff.
+  spv_result_t Output();
+
+  void DumpIdMap() {
+    if (!options_.dump_id_map) {
+      return;
+    }
+
+    out_ << " Src ->  Dst\n";
+    for (uint32_t src_id = 1; src_id < src_->IdBound(); ++src_id) {
+      uint32_t dst_id = id_map_.MappedDstId(src_id);
+      if (src_id_to_.inst_map_[src_id] != nullptr && dst_id != 0)
+        out_ << std::setw(4) << src_id << " -> " << std::setw(4) << dst_id
+             << " [" << spvOpcodeString(src_id_to_.inst_map_[src_id]->opcode())
+             << "]\n";
+    }
+  }
+
+ private:
+  // Helper functions that match ids between src and dst
+  void PoolPotentialIds(
+      opt::IteratorRange<opt::Module::const_inst_iterator> section,
+      std::vector<uint32_t>& ids, bool is_src,
+      std::function<bool(const opt::Instruction&)> filter,
+      std::function<uint32_t(const opt::Instruction&)> get_id);
+  void MatchIds(
+      PotentialIdMap& potential,
+      std::function<bool(const opt::Instruction*, const opt::Instruction*)>
+          match);
+  // Helper functions that match id-less instructions between src and dst.
+  void MatchPreambleInstructions(
+      opt::IteratorRange<opt::Module::const_inst_iterator> src_insts,
+      opt::IteratorRange<opt::Module::const_inst_iterator> dst_insts);
+  InstructionList SortPreambleInstructions(
+      const opt::Module* module,
+      opt::IteratorRange<opt::Module::const_inst_iterator> insts);
+  int ComparePreambleInstructions(const opt::Instruction* a,
+                                  const opt::Instruction* b,
+                                  const opt::Module* src_inst_module,
+                                  const opt::Module* dst_inst_module);
+  // Helper functions that match debug and annotation instructions of already
+  // matched ids.
+  void MatchDebugAndAnnotationInstructions(
+      opt::IteratorRange<opt::Module::const_inst_iterator> src_insts,
+      opt::IteratorRange<opt::Module::const_inst_iterator> dst_insts);
+
+  // Get various properties from an id.  These Helper functions are passed to
+  // `GroupIds` and `GroupIdsAndMatch` below (as the `get_group` argument).
+  uint32_t GroupIdsHelperGetTypeId(const IdInstructions& id_to, uint32_t id);
+  SpvStorageClass GroupIdsHelperGetTypePointerStorageClass(
+      const IdInstructions& id_to, uint32_t id);
+  SpvOp GroupIdsHelperGetTypePointerTypeOp(const IdInstructions& id_to,
+                                           uint32_t id);
+
+  // Given a list of ids, groups them based on some value.  The `get_group`
+  // function extracts a piece of information corresponding to each id, and the
+  // ids are bucketed based on that (and output in `groups`).  This is useful to
+  // attempt to match ids between src and dst only when said property is
+  // identical.
+  template <typename T>
+  void GroupIds(const IdGroup& ids, bool is_src, std::map<T, IdGroup>* groups,
+                T (Differ::*get_group)(const IdInstructions&, uint32_t));
+
+  // Calls GroupIds to bucket ids in src and dst based on a property returned by
+  // `get_group`.  This function then calls `match_group` for each bucket (i.e.
+  // "group") with identical values for said property.
+  //
+  // For example, say src and dst ids have the following properties
+  // correspondingly:
+  //
+  // - src ids' properties: {id0: A, id1: A, id2: B, id3: C, id4: B}
+  // - dst ids' properties: {id0': B, id1': C, id2': B, id3': D, id4': B}
+  //
+  // Then `match_group` is called 2 times:
+  //
+  // - Once with: ([id2, id4], [id0', id2', id4']) corresponding to B
+  // - Once with: ([id3], [id2']) corresponding to C
+  //
+  // Ids corresponding to A and D cannot match based on this property.
+  template <typename T>
+  void GroupIdsAndMatch(
+      const IdGroup& src_ids, const IdGroup& dst_ids, T invalid_group_key,
+      T (Differ::*get_group)(const IdInstructions&, uint32_t),
+      std::function<void(const IdGroup& src_group, const IdGroup& dst_group)>
+          match_group);
+
+  // Helper functions that determine if two instructions match
+  bool DoIdsMatch(uint32_t src_id, uint32_t dst_id);
+  bool DoesOperandMatch(const opt::Operand& src_operand,
+                        const opt::Operand& dst_operand);
+  bool DoOperandsMatch(const opt::Instruction* src_inst,
+                       const opt::Instruction* dst_inst,
+                       uint32_t in_operand_index_start,
+                       uint32_t in_operand_count);
+  bool DoInstructionsMatch(const opt::Instruction* src_inst,
+                           const opt::Instruction* dst_inst);
+  bool DoIdsMatchFuzzy(uint32_t src_id, uint32_t dst_id);
+  bool DoesOperandMatchFuzzy(const opt::Operand& src_operand,
+                             const opt::Operand& dst_operand);
+  bool DoInstructionsMatchFuzzy(const opt::Instruction* src_inst,
+                                const opt::Instruction* dst_inst);
+  bool AreIdenticalUintConstants(uint32_t src_id, uint32_t dst_id);
+  bool DoDebugAndAnnotationInstructionsMatch(const opt::Instruction* src_inst,
+                                             const opt::Instruction* dst_inst);
+  bool AreVariablesMatchable(uint32_t src_id, uint32_t dst_id,
+                             uint32_t flexibility);
+  bool MatchOpTypeStruct(const opt::Instruction* src_inst,
+                         const opt::Instruction* dst_inst,
+                         uint32_t flexibility);
+  bool MatchOpConstant(const opt::Instruction* src_inst,
+                       const opt::Instruction* dst_inst, uint32_t flexibility);
+  bool MatchOpSpecConstant(const opt::Instruction* src_inst,
+                           const opt::Instruction* dst_inst);
+  bool MatchOpVariable(const opt::Instruction* src_inst,
+                       const opt::Instruction* dst_inst, uint32_t flexibility);
+  bool MatchPerVertexType(uint32_t src_type_id, uint32_t dst_type_id);
+  bool MatchPerVertexVariable(const opt::Instruction* src_inst,
+                              const opt::Instruction* dst_inst);
+
+  // Helper functions for matching OpTypeForwardPointer
+  void MatchTypeForwardPointersByName(const IdGroup& src, const IdGroup& dst);
+  void MatchTypeForwardPointersByTypeOp(const IdGroup& src, const IdGroup& dst);
+
+  // Helper functions for function matching.
+  using FunctionMap = std::map<uint32_t, const opt::Function*>;
+
+  InstructionList GetFunctionBody(opt::IRContext* context,
+                                  opt::Function& function);
+  InstructionList GetFunctionHeader(const opt::Function& function);
+  void GetFunctionBodies(opt::IRContext* context, FunctionMap* functions,
+                         FunctionInstMap* function_insts);
+  void GetFunctionHeaderInstructions(const opt::Module* module,
+                                     FunctionInstMap* function_insts);
+  void BestEffortMatchFunctions(const IdGroup& src_func_ids,
+                                const IdGroup& dst_func_ids,
+                                const FunctionInstMap& src_func_insts,
+                                const FunctionInstMap& dst_func_insts);
+
+  // Calculates the diff of two function bodies.  Note that the matched
+  // instructions themselves may not be identical; output of exact matches
+  // should produce the exact instruction while inexact matches should produce a
+  // diff as well.
+  //
+  // Returns the similarity of the two bodies = 2*N_match / (N_src + N_dst)
+  void MatchFunctionParamIds(const opt::Function* src_func,
+                             const opt::Function* dst_func);
+  float MatchFunctionBodies(const InstructionList& src_body,
+                            const InstructionList& dst_body,
+                            DiffMatch* src_match_result,
+                            DiffMatch* dst_match_result);
+  void MatchIdsInFunctionBodies(const InstructionList& src_body,
+                                const InstructionList& dst_body,
+                                const DiffMatch& src_match_result,
+                                const DiffMatch& dst_match_result,
+                                uint32_t flexibility);
+  void MatchVariablesUsedByMatchedInstructions(const opt::Instruction* src_inst,
+                                               const opt::Instruction* dst_inst,
+                                               uint32_t flexibility);
+
+  // Helper functions to retrieve information pertaining to an id
+  const opt::Instruction* GetInst(const IdInstructions& id_to, uint32_t id);
+  uint32_t GetConstantUint(const IdInstructions& id_to, uint32_t constant_id);
+  SpvExecutionModel GetExecutionModel(const opt::Module* module,
+                                      uint32_t entry_point_id);
+  bool HasName(const IdInstructions& id_to, uint32_t id);
+  // Get the OpName associated with an id
+  std::string GetName(const IdInstructions& id_to, uint32_t id, bool* has_name);
+  // Get the OpName associated with an id, with argument types stripped for
+  // functions.  Some tools don't encode function argument types in the OpName
+  // string, and this improves diff between SPIR-V from those tools and others.
+  std::string GetSanitizedName(const IdInstructions& id_to, uint32_t id);
+  uint32_t GetVarTypeId(const IdInstructions& id_to, uint32_t var_id,
+                        SpvStorageClass* storage_class);
+  bool GetDecorationValue(const IdInstructions& id_to, uint32_t id,
+                          SpvDecoration decoration, uint32_t* decoration_value);
+  const opt::Instruction* GetForwardPointerInst(const IdInstructions& id_to,
+                                                uint32_t id);
+  bool IsIntType(const IdInstructions& id_to, uint32_t type_id);
+  bool IsFloatType(const IdInstructions& id_to, uint32_t type_id);
+  bool IsConstantUint(const IdInstructions& id_to, uint32_t id);
+  bool IsVariable(const IdInstructions& id_to, uint32_t pointer_id);
+  bool IsOp(const IdInstructions& id_to, uint32_t id, SpvOp opcode);
+  bool IsPerVertexType(const IdInstructions& id_to, uint32_t type_id);
+  bool IsPerVertexVariable(const IdInstructions& id_to, uint32_t type_id);
+  SpvStorageClass GetPerVertexStorageClass(const opt::Module* module,
+                                           uint32_t type_id);
+  spv_ext_inst_type_t GetExtInstType(const IdInstructions& id_to,
+                                     uint32_t set_id);
+  spv_number_kind_t GetNumberKind(const IdInstructions& id_to,
+                                  const opt::Instruction& inst,
+                                  uint32_t operand_index,
+                                  uint32_t* number_bit_width);
+  spv_number_kind_t GetTypeNumberKind(const IdInstructions& id_to, uint32_t id,
+                                      uint32_t* number_bit_width);
+
+  // Helper functions to output a diff line
+  const opt::Instruction* MappedDstInst(const opt::Instruction* src_inst);
+  const opt::Instruction* MappedSrcInst(const opt::Instruction* dst_inst);
+  const opt::Instruction* MappedInstImpl(const opt::Instruction* inst,
+                                         const IdMap& to_other,
+                                         const IdInstructions& other_id_to);
+  void OutputLine(std::function<bool()> are_lines_identical,
+                  std::function<void()> output_src_line,
+                  std::function<void()> output_dst_line);
+  template <typename InstList>
+  void OutputSection(
+      const InstList& src_insts, const InstList& dst_insts,
+      std::function<void(const opt::Instruction&, const IdInstructions&,
+                         const opt::Instruction&)>
+          write_inst);
+  void ToParsedInstruction(const opt::Instruction& inst,
+                           const IdInstructions& id_to,
+                           const opt::Instruction& original_inst,
+                           spv_parsed_instruction_t* parsed_inst,
+                           std::vector<spv_parsed_operand_t>& parsed_operands,
+                           std::vector<uint32_t>& inst_binary);
+  opt::Instruction ToMappedSrcIds(const opt::Instruction& dst_inst);
+
+  void OutputRed() {
+    if (options_.color_output) out_ << spvtools::clr::red{true};
+  }
+  void OutputGreen() {
+    if (options_.color_output) out_ << spvtools::clr::green{true};
+  }
+  void OutputResetColor() {
+    if (options_.color_output) out_ << spvtools::clr::reset{true};
+  }
+
+  opt::IRContext* src_context_;
+  opt::IRContext* dst_context_;
+  const opt::Module* src_;
+  const opt::Module* dst_;
+  Options options_;
+  std::ostream& out_;
+
+  // Helpers to look up instructions based on id.
+  IdInstructions src_id_to_;
+  IdInstructions dst_id_to_;
+
+  // The ids that have been matched between src and dst so far.
+  SrcDstIdMap id_map_;
+
+  // List of instructions in function bodies after canonicalization.  Cached
+  // here to avoid duplicate work.  More importantly, some maps use
+  // opt::Instruction pointers so they need to be unique.
+  FunctionInstMap src_func_insts_;
+  FunctionInstMap dst_func_insts_;
+  FunctionMap src_funcs_;
+  FunctionMap dst_funcs_;
+};
+
+void IdMap::MapUnmatchedIds(IdMap& other_way) {
+  const uint32_t src_id_bound = static_cast<uint32_t>(id_map_.size());
+  const uint32_t dst_id_bound = static_cast<uint32_t>(other_way.id_map_.size());
+
+  uint32_t next_src_id = src_id_bound;
+  uint32_t next_dst_id = dst_id_bound;
+
+  for (uint32_t src_id = 1; src_id < src_id_bound; ++src_id) {
+    if (!IsMapped(src_id)) {
+      MapIds(src_id, next_dst_id);
+
+      other_way.id_map_.push_back(0);
+      other_way.MapIds(next_dst_id++, src_id);
+    }
+  }
+
+  for (uint32_t dst_id = 1; dst_id < dst_id_bound; ++dst_id) {
+    if (!other_way.IsMapped(dst_id)) {
+      id_map_.push_back(0);
+      MapIds(next_src_id, dst_id);
+
+      other_way.MapIds(dst_id, next_src_id++);
+    }
+  }
+}
+
+void SrcDstIdMap::MapUnmatchedIds() {
+  src_to_dst_.MapUnmatchedIds(dst_to_src_);
+}
+
+void IdInstructions::MapIdToInstruction(uint32_t id,
+                                        const opt::Instruction* inst) {
+  assert(id != 0);
+  assert(id < inst_map_.size());
+  assert(inst_map_[id] == nullptr);
+
+  inst_map_[id] = inst;
+}
+
+void IdInstructions::MapIdsToInstruction(
+    opt::IteratorRange<opt::Module::const_inst_iterator> section) {
+  for (const opt::Instruction& inst : section) {
+    uint32_t result_id = inst.result_id();
+    if (result_id == 0) {
+      continue;
+    }
+
+    MapIdToInstruction(result_id, &inst);
+  }
+}
+
+void IdInstructions::MapIdsToInfos(
+    opt::IteratorRange<opt::Module::const_inst_iterator> section) {
+  for (const opt::Instruction& inst : section) {
+    IdToInfoMap* info_map = nullptr;
+    uint32_t id_operand = 0;
+
+    switch (inst.opcode()) {
+      case SpvOpName:
+        info_map = &name_map_;
+        break;
+      case SpvOpMemberName:
+        info_map = &name_map_;
+        break;
+      case SpvOpDecorate:
+        info_map = &decoration_map_;
+        break;
+      case SpvOpMemberDecorate:
+        info_map = &decoration_map_;
+        break;
+      case SpvOpTypeForwardPointer: {
+        uint32_t id = inst.GetSingleWordOperand(0);
+        assert(id != 0);
+
+        assert(id < forward_pointer_map_.size());
+        forward_pointer_map_[id] = &inst;
+        continue;
+      }
+      default:
+        // Currently unsupported instruction, don't attempt to use it for
+        // matching.
+        break;
+    }
+
+    if (info_map == nullptr) {
+      continue;
+    }
+
+    uint32_t id = inst.GetOperand(id_operand).AsId();
+    assert(id != 0);
+
+    assert(id < info_map->size());
+    assert(std::find((*info_map)[id].begin(), (*info_map)[id].end(), &inst) ==
+           (*info_map)[id].end());
+
+    (*info_map)[id].push_back(&inst);
+  }
+}
+
+void Differ::PoolPotentialIds(
+    opt::IteratorRange<opt::Module::const_inst_iterator> section,
+    std::vector<uint32_t>& ids, bool is_src,
+    std::function<bool(const opt::Instruction&)> filter,
+    std::function<uint32_t(const opt::Instruction&)> get_id) {
+  for (const opt::Instruction& inst : section) {
+    if (!filter(inst)) {
+      continue;
+    }
+
+    uint32_t result_id = get_id(inst);
+    assert(result_id != 0);
+
+    assert(std::find(ids.begin(), ids.end(), result_id) == ids.end());
+
+    // Don't include ids that are already matched, for example through
+    // OpTypeForwardPointer.
+    const bool is_matched = is_src ? id_map_.IsSrcMapped(result_id)
+                                   : id_map_.IsDstMapped(result_id);
+    if (is_matched) {
+      continue;
+    }
+
+    ids.push_back(result_id);
+  }
+}
+
+void Differ::MatchIds(
+    PotentialIdMap& potential,
+    std::function<bool(const opt::Instruction*, const opt::Instruction*)>
+        match) {
+  for (size_t src_index = 0; src_index < potential.src_ids.size();
+       ++src_index) {
+    for (size_t dst_index = 0; dst_index < potential.dst_ids.size();
+         ++dst_index) {
+      const uint32_t src_id = potential.src_ids[src_index];
+      const uint32_t dst_id = potential.dst_ids[dst_index];
+
+      if (dst_id == 0) {
+        // Already matched.
+        continue;
+      }
+
+      const opt::Instruction* src_inst = src_id_to_.inst_map_[src_id];
+      const opt::Instruction* dst_inst = dst_id_to_.inst_map_[dst_id];
+
+      if (match(src_inst, dst_inst)) {
+        id_map_.MapIds(src_id, dst_id);
+
+        // Remove the ids from the potential list.
+        potential.src_ids[src_index] = 0;
+        potential.dst_ids[dst_index] = 0;
+
+        // Find a match for the next src id.
+        break;
+      }
+    }
+  }
+
+  // Remove matched ids to make the next iteration faster.
+  CompactIds(potential.src_ids);
+  CompactIds(potential.dst_ids);
+}
+
+void Differ::MatchPreambleInstructions(
+    opt::IteratorRange<opt::Module::const_inst_iterator> src_insts,
+    opt::IteratorRange<opt::Module::const_inst_iterator> dst_insts) {
+  // First, pool all instructions from each section and sort them.
+  InstructionList sorted_src_insts = SortPreambleInstructions(src_, src_insts);
+  InstructionList sorted_dst_insts = SortPreambleInstructions(dst_, dst_insts);
+
+  // Then walk and match them.
+  size_t src_cur = 0;
+  size_t dst_cur = 0;
+
+  while (src_cur < sorted_src_insts.size() &&
+         dst_cur < sorted_dst_insts.size()) {
+    const opt::Instruction* src_inst = sorted_src_insts[src_cur];
+    const opt::Instruction* dst_inst = sorted_dst_insts[dst_cur];
+
+    int compare = ComparePreambleInstructions(src_inst, dst_inst, src_, dst_);
+    if (compare == 0) {
+      id_map_.MapInsts(src_inst, dst_inst);
+    }
+    if (compare <= 0) {
+      ++src_cur;
+    }
+    if (compare >= 0) {
+      ++dst_cur;
+    }
+  }
+}
+
+InstructionList Differ::SortPreambleInstructions(
+    const opt::Module* module,
+    opt::IteratorRange<opt::Module::const_inst_iterator> insts) {
+  InstructionList sorted;
+  for (const opt::Instruction& inst : insts) {
+    sorted.push_back(&inst);
+  }
+  std::sort(
+      sorted.begin(), sorted.end(),
+      [this, module](const opt::Instruction* a, const opt::Instruction* b) {
+        return ComparePreambleInstructions(a, b, module, module) < 0;
+      });
+  return sorted;
+}
+
+int Differ::ComparePreambleInstructions(const opt::Instruction* a,
+                                        const opt::Instruction* b,
+                                        const opt::Module* src_inst_module,
+                                        const opt::Module* dst_inst_module) {
+  assert(a->opcode() == b->opcode());
+  assert(!a->HasResultId());
+  assert(!a->HasResultType());
+
+  const uint32_t a_operand_count = a->NumOperands();
+  const uint32_t b_operand_count = b->NumOperands();
+
+  if (a_operand_count < b_operand_count) {
+    return -1;
+  }
+  if (a_operand_count > b_operand_count) {
+    return 1;
+  }
+
+  // Instead of comparing OpExecutionMode entry point ids as ids, compare them
+  // through their corresponding execution model.  This simplifies traversing
+  // the sorted list of instructions between src and dst modules.
+  if (a->opcode() == SpvOpExecutionMode) {
+    const SpvExecutionModel src_model =
+        GetExecutionModel(src_inst_module, a->GetSingleWordOperand(0));
+    const SpvExecutionModel dst_model =
+        GetExecutionModel(dst_inst_module, b->GetSingleWordOperand(0));
+
+    if (src_model < dst_model) {
+      return -1;
+    }
+    if (src_model > dst_model) {
+      return 1;
+    }
+  }
+
+  // Match every operand of the instruction.
+  for (uint32_t operand_index = 0; operand_index < a_operand_count;
+       ++operand_index) {
+    const opt::Operand& a_operand = a->GetOperand(operand_index);
+    const opt::Operand& b_operand = b->GetOperand(operand_index);
+
+    if (a_operand.type < b_operand.type) {
+      return -1;
+    }
+    if (a_operand.type > b_operand.type) {
+      return 1;
+    }
+
+    assert(a_operand.words.size() == 1);
+    assert(b_operand.words.size() == 1);
+
+    switch (a_operand.type) {
+      case SPV_OPERAND_TYPE_ID:
+        // Don't compare ids, there can't be multiple instances of the
+        // OpExecutionMode with different ids of the same execution model.
+        break;
+      case SPV_OPERAND_TYPE_TYPE_ID:
+      case SPV_OPERAND_TYPE_MEMORY_SEMANTICS_ID:
+      case SPV_OPERAND_TYPE_SCOPE_ID:
+        assert(false && "Unreachable");
+        break;
+      case SPV_OPERAND_TYPE_LITERAL_STRING: {
+        int str_compare =
+            strcmp(a_operand.AsString().c_str(), b_operand.AsString().c_str());
+        if (str_compare != 0) {
+          return str_compare;
+        }
+        break;
+      }
+      default:
+        // Expect literal values to match.
+        if (a_operand.words[0] < b_operand.words[0]) {
+          return -1;
+        }
+        if (a_operand.words[0] > b_operand.words[0]) {
+          return 1;
+        }
+        break;
+    }
+  }
+
+  return 0;
+}
+
+void Differ::MatchDebugAndAnnotationInstructions(
+    opt::IteratorRange<opt::Module::const_inst_iterator> src_insts,
+    opt::IteratorRange<opt::Module::const_inst_iterator> dst_insts) {
+  for (const opt::Instruction& src_inst : src_insts) {
+    for (const opt::Instruction& dst_inst : dst_insts) {
+      if (MappedSrcInst(&dst_inst) != nullptr) {
+        continue;
+      }
+
+      // Map instructions as soon as they match.  Debug and annotation
+      // instructions are matched such that there can't be multiple matches.
+      if (DoDebugAndAnnotationInstructionsMatch(&src_inst, &dst_inst)) {
+        id_map_.MapInsts(&src_inst, &dst_inst);
+        break;
+      }
+    }
+  }
+}
+
+uint32_t Differ::GroupIdsHelperGetTypeId(const IdInstructions& id_to,
+                                         uint32_t id) {
+  return GetInst(id_to, id)->type_id();
+}
+
+SpvStorageClass Differ::GroupIdsHelperGetTypePointerStorageClass(
+    const IdInstructions& id_to, uint32_t id) {
+  const opt::Instruction* inst = GetInst(id_to, id);
+  assert(inst && inst->opcode() == SpvOpTypePointer);
+  return SpvStorageClass(inst->GetSingleWordInOperand(0));
+}
+
+SpvOp Differ::GroupIdsHelperGetTypePointerTypeOp(const IdInstructions& id_to,
+                                                 uint32_t id) {
+  const opt::Instruction* inst = GetInst(id_to, id);
+  assert(inst && inst->opcode() == SpvOpTypePointer);
+
+  const uint32_t type_id = inst->GetSingleWordInOperand(1);
+  const opt::Instruction* type_inst = GetInst(id_to, type_id);
+  assert(type_inst);
+
+  return type_inst->opcode();
+}
+
+template <typename T>
+void Differ::GroupIds(const IdGroup& ids, bool is_src,
+                      std::map<T, IdGroup>* groups,
+                      T (Differ::*get_group)(const IdInstructions&, uint32_t)) {
+  assert(groups->empty());
+
+  const IdInstructions& id_to = is_src ? src_id_to_ : dst_id_to_;
+
+  for (const uint32_t id : ids) {
+    // Don't include ids that are already matched, for example through
+    // OpEntryPoint.
+    const bool is_matched =
+        is_src ? id_map_.IsSrcMapped(id) : id_map_.IsDstMapped(id);
+    if (is_matched) {
+      continue;
+    }
+
+    T group = (this->*get_group)(id_to, id);
+    (*groups)[group].push_back(id);
+  }
+}
+
+template <typename T>
+void Differ::GroupIdsAndMatch(
+    const IdGroup& src_ids, const IdGroup& dst_ids, T invalid_group_key,
+    T (Differ::*get_group)(const IdInstructions&, uint32_t),
+    std::function<void(const IdGroup& src_group, const IdGroup& dst_group)>
+        match_group) {
+  // Group the ids based on a key (get_group)
+  std::map<T, IdGroup> src_groups;
+  std::map<T, IdGroup> dst_groups;
+
+  GroupIds<T>(src_ids, true, &src_groups, get_group);
+  GroupIds<T>(dst_ids, false, &dst_groups, get_group);
+
+  // Iterate over the groups, and match those with identical keys
+  for (const auto& iter : src_groups) {
+    const T& key = iter.first;
+    const IdGroup& src_group = iter.second;
+
+    if (key == invalid_group_key) {
+      continue;
+    }
+
+    const IdGroup& dst_group = dst_groups[key];
+
+    // Let the caller match the groups as appropriate.
+    match_group(src_group, dst_group);
+  }
+}
+
+bool Differ::DoIdsMatch(uint32_t src_id, uint32_t dst_id) {
+  assert(dst_id != 0);
+  return id_map_.MappedDstId(src_id) == dst_id;
+}
+
+bool Differ::DoesOperandMatch(const opt::Operand& src_operand,
+                              const opt::Operand& dst_operand) {
+  assert(src_operand.type == dst_operand.type);
+
+  switch (src_operand.type) {
+    case SPV_OPERAND_TYPE_ID:
+    case SPV_OPERAND_TYPE_TYPE_ID:
+    case SPV_OPERAND_TYPE_RESULT_ID:
+    case SPV_OPERAND_TYPE_MEMORY_SEMANTICS_ID:
+    case SPV_OPERAND_TYPE_SCOPE_ID:
+      // Match ids only if they are already matched in the id map.
+      return DoIdsMatch(src_operand.AsId(), dst_operand.AsId());
+    case SPV_OPERAND_TYPE_LITERAL_STRING:
+      return src_operand.AsString() == dst_operand.AsString();
+    default:
+      // Otherwise expect them to match exactly.
+      assert(src_operand.type != SPV_OPERAND_TYPE_LITERAL_STRING);
+      if (src_operand.words.size() != dst_operand.words.size()) {
+        return false;
+      }
+      for (size_t i = 0; i < src_operand.words.size(); ++i) {
+        if (src_operand.words[i] != dst_operand.words[i]) {
+          return false;
+        }
+      }
+      return true;
+  }
+}
+
+bool Differ::DoOperandsMatch(const opt::Instruction* src_inst,
+                             const opt::Instruction* dst_inst,
+                             uint32_t in_operand_index_start,
+                             uint32_t in_operand_count) {
+  // Caller should have returned early for instructions with different opcode.
+  assert(src_inst->opcode() == dst_inst->opcode());
+
+  bool match = true;
+  for (uint32_t i = 0; i < in_operand_count; ++i) {
+    const uint32_t in_operand_index = in_operand_index_start + i;
+
+    const opt::Operand& src_operand = src_inst->GetInOperand(in_operand_index);
+    const opt::Operand& dst_operand = dst_inst->GetInOperand(in_operand_index);
+
+    match = match && DoesOperandMatch(src_operand, dst_operand);
+  }
+
+  return match;
+}
+
+bool Differ::DoInstructionsMatch(const opt::Instruction* src_inst,
+                                 const opt::Instruction* dst_inst) {
+  // Check whether the two instructions are identical, that is the instructions
+  // themselves are matched, every id is matched, and every other value is
+  // identical.
+  if (MappedDstInst(src_inst) != dst_inst) {
+    return false;
+  }
+
+  assert(src_inst->opcode() == dst_inst->opcode());
+  if (src_inst->NumOperands() != dst_inst->NumOperands()) {
+    return false;
+  }
+
+  for (uint32_t operand_index = 0; operand_index < src_inst->NumOperands();
+       ++operand_index) {
+    const opt::Operand& src_operand = src_inst->GetOperand(operand_index);
+    const opt::Operand& dst_operand = dst_inst->GetOperand(operand_index);
+
+    if (!DoesOperandMatch(src_operand, dst_operand)) {
+      return false;
+    }
+  }
+
+  return true;
+}
+
+bool Differ::DoIdsMatchFuzzy(uint32_t src_id, uint32_t dst_id) {
+  assert(dst_id != 0);
+  const uint32_t mapped_dst_id = id_map_.MappedDstId(src_id);
+
+  // Consider unmatched ids as a match.  In function bodies, no result id is
+  // matched yet and thus they are excluded from instruction matching when used
+  // as parameters in subsequent instructions.
+  if (mapped_dst_id == 0 || mapped_dst_id == dst_id) {
+    return true;
+  }
+
+  // Int and Uint constants are interchangeable, match them in that case.
+  if (AreIdenticalUintConstants(src_id, dst_id)) {
+    return true;
+  }
+
+  return false;
+}
+
+bool Differ::DoesOperandMatchFuzzy(const opt::Operand& src_operand,
+                                   const opt::Operand& dst_operand) {
+  if (src_operand.type != dst_operand.type) {
+    return false;
+  }
+
+  assert(src_operand.type != SPV_OPERAND_TYPE_RESULT_ID);
+  assert(dst_operand.type != SPV_OPERAND_TYPE_RESULT_ID);
+
+  switch (src_operand.type) {
+    case SPV_OPERAND_TYPE_ID:
+    case SPV_OPERAND_TYPE_TYPE_ID:
+    case SPV_OPERAND_TYPE_MEMORY_SEMANTICS_ID:
+    case SPV_OPERAND_TYPE_SCOPE_ID:
+      // Match id operands only if they are already matched in the id map.
+      return DoIdsMatchFuzzy(src_operand.AsId(), dst_operand.AsId());
+    default:
+      // Otherwise allow everything to match.
+      return true;
+  }
+}
+
+bool Differ::DoInstructionsMatchFuzzy(const opt::Instruction* src_inst,
+                                      const opt::Instruction* dst_inst) {
+  // Similar to DoOperandsMatch, but only checks that ids that have already been
+  // matched are identical.  Ids that are unknown are allowed to match, as well
+  // as any non-id operand.
+  if (src_inst->opcode() != dst_inst->opcode()) {
+    return false;
+  }
+  // For external instructions, make sure the set and opcode of the external
+  // instruction matches too.
+  if (src_inst->opcode() == SpvOpExtInst) {
+    if (!DoOperandsMatch(src_inst, dst_inst, 0, 2)) {
+      return false;
+    }
+  }
+
+  assert(src_inst->HasResultType() == dst_inst->HasResultType());
+  if (src_inst->HasResultType() &&
+      !DoIdsMatchFuzzy(src_inst->type_id(), dst_inst->type_id())) {
+    return false;
+  }
+
+  // TODO: allow some instructions to match with different instruction lengths,
+  // for example OpImage* with additional operands.
+  if (src_inst->NumInOperandWords() != dst_inst->NumInOperandWords()) {
+    return false;
+  }
+
+  bool match = true;
+  for (uint32_t in_operand_index = 0;
+       in_operand_index < src_inst->NumInOperandWords(); ++in_operand_index) {
+    const opt::Operand& src_operand = src_inst->GetInOperand(in_operand_index);
+    const opt::Operand& dst_operand = dst_inst->GetInOperand(in_operand_index);
+
+    match = match && DoesOperandMatchFuzzy(src_operand, dst_operand);
+  }
+
+  return match;
+}
+
+bool Differ::AreIdenticalUintConstants(uint32_t src_id, uint32_t dst_id) {
+  return IsConstantUint(src_id_to_, src_id) &&
+         IsConstantUint(dst_id_to_, dst_id) &&
+         GetConstantUint(src_id_to_, src_id) ==
+             GetConstantUint(dst_id_to_, dst_id);
+}
+
+bool Differ::DoDebugAndAnnotationInstructionsMatch(
+    const opt::Instruction* src_inst, const opt::Instruction* dst_inst) {
+  if (src_inst->opcode() != dst_inst->opcode()) {
+    return false;
+  }
+
+  switch (src_inst->opcode()) {
+    case SpvOpString:
+    case SpvOpSourceExtension:
+    case SpvOpModuleProcessed:
+      return DoesOperandMatch(src_inst->GetOperand(0), dst_inst->GetOperand(0));
+    case SpvOpSource:
+      return DoOperandsMatch(src_inst, dst_inst, 0, 2);
+    case SpvOpSourceContinued:
+      return true;
+    case SpvOpName:
+      return DoOperandsMatch(src_inst, dst_inst, 0, 1);
+    case SpvOpMemberName:
+      return DoOperandsMatch(src_inst, dst_inst, 0, 2);
+    case SpvOpDecorate:
+      return DoOperandsMatch(src_inst, dst_inst, 0, 2);
+    case SpvOpMemberDecorate:
+      return DoOperandsMatch(src_inst, dst_inst, 0, 3);
+    case SpvOpExtInst:
+    case SpvOpDecorationGroup:
+    case SpvOpGroupDecorate:
+    case SpvOpGroupMemberDecorate:
+      return false;
+    default:
+      return false;
+  }
+}
+
+bool Differ::AreVariablesMatchable(uint32_t src_id, uint32_t dst_id,
+                                   uint32_t flexibility) {
+  // Variables must match by their built-in decorations.
+  uint32_t src_built_in_decoration = 0, dst_built_in_decoration = 0;
+  const bool src_is_built_in = GetDecorationValue(
+      src_id_to_, src_id, SpvDecorationBuiltIn, &src_built_in_decoration);
+  const bool dst_is_built_in = GetDecorationValue(
+      dst_id_to_, dst_id, SpvDecorationBuiltIn, &dst_built_in_decoration);
+
+  if (src_is_built_in != dst_is_built_in) {
+    return false;
+  }
+  if (src_is_built_in && src_built_in_decoration != dst_built_in_decoration) {
+    return false;
+  }
+
+  // Check their types and storage classes.
+  SpvStorageClass src_storage_class, dst_storage_class;
+  const uint32_t src_type_id =
+      GetVarTypeId(src_id_to_, src_id, &src_storage_class);
+  const uint32_t dst_type_id =
+      GetVarTypeId(dst_id_to_, dst_id, &dst_storage_class);
+
+  if (!DoIdsMatch(src_type_id, dst_type_id)) {
+    return false;
+  }
+  switch (flexibility) {
+    case 0:
+      if (src_storage_class != dst_storage_class) {
+        return false;
+      }
+      break;
+    case 1:
+      if (src_storage_class != dst_storage_class) {
+        // Allow one of the two to be Private while the other is Input or
+        // Output, this allows matching in/out variables that have been turned
+        // global as part of linking two stages (as done in ANGLE).
+        const bool src_is_io = src_storage_class == SpvStorageClassInput ||
+                               src_storage_class == SpvStorageClassOutput;
+        const bool dst_is_io = dst_storage_class == SpvStorageClassInput ||
+                               dst_storage_class == SpvStorageClassOutput;
+        const bool src_is_private = src_storage_class == SpvStorageClassPrivate;
+        const bool dst_is_private = dst_storage_class == SpvStorageClassPrivate;
+
+        if (!((src_is_io && dst_is_private) || (src_is_private && dst_is_io))) {
+          return false;
+        }
+      }
+      break;
+    default:
+      assert(false && "Unreachable");
+      return false;
+  }
+
+  // TODO: Is there any other way to check compatiblity of the variables?  It's
+  // easy to tell when the variables definitely don't match, but there's little
+  // information that can be used for a definite match.
+  return true;
+}
+
+bool Differ::MatchOpTypeStruct(const opt::Instruction* src_inst,
+                               const opt::Instruction* dst_inst,
+                               uint32_t flexibility) {
+  const uint32_t src_type_id = src_inst->result_id();
+  const uint32_t dst_type_id = dst_inst->result_id();
+
+  bool src_has_name = false, dst_has_name = false;
+  std::string src_name = GetName(src_id_to_, src_type_id, &src_has_name);
+  std::string dst_name = GetName(dst_id_to_, dst_type_id, &dst_has_name);
+
+  // If debug info is present, always match the structs by name.
+  if (src_has_name && dst_has_name) {
+    if (src_name != dst_name) {
+      return false;
+    }
+
+    // For gl_PerVertex, find the type pointer of this type (array) and make
+    // sure the storage classes of src and dst match; geometry and tessellation
+    // shaders have two instances of gl_PerVertex.
+    if (src_name == "gl_PerVertex") {
+      return MatchPerVertexType(src_type_id, dst_type_id);
+    }
+
+    return true;
+  }
+
+  // If debug info is not present, match the structs by their type.
+
+  // For gl_PerVertex, find the type pointer of this type (array) and match by
+  // storage class. The gl_PerVertex struct is itself found by the BuiltIn
+  // decorations applied to its members.
+  const bool src_is_per_vertex = IsPerVertexType(src_id_to_, src_type_id);
+  const bool dst_is_per_vertex = IsPerVertexType(dst_id_to_, dst_type_id);
+  if (src_is_per_vertex != dst_is_per_vertex) {
+    return false;
+  }
+
+  if (src_is_per_vertex) {
+    return MatchPerVertexType(src_type_id, dst_type_id);
+  }
+
+  switch (flexibility) {
+    case 0:
+      if (src_inst->NumInOperandWords() != dst_inst->NumInOperandWords()) {
+        return false;
+      }
+      return DoOperandsMatch(src_inst, dst_inst, 0,
+                             src_inst->NumInOperandWords());
+    case 1:
+      // TODO: match by taking a diff of the fields, and see if there's a >75%
+      // match.  Need to then make sure OpMemberName, OpMemberDecorate,
+      // OpAccessChain etc are aware of the struct field matching.
+      return false;
+    default:
+      assert(false && "Unreachable");
+      return false;
+  }
+}
+
+bool Differ::MatchOpConstant(const opt::Instruction* src_inst,
+                             const opt::Instruction* dst_inst,
+                             uint32_t flexibility) {
+  // The constants' type must match.  In flexibility == 1, match constants of
+  // int and uint, as they are generally interchangeable.
+  switch (flexibility) {
+    case 0:
+      if (!DoesOperandMatch(src_inst->GetOperand(0), dst_inst->GetOperand(0))) {
+        return false;
+      }
+      break;
+    case 1:
+      if (!IsIntType(src_id_to_, src_inst->type_id()) ||
+          !IsIntType(dst_id_to_, dst_inst->type_id())) {
+        return false;
+      }
+      break;
+    default:
+      assert(false && "Unreachable");
+      return false;
+  }
+
+  const opt::Operand& src_value_operand = src_inst->GetOperand(2);
+  const opt::Operand& dst_value_operand = dst_inst->GetOperand(2);
+
+  const uint64_t src_value = src_value_operand.AsLiteralUint64();
+  const uint64_t dst_value = dst_value_operand.AsLiteralUint64();
+
+  // If values are identical, it's a match.
+  if (src_value == dst_value) {
+    return true;
+  }
+
+  // Otherwise, only allow flexibility for float types.
+  if (IsFloatType(src_id_to_, src_inst->type_id()) && flexibility == 1) {
+    // Tolerance is:
+    //
+    // - For float: allow 4 bits of mantissa as error
+    // - For double: allow 6 bits of mantissa as error
+    //
+    // TODO: the above values are arbitrary and a placeholder; investigate the
+    // amount of error resulting from using `printf("%f", f)` and `printf("%lf",
+    // d)` and having glslang parse them.
+    const uint64_t tolerance = src_value_operand.words.size() == 1 ? 16 : 64;
+    return src_value - dst_value < tolerance ||
+           dst_value - src_value < tolerance;
+  }
+
+  return false;
+}
+
+bool Differ::MatchOpSpecConstant(const opt::Instruction* src_inst,
+                                 const opt::Instruction* dst_inst) {
+  const uint32_t src_id = src_inst->result_id();
+  const uint32_t dst_id = dst_inst->result_id();
+
+  bool src_has_name = false, dst_has_name = false;
+  std::string src_name = GetName(src_id_to_, src_id, &src_has_name);
+  std::string dst_name = GetName(dst_id_to_, dst_id, &dst_has_name);
+
+  // If debug info is present, always match the spec consts by name.
+  if (src_has_name && dst_has_name) {
+    return src_name == dst_name;
+  }
+
+  // Otherwise, match them by SpecId.
+  uint32_t src_spec_id, dst_spec_id;
+
+  if (GetDecorationValue(src_id_to_, src_id, SpvDecorationSpecId,
+                         &src_spec_id) &&
+      GetDecorationValue(dst_id_to_, dst_id, SpvDecorationSpecId,
+                         &dst_spec_id)) {
+    return src_spec_id == dst_spec_id;
+  }
+
+  // There is no spec id, this is not valid.
+  assert(false && "Unreachable");
+  return false;
+}
+
+bool Differ::MatchOpVariable(const opt::Instruction* src_inst,
+                             const opt::Instruction* dst_inst,
+                             uint32_t flexibility) {
+  const uint32_t src_id = src_inst->result_id();
+  const uint32_t dst_id = dst_inst->result_id();
+
+  const bool src_is_pervertex = IsPerVertexVariable(src_id_to_, src_id);
+  const bool dst_is_pervertex = IsPerVertexVariable(dst_id_to_, dst_id);
+
+  // For gl_PerVertex, make sure the input and output instances are matched
+  // correctly.
+  if (src_is_pervertex != dst_is_pervertex) {
+    return false;
+  }
+  if (src_is_pervertex) {
+    return MatchPerVertexVariable(src_inst, dst_inst);
+  }
+
+  bool src_has_name = false, dst_has_name = false;
+  std::string src_name = GetName(src_id_to_, src_id, &src_has_name);
+  std::string dst_name = GetName(dst_id_to_, dst_id, &dst_has_name);
+
+  // If debug info is present, always match the variables by name.
+  if (src_has_name && dst_has_name) {
+    return src_name == dst_name;
+  }
+
+  // If debug info is not present, see if the variables can be matched by their
+  // built-in decorations.
+  uint32_t src_built_in_decoration;
+  const bool src_is_built_in = GetDecorationValue(
+      src_id_to_, src_id, SpvDecorationBuiltIn, &src_built_in_decoration);
+
+  if (src_is_built_in && AreVariablesMatchable(src_id, dst_id, flexibility)) {
+    return true;
+  }
+
+  SpvStorageClass src_storage_class, dst_storage_class;
+  GetVarTypeId(src_id_to_, src_id, &src_storage_class);
+  GetVarTypeId(dst_id_to_, dst_id, &dst_storage_class);
+
+  if (src_storage_class != dst_storage_class) {
+    return false;
+  }
+
+  // If variables are decorated with set/binding, match by the value of those
+  // decorations.
+  if (!options_.ignore_set_binding) {
+    uint32_t src_set = 0, dst_set = 0;
+    uint32_t src_binding = 0, dst_binding = 0;
+
+    const bool src_has_set = GetDecorationValue(
+        src_id_to_, src_id, SpvDecorationDescriptorSet, &src_set);
+    const bool dst_has_set = GetDecorationValue(
+        dst_id_to_, dst_id, SpvDecorationDescriptorSet, &dst_set);
+    const bool src_has_binding =
+        GetDecorationValue(src_id_to_, src_id, SpvDecorationBinding, &src_set);
+    const bool dst_has_binding =
+        GetDecorationValue(dst_id_to_, dst_id, SpvDecorationBinding, &dst_set);
+
+    if (src_has_set && dst_has_set && src_has_binding && dst_has_binding) {
+      return src_set == dst_set && src_binding == dst_binding;
+    }
+  }
+
+  // If variables are decorated with location, match by the value of that
+  // decoration.
+  if (!options_.ignore_location) {
+    uint32_t src_location, dst_location;
+
+    const bool src_has_location = GetDecorationValue(
+        src_id_to_, src_id, SpvDecorationLocation, &src_location);
+    const bool dst_has_location = GetDecorationValue(
+        dst_id_to_, dst_id, SpvDecorationLocation, &dst_location);
+
+    if (src_has_location && dst_has_location) {
+      return src_location == dst_location;
+    }
+  }
+
+  // Currently, there's no other way to match variables.
+  return false;
+}
+
+bool Differ::MatchPerVertexType(uint32_t src_type_id, uint32_t dst_type_id) {
+  // For gl_PerVertex, find the type pointer of this type (array) and make sure
+  // the storage classes of src and dst match; geometry and tessellation shaders
+  // have two instances of gl_PerVertex.
+  SpvStorageClass src_storage_class =
+      GetPerVertexStorageClass(src_, src_type_id);
+  SpvStorageClass dst_storage_class =
+      GetPerVertexStorageClass(dst_, dst_type_id);
+
+  assert(src_storage_class == SpvStorageClassInput ||
+         src_storage_class == SpvStorageClassOutput);
+  assert(dst_storage_class == SpvStorageClassInput ||
+         dst_storage_class == SpvStorageClassOutput);
+
+  return src_storage_class == dst_storage_class;
+}
+
+bool Differ::MatchPerVertexVariable(const opt::Instruction* src_inst,
+                                    const opt::Instruction* dst_inst) {
+  SpvStorageClass src_storage_class =
+      SpvStorageClass(src_inst->GetSingleWordInOperand(0));
+  SpvStorageClass dst_storage_class =
+      SpvStorageClass(dst_inst->GetSingleWordInOperand(0));
+
+  return src_storage_class == dst_storage_class;
+}
+
+void Differ::MatchTypeForwardPointersByName(const IdGroup& src,
+                                            const IdGroup& dst) {
+  // Given two sets of compatible groups of OpTypeForwardPointer instructions,
+  // attempts to match them by name.
+
+  // Group them by debug info and loop over them.
+  GroupIdsAndMatch<std::string>(
+      src, dst, "", &Differ::GetSanitizedName,
+      [this](const IdGroup& src_group, const IdGroup& dst_group) {
+
+        // Match only if there's a unique forward declaration with this debug
+        // name.
+        if (src_group.size() == 1 && dst_group.size() == 1) {
+          id_map_.MapIds(src_group[0], dst_group[0]);
+        }
+      });
+}
+
+void Differ::MatchTypeForwardPointersByTypeOp(const IdGroup& src,
+                                              const IdGroup& dst) {
+  // Given two sets of compatible groups of OpTypeForwardPointer instructions,
+  // attempts to match them by type op.  Must be called after
+  // MatchTypeForwardPointersByName to match as many as possible by debug info.
+
+  // Remove ids that are matched with debug info in
+  // MatchTypeForwardPointersByName.
+  IdGroup src_unmatched_ids;
+  IdGroup dst_unmatched_ids;
+
+  std::copy_if(src.begin(), src.end(), std::back_inserter(src_unmatched_ids),
+               [this](uint32_t id) { return !id_map_.IsSrcMapped(id); });
+  std::copy_if(dst.begin(), dst.end(), std::back_inserter(dst_unmatched_ids),
+               [this](uint32_t id) { return !id_map_.IsDstMapped(id); });
+
+  // Match only if there's a unique forward declaration with this
+  // storage class and type opcode.  If both have debug info, they
+  // must not have been matchable.
+  if (src_unmatched_ids.size() == 1 && dst_unmatched_ids.size() == 1) {
+    uint32_t src_id = src_unmatched_ids[0];
+    uint32_t dst_id = dst_unmatched_ids[0];
+    if (!HasName(src_id_to_, src_id) || !HasName(dst_id_to_, dst_id)) {
+      id_map_.MapIds(src_id, dst_id);
+    }
+  }
+}
+
+InstructionList Differ::GetFunctionBody(opt::IRContext* context,
+                                        opt::Function& function) {
+  // Canonicalize the blocks of the function to produce better diff, for example
+  // to not produce any diff if the src and dst have the same switch/case blocks
+  // but with the cases simply reordered.
+  std::list<opt::BasicBlock*> order;
+  context->cfg()->ComputeStructuredOrder(&function, &*function.begin(), &order);
+
+  // Go over the instructions of the function and add the instructions to a flat
+  // list to simplify future iterations.
+  InstructionList body;
+  for (opt::BasicBlock* block : order) {
+    block->ForEachInst(
+        [&body](const opt::Instruction* inst) { body.push_back(inst); }, true);
+  }
+  body.push_back(function.EndInst());
+
+  return body;
+}
+
+InstructionList Differ::GetFunctionHeader(const opt::Function& function) {
+  // Go over the instructions of the function and add the header instructions to
+  // a flat list to simplify diff generation.
+  InstructionList body;
+  function.WhileEachInst(
+      [&body](const opt::Instruction* inst) {
+        if (inst->opcode() == SpvOpLabel) {
+          return false;
+        }
+        body.push_back(inst);
+        return true;
+      },
+      true, true);
+
+  return body;
+}
+
+void Differ::GetFunctionBodies(opt::IRContext* context, FunctionMap* functions,
+                               FunctionInstMap* function_insts) {
+  for (opt::Function& function : *context->module()) {
+    uint32_t id = function.result_id();
+    assert(functions->find(id) == functions->end());
+    assert(function_insts->find(id) == function_insts->end());
+
+    (*functions)[id] = &function;
+
+    InstructionList body = GetFunctionBody(context, function);
+    (*function_insts)[id] = std::move(body);
+  }
+}
+
+void Differ::GetFunctionHeaderInstructions(const opt::Module* module,
+                                           FunctionInstMap* function_insts) {
+  for (opt::Function& function : *module) {
+    InstructionList body = GetFunctionHeader(function);
+    (*function_insts)[function.result_id()] = std::move(body);
+  }
+}
+
+void Differ::BestEffortMatchFunctions(const IdGroup& src_func_ids,
+                                      const IdGroup& dst_func_ids,
+                                      const FunctionInstMap& src_func_insts,
+                                      const FunctionInstMap& dst_func_insts) {
+  struct MatchResult {
+    uint32_t src_id;
+    uint32_t dst_id;
+    DiffMatch src_match;
+    DiffMatch dst_match;
+    float match_rate;
+    bool operator<(const MatchResult& other) const {
+      return match_rate > other.match_rate;
+    }
+  };
+  std::vector<MatchResult> all_match_results;
+
+  for (const uint32_t src_func_id : src_func_ids) {
+    if (id_map_.IsSrcMapped(src_func_id)) {
+      continue;
+    }
+    const std::string src_name = GetSanitizedName(src_id_to_, src_func_id);
+
+    for (const uint32_t dst_func_id : dst_func_ids) {
+      if (id_map_.IsDstMapped(dst_func_id)) {
+        continue;
+      }
+
+      // Don't match functions that are named, but the names are different.
+      const std::string dst_name = GetSanitizedName(dst_id_to_, dst_func_id);
+      if (src_name != "" && dst_name != "" && src_name != dst_name) {
+        continue;
+      }
+
+      DiffMatch src_match_result, dst_match_result;
+      float match_rate = MatchFunctionBodies(
+          src_func_insts.at(src_func_id), dst_func_insts.at(dst_func_id),
+          &src_match_result, &dst_match_result);
+
+      // Only consider the functions a match if there's at least 60% match.
+      // This is an arbitrary limit that should be tuned.
+      constexpr float pass_match_rate = 0.6f;
+      if (match_rate >= pass_match_rate) {
+        all_match_results.emplace_back(
+            MatchResult{src_func_id, dst_func_id, std::move(src_match_result),
+                        std::move(dst_match_result), match_rate});
+      }
+    }
+  }
+
+  std::sort(all_match_results.begin(), all_match_results.end());
+
+  for (const MatchResult& match_result : all_match_results) {
+    if (id_map_.IsSrcMapped(match_result.src_id) ||
+        id_map_.IsDstMapped(match_result.dst_id)) {
+      continue;
+    }
+
+    id_map_.MapIds(match_result.src_id, match_result.dst_id);
+
+    MatchIdsInFunctionBodies(src_func_insts.at(match_result.src_id),
+                             dst_func_insts.at(match_result.dst_id),
+                             match_result.src_match, match_result.dst_match, 0);
+  }
+}
+
+void Differ::MatchFunctionParamIds(const opt::Function* src_func,
+                                   const opt::Function* dst_func) {
+  IdGroup src_params;
+  IdGroup dst_params;
+  src_func->ForEachParam(
+      [&src_params](const opt::Instruction* param) {
+        src_params.push_back(param->result_id());
+      },
+      false);
+  dst_func->ForEachParam(
+      [&dst_params](const opt::Instruction* param) {
+        dst_params.push_back(param->result_id());
+      },
+      false);
+
+  GroupIdsAndMatch<std::string>(
+      src_params, dst_params, "", &Differ::GetSanitizedName,
+      [this](const IdGroup& src_group, const IdGroup& dst_group) {
+
+        // There shouldn't be two parameters with the same name, so the ids
+        // should match. There is nothing restricting the SPIR-V however to have
+        // two parameters with the same name, so be resilient against that.
+        if (src_group.size() == 1 && dst_group.size() == 1) {
+          id_map_.MapIds(src_group[0], dst_group[0]);
+        }
+      });
+
+  // Then match the parameters by their type.  If there are multiple of them,
+  // match them by their order.
+  GroupIdsAndMatch<uint32_t>(
+      src_params, dst_params, 0, &Differ::GroupIdsHelperGetTypeId,
+      [this](const IdGroup& src_group_by_type_id,
+             const IdGroup& dst_group_by_type_id) {
+
+        const size_t shared_param_count =
+            std::min(src_group_by_type_id.size(), dst_group_by_type_id.size());
+
+        for (size_t param_index = 0; param_index < shared_param_count;
+             ++param_index) {
+          id_map_.MapIds(src_group_by_type_id[0], dst_group_by_type_id[0]);
+        }
+      });
+}
+
+float Differ::MatchFunctionBodies(const InstructionList& src_body,
+                                  const InstructionList& dst_body,
+                                  DiffMatch* src_match_result,
+                                  DiffMatch* dst_match_result) {
+  LongestCommonSubsequence<std::vector<const opt::Instruction*>> lcs(src_body,
+                                                                     dst_body);
+
+  uint32_t best_match_length = lcs.Get<const opt::Instruction*>(
+      [this](const opt::Instruction* src_inst,
+             const opt::Instruction* dst_inst) {
+        return DoInstructionsMatchFuzzy(src_inst, dst_inst);
+      },
+      src_match_result, dst_match_result);
+
+  // TODO: take the gaps in between matches and match those again with a relaxed
+  // instruction-and-type-only comparison.  This can produce a better diff for
+  // example if an array index is changed, causing the OpAccessChain id to not
+  // match and subsequently every operation that's derived from that id.
+  // Usually this mismatch cascades until the next OpStore which doesn't produce
+  // an id.
+
+  return static_cast<float>(best_match_length) * 2.0f /
+         static_cast<float>(src_body.size() + dst_body.size());
+}
+
+void Differ::MatchIdsInFunctionBodies(const InstructionList& src_body,
+                                      const InstructionList& dst_body,
+                                      const DiffMatch& src_match_result,
+                                      const DiffMatch& dst_match_result,
+                                      uint32_t flexibility) {
+  size_t src_cur = 0;
+  size_t dst_cur = 0;
+
+  while (src_cur < src_body.size() && dst_cur < dst_body.size()) {
+    if (src_match_result[src_cur] && dst_match_result[dst_cur]) {
+      // Match instructions the src and dst instructions.
+      //
+      // TODO: count the matchings between variables discovered this way and
+      // choose the "best match" after all functions have been diffed and all
+      // instructions analyzed.
+      const opt::Instruction* src_inst = src_body[src_cur++];
+      const opt::Instruction* dst_inst = dst_body[dst_cur++];
+
+      // Record the matching between the instructions.  This is done only once
+      // (hence flexibility == 0).  Calls with non-zero flexibility values will
+      // only deal with matching other ids based on the operands.
+      if (flexibility == 0) {
+        id_map_.MapInsts(src_inst, dst_inst);
+      }
+
+      // Match any unmatched variables referenced by the instructions.
+      MatchVariablesUsedByMatchedInstructions(src_inst, dst_inst, flexibility);
+      continue;
+    }
+    if (!src_match_result[src_cur]) {
+      ++src_cur;
+    }
+    if (!dst_match_result[dst_cur]) {
+      ++dst_cur;
+    }
+  }
+}
+
+void Differ::MatchVariablesUsedByMatchedInstructions(
+    const opt::Instruction* src_inst, const opt::Instruction* dst_inst,
+    uint32_t flexibility) {
+  // For OpAccessChain, OpLoad and OpStore instructions that reference unmatched
+  // variables, match them as a best effort.
+  assert(src_inst->opcode() == dst_inst->opcode());
+  switch (src_inst->opcode()) {
+    default:
+      // TODO: match functions based on OpFunctionCall?
+      break;
+    case SpvOpAccessChain:
+    case SpvOpInBoundsAccessChain:
+    case SpvOpPtrAccessChain:
+    case SpvOpInBoundsPtrAccessChain:
+    case SpvOpLoad:
+    case SpvOpStore:
+      const uint32_t src_pointer_id = src_inst->GetSingleWordInOperand(0);
+      const uint32_t dst_pointer_id = dst_inst->GetSingleWordInOperand(0);
+      if (IsVariable(src_id_to_, src_pointer_id) &&
+          IsVariable(dst_id_to_, dst_pointer_id) &&
+          !id_map_.IsSrcMapped(src_pointer_id) &&
+          !id_map_.IsDstMapped(dst_pointer_id) &&
+          AreVariablesMatchable(src_pointer_id, dst_pointer_id, flexibility)) {
+        id_map_.MapIds(src_pointer_id, dst_pointer_id);
+      }
+      break;
+  }
+}
+
+const opt::Instruction* Differ::GetInst(const IdInstructions& id_to,
+                                        uint32_t id) {
+  assert(id != 0);
+  assert(id < id_to.inst_map_.size());
+
+  const opt::Instruction* inst = id_to.inst_map_[id];
+  assert(inst != nullptr);
+
+  return inst;
+}
+
+uint32_t Differ::GetConstantUint(const IdInstructions& id_to,
+                                 uint32_t constant_id) {
+  const opt::Instruction* constant_inst = GetInst(id_to, constant_id);
+  assert(constant_inst->opcode() == SpvOpConstant);
+  assert(GetInst(id_to, constant_inst->type_id())->opcode() == SpvOpTypeInt);
+
+  return constant_inst->GetSingleWordInOperand(0);
+}
+
+SpvExecutionModel Differ::GetExecutionModel(const opt::Module* module,
+                                            uint32_t entry_point_id) {
+  for (const opt::Instruction& inst : module->entry_points()) {
+    assert(inst.opcode() == SpvOpEntryPoint);
+    if (inst.GetSingleWordOperand(1) == entry_point_id) {
+      return SpvExecutionModel(inst.GetSingleWordOperand(0));
+    }
+  }
+
+  assert(false && "Unreachable");
+  return SpvExecutionModel(0xFFF);
+}
+
+bool Differ::HasName(const IdInstructions& id_to, uint32_t id) {
+  assert(id != 0);
+  assert(id < id_to.name_map_.size());
+
+  for (const opt::Instruction* inst : id_to.name_map_[id]) {
+    if (inst->opcode() == SpvOpName) {
+      return true;
+    }
+  }
+
+  return false;
+}
+
+std::string Differ::GetName(const IdInstructions& id_to, uint32_t id,
+                            bool* has_name) {
+  assert(id != 0);
+  assert(id < id_to.name_map_.size());
+
+  for (const opt::Instruction* inst : id_to.name_map_[id]) {
+    if (inst->opcode() == SpvOpName) {
+      *has_name = true;
+      return inst->GetOperand(1).AsString();
+    }
+  }
+
+  *has_name = false;
+  return "";
+}
+
+std::string Differ::GetSanitizedName(const IdInstructions& id_to, uint32_t id) {
+  bool has_name = false;
+  std::string name = GetName(id_to, id, &has_name);
+
+  if (!has_name) {
+    return "";
+  }
+
+  // Remove args from the name, in case this is a function name
+  return name.substr(0, name.find('('));
+}
+
+uint32_t Differ::GetVarTypeId(const IdInstructions& id_to, uint32_t var_id,
+                              SpvStorageClass* storage_class) {
+  const opt::Instruction* var_inst = GetInst(id_to, var_id);
+  assert(var_inst->opcode() == SpvOpVariable);
+
+  *storage_class = SpvStorageClass(var_inst->GetSingleWordInOperand(0));
+
+  // Get the type pointer from the variable.
+  const uint32_t type_pointer_id = var_inst->type_id();
+  const opt::Instruction* type_pointer_inst = GetInst(id_to, type_pointer_id);
+
+  // Get the type from the type pointer.
+  return type_pointer_inst->GetSingleWordInOperand(1);
+}
+
+bool Differ::GetDecorationValue(const IdInstructions& id_to, uint32_t id,
+                                SpvDecoration decoration,
+                                uint32_t* decoration_value) {
+  assert(id != 0);
+  assert(id < id_to.decoration_map_.size());
+
+  for (const opt::Instruction* inst : id_to.decoration_map_[id]) {
+    if (inst->opcode() == SpvOpDecorate &&
+        inst->GetSingleWordOperand(0) == id &&
+        inst->GetSingleWordOperand(1) == decoration) {
+      *decoration_value = inst->GetSingleWordOperand(2);
+      return true;
+    }
+  }
+
+  return false;
+}
+
+const opt::Instruction* Differ::GetForwardPointerInst(
+    const IdInstructions& id_to, uint32_t id) {
+  assert(id != 0);
+  assert(id < id_to.forward_pointer_map_.size());
+  return id_to.forward_pointer_map_[id];
+}
+
+bool Differ::IsIntType(const IdInstructions& id_to, uint32_t type_id) {
+  return IsOp(id_to, type_id, SpvOpTypeInt);
+}
+
+bool Differ::IsFloatType(const IdInstructions& id_to, uint32_t type_id) {
+  return IsOp(id_to, type_id, SpvOpTypeFloat);
+}
+
+bool Differ::IsConstantUint(const IdInstructions& id_to, uint32_t id) {
+  const opt::Instruction* constant_inst = GetInst(id_to, id);
+  if (constant_inst->opcode() != SpvOpConstant) {
+    return false;
+  }
+
+  const opt::Instruction* type_inst = GetInst(id_to, constant_inst->type_id());
+  return type_inst->opcode() == SpvOpTypeInt;
+}
+
+bool Differ::IsVariable(const IdInstructions& id_to, uint32_t pointer_id) {
+  return IsOp(id_to, pointer_id, SpvOpVariable);
+}
+
+bool Differ::IsOp(const IdInstructions& id_to, uint32_t id, SpvOp op) {
+  return GetInst(id_to, id)->opcode() == op;
+}
+
+bool Differ::IsPerVertexType(const IdInstructions& id_to, uint32_t type_id) {
+  assert(type_id != 0);
+  assert(type_id < id_to.decoration_map_.size());
+
+  for (const opt::Instruction* inst : id_to.decoration_map_[type_id]) {
+    if (inst->opcode() == SpvOpMemberDecorate &&
+        inst->GetSingleWordOperand(0) == type_id &&
+        inst->GetSingleWordOperand(2) == SpvDecorationBuiltIn) {
+      SpvBuiltIn built_in = SpvBuiltIn(inst->GetSingleWordOperand(3));
+
+      // Only gl_PerVertex can have, and it can only have, the following
+      // built-in decorations.
+      return built_in == SpvBuiltInPosition ||
+             built_in == SpvBuiltInPointSize ||
+             built_in == SpvBuiltInClipDistance ||
+             built_in == SpvBuiltInCullDistance;
+    }
+  }
+
+  return false;
+}
+
+bool Differ::IsPerVertexVariable(const IdInstructions& id_to, uint32_t var_id) {
+  // Get the type from the type pointer.
+  SpvStorageClass storage_class;
+  uint32_t type_id = GetVarTypeId(id_to, var_id, &storage_class);
+  const opt::Instruction* type_inst = GetInst(id_to, type_id);
+
+  // If array, get the element type.
+  if (type_inst->opcode() == SpvOpTypeArray) {
+    type_id = type_inst->GetSingleWordInOperand(0);
+  }
+
+  // Now check if the type is gl_PerVertex.
+  return IsPerVertexType(id_to, type_id);
+}
+
+SpvStorageClass Differ::GetPerVertexStorageClass(const opt::Module* module,
+                                                 uint32_t type_id) {
+  for (const opt::Instruction& inst : module->types_values()) {
+    switch (inst.opcode()) {
+      case SpvOpTypeArray:
+        // The gl_PerVertex instance could be an array, look for a variable of
+        // the array type instead.
+        if (inst.GetSingleWordInOperand(0) == type_id) {
+          type_id = inst.result_id();
+        }
+        break;
+      case SpvOpTypePointer:
+        // Find the storage class of the pointer to this type.
+        if (inst.GetSingleWordInOperand(1) == type_id) {
+          return SpvStorageClass(inst.GetSingleWordInOperand(0));
+        }
+        break;
+      default:
+        break;
+    }
+  }
+
+  // gl_PerVertex is declared, but is unused.  Return either of Input or Output
+  // classes just so it matches one in the other module.  This should be highly
+  // unlikely, perhaps except for ancient GS-used-to-emulate-CS scenarios.
+  return SpvStorageClassOutput;
+}
+
+spv_ext_inst_type_t Differ::GetExtInstType(const IdInstructions& id_to,
+                                           uint32_t set_id) {
+  const opt::Instruction* set_inst = GetInst(id_to, set_id);
+  return spvExtInstImportTypeGet(set_inst->GetInOperand(0).AsString().c_str());
+}
+
+spv_number_kind_t Differ::GetNumberKind(const IdInstructions& id_to,
+                                        const opt::Instruction& inst,
+                                        uint32_t operand_index,
+                                        uint32_t* number_bit_width) {
+  const opt::Operand& operand = inst.GetOperand(operand_index);
+  *number_bit_width = 0;
+
+  // A very limited version of Parser::parseOperand.
+  switch (operand.type) {
+    case SPV_OPERAND_TYPE_LITERAL_INTEGER:
+    case SPV_OPERAND_TYPE_OPTIONAL_LITERAL_INTEGER:
+      // Always unsigned integers.
+      *number_bit_width = 32;
+      return SPV_NUMBER_UNSIGNED_INT;
+    case SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER:
+    case SPV_OPERAND_TYPE_OPTIONAL_TYPED_LITERAL_INTEGER:
+      switch (inst.opcode()) {
+        case SpvOpSwitch:
+        case SpvOpConstant:
+        case SpvOpSpecConstant:
+          // Same kind of number as the selector (OpSwitch) or the type
+          // (Op*Constant).
+          return GetTypeNumberKind(id_to, inst.GetSingleWordOperand(0),
+                                   number_bit_width);
+        default:
+          assert(false && "Unreachable");
+          break;
+      }
+      break;
+    default:
+      break;
+  }
+
+  return SPV_NUMBER_NONE;
+}
+
+spv_number_kind_t Differ::GetTypeNumberKind(const IdInstructions& id_to,
+                                            uint32_t id,
+                                            uint32_t* number_bit_width) {
+  const opt::Instruction* type_inst = GetInst(id_to, id);
+  if (!spvOpcodeIsScalarType(type_inst->opcode())) {
+    type_inst = GetInst(id_to, type_inst->type_id());
+  }
+
+  switch (type_inst->opcode()) {
+    case SpvOpTypeInt:
+      *number_bit_width = type_inst->GetSingleWordOperand(1);
+      return type_inst->GetSingleWordOperand(2) == 0 ? SPV_NUMBER_UNSIGNED_INT
+                                                     : SPV_NUMBER_SIGNED_INT;
+      break;
+    case SpvOpTypeFloat:
+      *number_bit_width = type_inst->GetSingleWordOperand(1);
+      return SPV_NUMBER_FLOATING;
+    default:
+      assert(false && "Unreachable");
+      return SPV_NUMBER_NONE;
+  }
+}
+
+void Differ::MatchCapabilities() {
+  MatchPreambleInstructions(src_->capabilities(), dst_->capabilities());
+}
+
+void Differ::MatchExtensions() {
+  MatchPreambleInstructions(src_->extensions(), dst_->extensions());
+}
+
+void Differ::MatchExtInstImportIds() {
+  // Bunch all of this section's ids as potential matches.
+  PotentialIdMap potential_id_map;
+  auto get_result_id = [](const opt::Instruction& inst) {
+    return inst.result_id();
+  };
+  auto accept_all = [](const opt::Instruction&) { return true; };
+
+  PoolPotentialIds(src_->ext_inst_imports(), potential_id_map.src_ids, true,
+                   accept_all, get_result_id);
+  PoolPotentialIds(dst_->ext_inst_imports(), potential_id_map.dst_ids, false,
+                   accept_all, get_result_id);
+
+  // Then match the ids.
+  MatchIds(potential_id_map, [](const opt::Instruction* src_inst,
+                                const opt::Instruction* dst_inst) {
+    // Match OpExtInstImport by exact name, which is operand 1
+    const opt::Operand& src_name = src_inst->GetOperand(1);
+    const opt::Operand& dst_name = dst_inst->GetOperand(1);
+
+    return src_name.AsString() == dst_name.AsString();
+  });
+}
+void Differ::MatchMemoryModel() {
+  // Always match the memory model instructions, there is always a single one of
+  // it.
+  id_map_.MapInsts(src_->GetMemoryModel(), dst_->GetMemoryModel());
+}
+
+void Differ::MatchEntryPointIds() {
+  // Match OpEntryPoint ids (at index 1) by ExecutionModel (at index 0) and
+  // possibly name (at index 2).  OpEntryPoint doesn't produce a result id, so
+  // this function doesn't use the helpers the other functions use.
+
+  // Map from execution model to OpEntryPoint instructions of that model.
+  using ExecutionModelMap =
+      std::unordered_map<uint32_t, std::vector<const opt::Instruction*>>;
+  ExecutionModelMap src_entry_points_map;
+  ExecutionModelMap dst_entry_points_map;
+  std::set<uint32_t> all_execution_models;
+
+  for (const opt::Instruction& src_inst : src_->entry_points()) {
+    uint32_t execution_model = src_inst.GetSingleWordOperand(0);
+    src_entry_points_map[execution_model].push_back(&src_inst);
+    all_execution_models.insert(execution_model);
+  }
+  for (const opt::Instruction& dst_inst : dst_->entry_points()) {
+    uint32_t execution_model = dst_inst.GetSingleWordOperand(0);
+    dst_entry_points_map[execution_model].push_back(&dst_inst);
+    all_execution_models.insert(execution_model);
+  }
+
+  // Go through each model and match the ids.
+  for (const uint32_t execution_model : all_execution_models) {
+    auto& src_insts = src_entry_points_map[execution_model];
+    auto& dst_insts = dst_entry_points_map[execution_model];
+
+    // If there is only one entry point in src and dst with that model, match
+    // them unconditionally.
+    if (src_insts.size() == 1 && dst_insts.size() == 1) {
+      uint32_t src_id = src_insts[0]->GetSingleWordOperand(1);
+      uint32_t dst_id = dst_insts[0]->GetSingleWordOperand(1);
+      id_map_.MapIds(src_id, dst_id);
+      id_map_.MapInsts(src_insts[0], dst_insts[0]);
+      continue;
+    }
+
+    // Otherwise match them by name.
+    bool matched = false;
+    for (const opt::Instruction* src_inst : src_insts) {
+      for (const opt::Instruction* dst_inst : dst_insts) {
+        const opt::Operand& src_name = src_inst->GetOperand(2);
+        const opt::Operand& dst_name = dst_inst->GetOperand(2);
+
+        if (src_name.AsString() == dst_name.AsString()) {
+          uint32_t src_id = src_inst->GetSingleWordOperand(1);
+          uint32_t dst_id = dst_inst->GetSingleWordOperand(1);
+          id_map_.MapIds(src_id, dst_id);
+          id_map_.MapInsts(src_inst, dst_inst);
+          matched = true;
+          break;
+        }
+      }
+      if (matched) {
+        break;
+      }
+    }
+  }
+}
+
+void Differ::MatchExecutionModes() {
+  MatchPreambleInstructions(src_->execution_modes(), dst_->execution_modes());
+}
+
+void Differ::MatchTypeForwardPointers() {
+  // Bunch all of type forward pointers as potential matches.
+  PotentialIdMap potential_id_map;
+  auto get_pointer_type_id = [](const opt::Instruction& inst) {
+    return inst.GetSingleWordOperand(0);
+  };
+  auto accept_type_forward_pointer_ops = [](const opt::Instruction& inst) {
+    return inst.opcode() == SpvOpTypeForwardPointer;
+  };
+
+  PoolPotentialIds(src_->types_values(), potential_id_map.src_ids, true,
+                   accept_type_forward_pointer_ops, get_pointer_type_id);
+  PoolPotentialIds(dst_->types_values(), potential_id_map.dst_ids, false,
+                   accept_type_forward_pointer_ops, get_pointer_type_id);
+
+  // Matching types with cyclical references (i.e. in the style of linked lists)
+  // can get very complex.  Currently, the diff tool matches types bottom up, so
+  // on every instruction it expects to know if its operands are already matched
+  // or not.  With cyclical references, it cannot know that.  Type matching may
+  // need significant modifications to be able to support this use case.
+  //
+  // Currently, forwarded types are only matched by storage class and debug
+  // info, with minimal matching of the type being forwarded:
+  //
+  // - Group by class
+  //   - Group by OpType being pointed to
+  //     - Group by debug info
+  //       - If same name and unique, match
+  //     - If leftover is unique, match
+
+  // Group forwarded pointers by storage class first and loop over them.
+  GroupIdsAndMatch<SpvStorageClass>(
+      potential_id_map.src_ids, potential_id_map.dst_ids, SpvStorageClassMax,
+      &Differ::GroupIdsHelperGetTypePointerStorageClass,
+      [this](const IdGroup& src_group_by_storage_class,
+             const IdGroup& dst_group_by_storage_class) {
+
+        // Group them further by the type they are pointing to and loop over
+        // them.
+        GroupIdsAndMatch<SpvOp>(
+            src_group_by_storage_class, dst_group_by_storage_class, SpvOpMax,
+            &Differ::GroupIdsHelperGetTypePointerTypeOp,
+            [this](const IdGroup& src_group_by_type_op,
+                   const IdGroup& dst_group_by_type_op) {
+
+              // Group them even further by debug info, if possible and match by
+              // debug name.
+              MatchTypeForwardPointersByName(src_group_by_type_op,
+                                             dst_group_by_type_op);
+
+              // Match the leftovers only if they lack debug info and there is
+              // only one instance of them.
+              MatchTypeForwardPointersByTypeOp(src_group_by_type_op,
+                                               dst_group_by_type_op);
+            });
+      });
+
+  // Match the instructions that forward declare the same type themselves
+  for (uint32_t src_id : potential_id_map.src_ids) {
+    uint32_t dst_id = id_map_.MappedDstId(src_id);
+    if (dst_id == 0) continue;
+
+    const opt::Instruction* src_forward_inst =
+        GetForwardPointerInst(src_id_to_, src_id);
+    const opt::Instruction* dst_forward_inst =
+        GetForwardPointerInst(dst_id_to_, dst_id);
+
+    assert(src_forward_inst);
+    assert(dst_forward_inst);
+
+    id_map_.MapInsts(src_forward_inst, dst_forward_inst);
+  }
+}
+
+void Differ::MatchTypeIds() {
+  // Bunch all of type ids as potential matches.
+  PotentialIdMap potential_id_map;
+  auto get_result_id = [](const opt::Instruction& inst) {
+    return inst.result_id();
+  };
+  auto accept_type_ops = [](const opt::Instruction& inst) {
+    return spvOpcodeGeneratesType(inst.opcode());
+  };
+
+  PoolPotentialIds(src_->types_values(), potential_id_map.src_ids, true,
+                   accept_type_ops, get_result_id);
+  PoolPotentialIds(dst_->types_values(), potential_id_map.dst_ids, false,
+                   accept_type_ops, get_result_id);
+
+  // Then match the ids.  Start with exact matches, then match the leftover with
+  // gradually loosening degrees of strictness.  For example, in the absence of
+  // debug info, two block types will be matched if they differ only in a few of
+  // the fields.
+  for (uint32_t flexibility = 0; flexibility < 2; ++flexibility) {
+    MatchIds(potential_id_map, [this, flexibility](
+                                   const opt::Instruction* src_inst,
+                                   const opt::Instruction* dst_inst) {
+      const SpvOp src_op = src_inst->opcode();
+      const SpvOp dst_op = dst_inst->opcode();
+
+      // Don't match if the opcode is not the same.
+      if (src_op != dst_op) {
+        return false;
+      }
+
+      switch (src_op) {
+        case SpvOpTypeVoid:
+        case SpvOpTypeBool:
+        case SpvOpTypeSampler:
+          // void, bool and sampler are unique, match them.
+          return true;
+        case SpvOpTypeInt:
+        case SpvOpTypeFloat:
+        case SpvOpTypeVector:
+        case SpvOpTypeMatrix:
+        case SpvOpTypeSampledImage:
+        case SpvOpTypeRuntimeArray:
+        case SpvOpTypePointer:
+          // Match these instructions when all operands match.
+          assert(src_inst->NumInOperandWords() ==
+                 dst_inst->NumInOperandWords());
+          return DoOperandsMatch(src_inst, dst_inst, 0,
+                                 src_inst->NumInOperandWords());
+
+        case SpvOpTypeFunction:
+        case SpvOpTypeImage:
+          // Match function types only if they have the same number of operands,
+          // and they all match.
+          // Match image types similarly, expecting the optional final parameter
+          // to match (if provided in both)
+          if (src_inst->NumInOperandWords() != dst_inst->NumInOperandWords()) {
+            return false;
+          }
+          return DoOperandsMatch(src_inst, dst_inst, 0,
+                                 src_inst->NumInOperandWords());
+
+        case SpvOpTypeArray:
+          // Match arrays only if the element type and length match.  The length
+          // is an id of a constant, so the actual constant it's defining is
+          // compared instead.
+          if (!DoOperandsMatch(src_inst, dst_inst, 0, 1)) {
+            return false;
+          }
+
+          if (AreIdenticalUintConstants(src_inst->GetSingleWordInOperand(1),
+                                        dst_inst->GetSingleWordInOperand(1))) {
+            return true;
+          }
+
+          // If size is not OpConstant, expect the ids to match exactly (for
+          // example if a spec contant is used).
+          return DoOperandsMatch(src_inst, dst_inst, 1, 1);
+
+        case SpvOpTypeStruct:
+          return MatchOpTypeStruct(src_inst, dst_inst, flexibility);
+
+        default:
+          return false;
+      }
+    });
+  }
+}
+
+void Differ::MatchConstants() {
+  // Bunch all of constant ids as potential matches.
+  PotentialIdMap potential_id_map;
+  auto get_result_id = [](const opt::Instruction& inst) {
+    return inst.result_id();
+  };
+  auto accept_type_ops = [](const opt::Instruction& inst) {
+    return spvOpcodeIsConstant(inst.opcode());
+  };
+
+  PoolPotentialIds(src_->types_values(), potential_id_map.src_ids, true,
+                   accept_type_ops, get_result_id);
+  PoolPotentialIds(dst_->types_values(), potential_id_map.dst_ids, false,
+                   accept_type_ops, get_result_id);
+
+  // Then match the ids.  Constants are matched exactly, except for float types
+  // that are first matched exactly, then leftovers are matched with a small
+  // error.
+  for (uint32_t flexibility = 0; flexibility < 2; ++flexibility) {
+    MatchIds(potential_id_map, [this, flexibility](
+                                   const opt::Instruction* src_inst,
+                                   const opt::Instruction* dst_inst) {
+      const SpvOp src_op = src_inst->opcode();
+      const SpvOp dst_op = dst_inst->opcode();
+
+      // Don't match if the opcode is not the same.
+      if (src_op != dst_op) {
+        return false;
+      }
+
+      switch (src_op) {
+        case SpvOpConstantTrue:
+        case SpvOpConstantFalse:
+          // true and false are unique, match them.
+          return true;
+        case SpvOpConstant:
+          return MatchOpConstant(src_inst, dst_inst, flexibility);
+        case SpvOpConstantComposite:
+        case SpvOpSpecConstantComposite:
+          // Composite constants must match in type and value.
+          //
+          // TODO: match OpConstantNull with OpConstantComposite with all zeros
+          // at flexibility == 1
+          // TODO: match constants from structs that have been flexibly-matched.
+          if (src_inst->NumInOperandWords() != dst_inst->NumInOperandWords()) {
+            return false;
+          }
+          return DoesOperandMatch(src_inst->GetOperand(0),
+                                  dst_inst->GetOperand(0)) &&
+                 DoOperandsMatch(src_inst, dst_inst, 0,
+                                 src_inst->NumInOperandWords());
+        case SpvOpConstantSampler:
+          // Match sampler constants exactly.
+          // TODO: Allow flexibility in parameters to better diff shaders where
+          // the sampler param has changed.
+          assert(src_inst->NumInOperandWords() ==
+                 dst_inst->NumInOperandWords());
+          return DoOperandsMatch(src_inst, dst_inst, 0,
+                                 src_inst->NumInOperandWords());
+        case SpvOpConstantNull:
+          // Match null constants as long as the type matches.
+          return DoesOperandMatch(src_inst->GetOperand(0),
+                                  dst_inst->GetOperand(0));
+
+        case SpvOpSpecConstantTrue:
+        case SpvOpSpecConstantFalse:
+        case SpvOpSpecConstant:
+        case SpvOpSpecConstantOp:
+          // Match spec constants by name if available, then by the SpecId
+          // decoration.
+          return MatchOpSpecConstant(src_inst, dst_inst);
+
+        default:
+          return false;
+      }
+    });
+  }
+}
+
+void Differ::MatchVariableIds() {
+  // Bunch all of variable ids as potential matches.
+  PotentialIdMap potential_id_map;
+  auto get_result_id = [](const opt::Instruction& inst) {
+    return inst.result_id();
+  };
+  auto accept_type_ops = [](const opt::Instruction& inst) {
+    return inst.opcode() == SpvOpVariable;
+  };
+
+  PoolPotentialIds(src_->types_values(), potential_id_map.src_ids, true,
+                   accept_type_ops, get_result_id);
+  PoolPotentialIds(dst_->types_values(), potential_id_map.dst_ids, false,
+                   accept_type_ops, get_result_id);
+
+  // Then match the ids.  Start with exact matches, then match the leftover with
+  // gradually loosening degrees of strictness.  For example, in the absence of
+  // debug info, two otherwise identical variables will be matched if one of
+  // them has a Private storage class and the other doesn't.
+  for (uint32_t flexibility = 0; flexibility < 2; ++flexibility) {
+    MatchIds(potential_id_map,
+             [this, flexibility](const opt::Instruction* src_inst,
+                                 const opt::Instruction* dst_inst) {
+               assert(src_inst->opcode() == SpvOpVariable);
+               assert(dst_inst->opcode() == SpvOpVariable);
+
+               return MatchOpVariable(src_inst, dst_inst, flexibility);
+             });
+  }
+}
+
+void Differ::MatchFunctions() {
+  IdGroup src_func_ids;
+  IdGroup dst_func_ids;
+
+  for (const auto& func : src_funcs_) {
+    src_func_ids.push_back(func.first);
+  }
+  for (const auto& func : dst_funcs_) {
+    dst_func_ids.push_back(func.first);
+  }
+
+  // Base the matching of functions on debug info when available.
+  GroupIdsAndMatch<std::string>(
+      src_func_ids, dst_func_ids, "", &Differ::GetSanitizedName,
+      [this](const IdGroup& src_group, const IdGroup& dst_group) {
+
+        // If there is a single function with this name in src and dst, it's a
+        // definite match.
+        if (src_group.size() == 1 && dst_group.size() == 1) {
+          id_map_.MapIds(src_group[0], dst_group[0]);
+          return;
+        }
+
+        // If there are multiple functions with the same name, group them by
+        // type, and match only if the types match (and are unique).
+        GroupIdsAndMatch<uint32_t>(src_group, dst_group, 0,
+                                   &Differ::GroupIdsHelperGetTypeId,
+                                   [this](const IdGroup& src_group_by_type_id,
+                                          const IdGroup& dst_group_by_type_id) {
+
+                                     if (src_group_by_type_id.size() == 1 &&
+                                         dst_group_by_type_id.size() == 1) {
+                                       id_map_.MapIds(src_group_by_type_id[0],
+                                                      dst_group_by_type_id[0]);
+                                     }
+                                   });
+      });
+
+  // Any functions that are left are pooled together and matched as if unnamed,
+  // with the only exception that two functions with mismatching names are not
+  // matched.
+  //
+  // Before that however, the diff of the functions that are matched are taken
+  // and processed, so that more of the global variables can be matched before
+  // attempting to match the rest of the functions.  They can contribute to the
+  // precision of the diff of those functions.
+  for (const uint32_t src_func_id : src_func_ids) {
+    const uint32_t dst_func_id = id_map_.MappedDstId(src_func_id);
+    if (dst_func_id == 0) {
+      continue;
+    }
+
+    // Since these functions are definite matches, match their parameters for a
+    // better diff.
+    MatchFunctionParamIds(src_funcs_[src_func_id], dst_funcs_[dst_func_id]);
+
+    // Take the diff of the two functions.
+    DiffMatch src_match_result, dst_match_result;
+    MatchFunctionBodies(src_func_insts_[src_func_id],
+                        dst_func_insts_[dst_func_id], &src_match_result,
+                        &dst_match_result);
+
+    // Match ids between the two function bodies; which can also result in
+    // global variables getting matched.
+    MatchIdsInFunctionBodies(src_func_insts_[src_func_id],
+                             dst_func_insts_[dst_func_id], src_match_result,
+                             dst_match_result, 0);
+  }
+
+  // Best effort match functions with matching type.
+  GroupIdsAndMatch<uint32_t>(
+      src_func_ids, dst_func_ids, 0, &Differ::GroupIdsHelperGetTypeId,
+      [this](const IdGroup& src_group_by_type_id,
+             const IdGroup& dst_group_by_type_id) {
+
+        BestEffortMatchFunctions(src_group_by_type_id, dst_group_by_type_id,
+                                 src_func_insts_, dst_func_insts_);
+      });
+
+  // Any function that's left, best effort match them.
+  BestEffortMatchFunctions(src_func_ids, dst_func_ids, src_func_insts_,
+                           dst_func_insts_);
+}
+
+void Differ::MatchDebugs1() {
+  // This section in cludes: OpString, OpSourceExtension, OpSource,
+  // OpSourceContinued
+  MatchDebugAndAnnotationInstructions(src_->debugs1(), dst_->debugs1());
+}
+
+void Differ::MatchDebugs2() {
+  // This section includes: OpName, OpMemberName
+  MatchDebugAndAnnotationInstructions(src_->debugs2(), dst_->debugs2());
+}
+
+void Differ::MatchDebugs3() {
+  // This section includes: OpModuleProcessed
+  MatchDebugAndAnnotationInstructions(src_->debugs3(), dst_->debugs3());
+}
+
+void Differ::MatchExtInstDebugInfo() {
+  // This section includes OpExtInst for DebugInfo extension
+  MatchDebugAndAnnotationInstructions(src_->ext_inst_debuginfo(),
+                                      dst_->ext_inst_debuginfo());
+}
+
+void Differ::MatchAnnotations() {
+  // This section includes OpDecorate and family.
+  MatchDebugAndAnnotationInstructions(src_->annotations(), dst_->annotations());
+}
+
+const opt::Instruction* Differ::MappedDstInst(
+    const opt::Instruction* src_inst) {
+  return MappedInstImpl(src_inst, id_map_.SrcToDstMap(), dst_id_to_);
+}
+
+const opt::Instruction* Differ::MappedSrcInst(
+    const opt::Instruction* dst_inst) {
+  return MappedInstImpl(dst_inst, id_map_.DstToSrcMap(), src_id_to_);
+}
+
+const opt::Instruction* Differ::MappedInstImpl(
+    const opt::Instruction* inst, const IdMap& to_other,
+    const IdInstructions& other_id_to) {
+  if (inst->HasResultId()) {
+    if (to_other.IsMapped(inst->result_id())) {
+      const uint32_t other_result_id = to_other.MappedId(inst->result_id());
+
+      assert(other_result_id < other_id_to.inst_map_.size());
+      return other_id_to.inst_map_[other_result_id];
+    }
+
+    return nullptr;
+  }
+
+  return to_other.MappedInst(inst);
+}
+
+void Differ::OutputLine(std::function<bool()> are_lines_identical,
+                        std::function<void()> output_src_line,
+                        std::function<void()> output_dst_line) {
+  if (are_lines_identical()) {
+    out_ << " ";
+    output_src_line();
+  } else {
+    OutputRed();
+    out_ << "-";
+    output_src_line();
+
+    OutputGreen();
+    out_ << "+";
+    output_dst_line();
+
+    OutputResetColor();
+  }
+}
+
+const opt::Instruction* IterInst(opt::Module::const_inst_iterator& iter) {
+  return &*iter;
+}
+
+const opt::Instruction* IterInst(InstructionList::const_iterator& iter) {
+  return *iter;
+}
+
+template <typename InstList>
+void Differ::OutputSection(
+    const InstList& src_insts, const InstList& dst_insts,
+    std::function<void(const opt::Instruction&, const IdInstructions&,
+                       const opt::Instruction&)>
+        write_inst) {
+  auto src_iter = src_insts.begin();
+  auto dst_iter = dst_insts.begin();
+
+  // - While src_inst doesn't have a match, output it with -
+  // - While dst_inst doesn't have a match, output it with +
+  // - Now src_inst and dst_inst both have matches; might not match each other!
+  //   * If section is unordered, just process src_inst and its match (dst_inst
+  //   or not),
+  //     dst_inst will eventually be processed when its match is seen.
+  //   * If section is ordered, also just process src_inst and its match.  Its
+  //   match must
+  //     necessarily be dst_inst.
+  while (src_iter != src_insts.end() || dst_iter != dst_insts.end()) {
+    OutputRed();
+    while (src_iter != src_insts.end() &&
+           MappedDstInst(IterInst(src_iter)) == nullptr) {
+      out_ << "-";
+      write_inst(*IterInst(src_iter), src_id_to_, *IterInst(src_iter));
+      ++src_iter;
+    }
+    OutputGreen();
+    while (dst_iter != dst_insts.end() &&
+           MappedSrcInst(IterInst(dst_iter)) == nullptr) {
+      out_ << "+";
+      write_inst(ToMappedSrcIds(*IterInst(dst_iter)), dst_id_to_,
+                 *IterInst(dst_iter));
+      ++dst_iter;
+    }
+    OutputResetColor();
+
+    if (src_iter != src_insts.end() && dst_iter != dst_insts.end()) {
+      const opt::Instruction* src_inst = IterInst(src_iter);
+      const opt::Instruction* matched_dst_inst = MappedDstInst(src_inst);
+
+      assert(matched_dst_inst != nullptr);
+      assert(MappedSrcInst(IterInst(dst_iter)) != nullptr);
+
+      OutputLine(
+          [this, src_inst, matched_dst_inst]() {
+            return DoInstructionsMatch(src_inst, matched_dst_inst);
+          },
+          [this, src_inst, &write_inst]() {
+            write_inst(*src_inst, src_id_to_, *src_inst);
+          },
+          [this, matched_dst_inst, &write_inst]() {
+            write_inst(ToMappedSrcIds(*matched_dst_inst), dst_id_to_,
+                       *matched_dst_inst);
+          });
+
+      ++src_iter;
+      ++dst_iter;
+    }
+  }
+}
+
+void Differ::ToParsedInstruction(
+    const opt::Instruction& inst, const IdInstructions& id_to,
+    const opt::Instruction& original_inst,
+    spv_parsed_instruction_t* parsed_inst,
+    std::vector<spv_parsed_operand_t>& parsed_operands,
+    std::vector<uint32_t>& inst_binary) {
+  inst.ToBinaryWithoutAttachedDebugInsts(&inst_binary);
+  parsed_operands.resize(inst.NumOperands());
+
+  parsed_inst->words = inst_binary.data();
+  parsed_inst->num_words = static_cast<uint16_t>(inst_binary.size());
+  parsed_inst->opcode = static_cast<uint16_t>(inst.opcode());
+  parsed_inst->ext_inst_type =
+      inst.opcode() == SpvOpExtInst
+          ? GetExtInstType(id_to, original_inst.GetSingleWordInOperand(0))
+          : SPV_EXT_INST_TYPE_NONE;
+  parsed_inst->type_id =
+      inst.HasResultType() ? inst.GetSingleWordOperand(0) : 0;
+  parsed_inst->result_id = inst.HasResultId() ? inst.result_id() : 0;
+  parsed_inst->operands = parsed_operands.data();
+  parsed_inst->num_operands = static_cast<uint16_t>(parsed_operands.size());
+
+  // Word 0 is always op and num_words, so operands start at offset 1.
+  uint32_t offset = 1;
+  for (uint16_t operand_index = 0; operand_index < parsed_inst->num_operands;
+       ++operand_index) {
+    const opt::Operand& operand = inst.GetOperand(operand_index);
+    spv_parsed_operand_t& parsed_operand = parsed_operands[operand_index];
+
+    parsed_operand.offset = static_cast<uint16_t>(offset);
+    parsed_operand.num_words = static_cast<uint16_t>(operand.words.size());
+    parsed_operand.type = operand.type;
+    parsed_operand.number_kind = GetNumberKind(
+        id_to, original_inst, operand_index, &parsed_operand.number_bit_width);
+
+    offset += parsed_operand.num_words;
+  }
+}
+
+opt::Instruction Differ::ToMappedSrcIds(const opt::Instruction& dst_inst) {
+  // Create an identical instruction to dst_inst, except ids are changed to the
+  // mapped one.
+  opt::Instruction mapped_inst = dst_inst;
+
+  for (uint32_t operand_index = 0; operand_index < mapped_inst.NumOperands();
+       ++operand_index) {
+    opt::Operand& operand = mapped_inst.GetOperand(operand_index);
+
+    if (spvIsIdType(operand.type)) {
+      assert(id_map_.IsDstMapped(operand.AsId()));
+      operand.words[0] = id_map_.MappedSrcId(operand.AsId());
+    }
+  }
+
+  return mapped_inst;
+}
+
+spv_result_t Differ::Output() {
+  id_map_.MapUnmatchedIds();
+  src_id_to_.inst_map_.resize(id_map_.SrcToDstMap().IdBound(), nullptr);
+  dst_id_to_.inst_map_.resize(id_map_.DstToSrcMap().IdBound(), nullptr);
+
+  const spv_target_env target_env = SPV_ENV_UNIVERSAL_1_6;
+  spv_opcode_table opcode_table;
+  spv_operand_table operand_table;
+  spv_ext_inst_table ext_inst_table;
+  spv_result_t result;
+
+  result = spvOpcodeTableGet(&opcode_table, target_env);
+  if (result != SPV_SUCCESS) return result;
+
+  result = spvOperandTableGet(&operand_table, target_env);
+  if (result != SPV_SUCCESS) return result;
+
+  result = spvExtInstTableGet(&ext_inst_table, target_env);
+  if (result != SPV_SUCCESS) return result;
+
+  spv_context_t context{
+      target_env,
+      opcode_table,
+      operand_table,
+      ext_inst_table,
+  };
+
+  const AssemblyGrammar grammar(&context);
+  if (!grammar.isValid()) return SPV_ERROR_INVALID_TABLE;
+
+  uint32_t disassembly_options = SPV_BINARY_TO_TEXT_OPTION_PRINT;
+  if (options_.indent) {
+    disassembly_options |= SPV_BINARY_TO_TEXT_OPTION_INDENT;
+  }
+
+  NameMapper name_mapper = GetTrivialNameMapper();
+  disassemble::InstructionDisassembler dis(grammar, out_, disassembly_options,
+                                           name_mapper);
+
+  if (!options_.no_header) {
+    // Output the header
+    // TODO: when using diff with text, the assembler overrides the version and
+    // generator, so these aren't reflected correctly in the output.  Could
+    // potentially extract this info from the header comment.
+    OutputLine([]() { return true; }, [&dis]() { dis.EmitHeaderSpirv(); },
+               []() { assert(false && "Unreachable"); });
+    OutputLine([this]() { return src_->version() == dst_->version(); },
+               [this, &dis]() { dis.EmitHeaderVersion(src_->version()); },
+               [this, &dis]() { dis.EmitHeaderVersion(dst_->version()); });
+    OutputLine([this]() { return src_->generator() == dst_->generator(); },
+               [this, &dis]() { dis.EmitHeaderGenerator(src_->generator()); },
+               [this, &dis]() { dis.EmitHeaderGenerator(dst_->generator()); });
+    OutputLine(
+        [this]() { return src_->IdBound() == id_map_.SrcToDstMap().IdBound(); },
+        [this, &dis]() { dis.EmitHeaderIdBound(src_->IdBound()); },
+        [this, &dis]() {
+          dis.EmitHeaderIdBound(id_map_.SrcToDstMap().IdBound());
+        });
+    OutputLine([this]() { return src_->schema() == dst_->schema(); },
+               [this, &dis]() { dis.EmitHeaderSchema(src_->schema()); },
+               [this, &dis]() { dis.EmitHeaderSchema(dst_->schema()); });
+  }
+
+  // For each section, iterate both modules and output the disassembly.
+  auto write_inst = [this, &dis](const opt::Instruction& inst,
+                                 const IdInstructions& id_to,
+                                 const opt::Instruction& original_inst) {
+    spv_parsed_instruction_t parsed_inst;
+    std::vector<spv_parsed_operand_t> parsed_operands;
+    std::vector<uint32_t> inst_binary;
+
+    ToParsedInstruction(inst, id_to, original_inst, &parsed_inst,
+                        parsed_operands, inst_binary);
+
+    dis.EmitInstruction(parsed_inst, 0);
+  };
+
+  OutputSection(src_->capabilities(), dst_->capabilities(), write_inst);
+  OutputSection(src_->extensions(), dst_->extensions(), write_inst);
+  OutputSection(src_->ext_inst_imports(), dst_->ext_inst_imports(), write_inst);
+
+  // There is only one memory model.
+  OutputLine(
+      [this]() {
+        return DoInstructionsMatch(src_->GetMemoryModel(),
+                                   dst_->GetMemoryModel());
+      },
+      [this, &write_inst]() {
+        write_inst(*src_->GetMemoryModel(), src_id_to_,
+                   *src_->GetMemoryModel());
+      },
+      [this, &write_inst]() {
+        write_inst(*dst_->GetMemoryModel(), dst_id_to_,
+                   *dst_->GetMemoryModel());
+      });
+
+  OutputSection(src_->entry_points(), dst_->entry_points(), write_inst);
+  OutputSection(src_->execution_modes(), dst_->execution_modes(), write_inst);
+  OutputSection(src_->debugs1(), dst_->debugs1(), write_inst);
+  OutputSection(src_->debugs2(), dst_->debugs2(), write_inst);
+  OutputSection(src_->debugs3(), dst_->debugs3(), write_inst);
+  OutputSection(src_->ext_inst_debuginfo(), dst_->ext_inst_debuginfo(),
+                write_inst);
+  OutputSection(src_->annotations(), dst_->annotations(), write_inst);
+  OutputSection(src_->types_values(), dst_->types_values(), write_inst);
+
+  // Get the body of all the functions.
+  FunctionInstMap src_func_header_insts;
+  FunctionInstMap dst_func_header_insts;
+
+  GetFunctionHeaderInstructions(src_, &src_func_header_insts);
+  GetFunctionHeaderInstructions(dst_, &dst_func_header_insts);
+
+  for (const auto& src_func : src_func_insts_) {
+    const uint32_t src_func_id = src_func.first;
+    const InstructionList& src_insts = src_func.second;
+    const InstructionList& src_header_insts =
+        src_func_header_insts[src_func_id];
+
+    const uint32_t dst_func_id = id_map_.MappedDstId(src_func_id);
+    if (dst_func_insts_.find(dst_func_id) == dst_func_insts_.end()) {
+      OutputSection(src_header_insts, InstructionList(), write_inst);
+      OutputSection(src_insts, InstructionList(), write_inst);
+      continue;
+    }
+
+    const InstructionList& dst_insts = dst_func_insts_[dst_func_id];
+    const InstructionList& dst_header_insts =
+        dst_func_header_insts[dst_func_id];
+    OutputSection(src_header_insts, dst_header_insts, write_inst);
+    OutputSection(src_insts, dst_insts, write_inst);
+  }
+
+  for (const auto& dst_func : dst_func_insts_) {
+    const uint32_t dst_func_id = dst_func.first;
+    const InstructionList& dst_insts = dst_func.second;
+    const InstructionList& dst_header_insts =
+        dst_func_header_insts[dst_func_id];
+
+    const uint32_t src_func_id = id_map_.MappedSrcId(dst_func_id);
+    if (src_func_insts_.find(src_func_id) == src_func_insts_.end()) {
+      OutputSection(InstructionList(), dst_header_insts, write_inst);
+      OutputSection(InstructionList(), dst_insts, write_inst);
+    }
+  }
+
+  out_ << std::flush;
+
+  return SPV_SUCCESS;
+}
+
+}  // anonymous namespace
+
+spv_result_t Diff(opt::IRContext* src, opt::IRContext* dst, std::ostream& out,
+                  Options options) {
+  // High level algorithm:
+  //
+  // - Some sections of SPIR-V don't deal with ids; instructions in those
+  //   sections are matched identically.  For example OpCapability instructions.
+  // - Some sections produce ids, and they can be trivially matched by their
+  //   parameters.  For example OpExtInstImport instructions.
+  // - Some sections annotate ids.  These are matched at the end, after the ids
+  //   themselves are matched.  For example OpName or OpDecorate instructions.
+  // - Some sections produce ids that depend on other ids and they can be
+  //   recursively matched.  For example OpType* instructions.
+  // - Some sections produce ids that are not trivially matched.  For these ids,
+  //   the debug info is used when possible, or a best guess (such as through
+  //   decorations) is used.  For example OpVariable instructions.
+  // - Matching functions is done with multiple attempts:
+  //   * Functions with identical debug names are matched if there are no
+  //     overloads.
+  //   * Otherwise, functions with identical debug names and types are matched.
+  //   * The rest of the functions are best-effort matched, first in groups of
+  //     identical type, then any with any.
+  //     * The best-effort matching takes the diff of every pair of functions in
+  //       a group and selects the top matches that also meet a similarity
+  //       index.
+  //   * Once a pair of functions are matched, the fuzzy diff of the
+  //     instructions is used to match the instructions in the function body.
+  //     The fuzzy diff makes sure that sufficiently similar instructions are
+  //     matched and that yet-to-be-matched result ids don't result in a larger
+  //     diff.
+  //
+  // Once the instructions are matched between the src and dst SPIR-V, the src
+  // is traversed and its disassembly is output.  In the process, any unmatched
+  // instruction is prefixed with -, and any unmatched instruction in dst in the
+  // same section is output prefixed with +.  To avoid confusion, the
+  // instructions in dst are output with matching ids in src so the output
+  // assembly is consistent.
+
+  Differ differ(src, dst, out, options);
+
+  // First, match instructions between the different non-annotation sections of
+  // the SPIR-V.
+  differ.MatchCapabilities();
+  differ.MatchExtensions();
+  differ.MatchExtInstImportIds();
+  differ.MatchMemoryModel();
+  differ.MatchEntryPointIds();
+  differ.MatchExecutionModes();
+  differ.MatchTypeForwardPointers();
+  differ.MatchTypeIds();
+  differ.MatchConstants();
+  differ.MatchVariableIds();
+  differ.MatchFunctions();
+
+  // Match instructions that annotate previously-matched ids.
+  differ.MatchDebugs1();
+  differ.MatchDebugs2();
+  differ.MatchDebugs3();
+  differ.MatchExtInstDebugInfo();
+  differ.MatchAnnotations();
+
+  // Show the disassembly with the diff.
+  //
+  // TODO: Based on an option, output either based on src or dst, i.e. the diff
+  // can show the ids and instruction/function order either from src or dst.
+  spv_result_t result = differ.Output();
+
+  differ.DumpIdMap();
+
+  return result;
+}
+
+}  // namespace diff
+}  // namespace spvtools

+ 48 - 0
ThirdParty/Glslang/External/spirv-tools/source/diff/diff.h

@@ -0,0 +1,48 @@
+// 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_DIFF_DIFF_H_
+#define SOURCE_DIFF_DIFF_H_
+
+#include "source/opt/ir_context.h"
+
+namespace spvtools {
+namespace diff {
+
+struct Options {
+  bool ignore_set_binding = false;
+  bool ignore_location = false;
+  bool indent = false;
+  bool no_header = false;
+  bool color_output = false;
+  bool dump_id_map = false;
+};
+
+// Given two SPIR-V modules, this function outputs the textual diff of their
+// assembly in `out`.  The diff is *semantic*, so that the ordering of certain
+// instructions wouldn't matter.
+//
+// The output is a disassembly of src, with diff(1)-style + and - lines that
+// show how the src is changed into dst.  To make this disassembly
+// self-consistent, the ids that are output are all in the space of the src
+// module; e.g. any + lines (showing instructions from the dst module) have
+// their ids mapped to the matched instruction in the src module (or a new id
+// allocated in the src module if unmatched).
+spv_result_t Diff(opt::IRContext* src, opt::IRContext* dst, std::ostream& out,
+                  Options options);
+
+}  // namespace diff
+}  // namespace spvtools
+
+#endif  // SOURCE_DIFF_DIFF_H_

+ 224 - 0
ThirdParty/Glslang/External/spirv-tools/source/diff/lcs.h

@@ -0,0 +1,224 @@
+// 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_DIFF_LCS_H_
+#define SOURCE_DIFF_LCS_H_
+
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <functional>
+#include <stack>
+#include <vector>
+
+namespace spvtools {
+namespace diff {
+
+// The result of a diff.
+using DiffMatch = std::vector<bool>;
+
+// Helper class to find the longest common subsequence between two function
+// bodies.
+template <typename Sequence>
+class LongestCommonSubsequence {
+ public:
+  LongestCommonSubsequence(const Sequence& src, const Sequence& dst)
+      : src_(src),
+        dst_(dst),
+        table_(src.size(), std::vector<DiffMatchEntry>(dst.size())) {}
+
+  // Given two sequences, it creates a matching between them.  The elements are
+  // simply marked as matched in src and dst, with any unmatched element in src
+  // implying a removal and any unmatched element in dst implying an addition.
+  //
+  // Returns the length of the longest common subsequence.
+  template <typename T>
+  uint32_t Get(std::function<bool(T src_elem, T dst_elem)> match,
+               DiffMatch* src_match_result, DiffMatch* dst_match_result);
+
+ private:
+  struct DiffMatchIndex {
+    uint32_t src_offset;
+    uint32_t dst_offset;
+  };
+
+  template <typename T>
+  void CalculateLCS(std::function<bool(T src_elem, T dst_elem)> match);
+  void RetrieveMatch(DiffMatch* src_match_result, DiffMatch* dst_match_result);
+  bool IsInBound(DiffMatchIndex index) {
+    return index.src_offset < src_.size() && index.dst_offset < dst_.size();
+  }
+  bool IsCalculated(DiffMatchIndex index) {
+    assert(IsInBound(index));
+    return table_[index.src_offset][index.dst_offset].valid;
+  }
+  bool IsCalculatedOrOutOfBound(DiffMatchIndex index) {
+    return !IsInBound(index) || IsCalculated(index);
+  }
+  uint32_t GetMemoizedLength(DiffMatchIndex index) {
+    if (!IsInBound(index)) {
+      return 0;
+    }
+    assert(IsCalculated(index));
+    return table_[index.src_offset][index.dst_offset].best_match_length;
+  }
+  bool IsMatched(DiffMatchIndex index) {
+    assert(IsCalculated(index));
+    return table_[index.src_offset][index.dst_offset].matched;
+  }
+  void MarkMatched(DiffMatchIndex index, uint32_t best_match_length,
+                   bool matched) {
+    assert(IsInBound(index));
+    DiffMatchEntry& entry = table_[index.src_offset][index.dst_offset];
+    assert(!entry.valid);
+
+    entry.best_match_length = best_match_length & 0x3FFFFFFF;
+    assert(entry.best_match_length == best_match_length);
+    entry.matched = matched;
+    entry.valid = true;
+  }
+
+  const Sequence& src_;
+  const Sequence& dst_;
+
+  struct DiffMatchEntry {
+    DiffMatchEntry() : best_match_length(0), matched(false), valid(false) {}
+
+    uint32_t best_match_length : 30;
+    // Whether src[i] and dst[j] matched.  This is an optimization to avoid
+    // calling the `match` function again when walking the LCS table.
+    uint32_t matched : 1;
+    // Use for the recursive algorithm to know if the contents of this entry are
+    // valid.
+    uint32_t valid : 1;
+  };
+
+  std::vector<std::vector<DiffMatchEntry>> table_;
+};
+
+template <typename Sequence>
+template <typename T>
+uint32_t LongestCommonSubsequence<Sequence>::Get(
+    std::function<bool(T src_elem, T dst_elem)> match,
+    DiffMatch* src_match_result, DiffMatch* dst_match_result) {
+  CalculateLCS(match);
+  RetrieveMatch(src_match_result, dst_match_result);
+  return GetMemoizedLength({0, 0});
+}
+
+template <typename Sequence>
+template <typename T>
+void LongestCommonSubsequence<Sequence>::CalculateLCS(
+    std::function<bool(T src_elem, T dst_elem)> match) {
+  // The LCS algorithm is simple.  Given sequences s and d, with a:b depicting a
+  // range in python syntax:
+  //
+  //     lcs(s[i:], d[j:]) =
+  //         lcs(s[i+1:], d[j+1:]) + 1                        if s[i] == d[j]
+  //         max(lcs(s[i+1:], d[j:]), lcs(s[i:], d[j+1:]))               o.w.
+  //
+  // Once the LCS table is filled according to the above, it can be walked and
+  // the best match retrieved.
+  //
+  // This is a recursive function with memoization, which avoids filling table
+  // entries where unnecessary.  This makes the best case O(N) instead of
+  // O(N^2).  The implemention uses a std::stack to avoid stack overflow on long
+  // sequences.
+
+  if (src_.empty() || dst_.empty()) {
+    return;
+  }
+
+  std::stack<DiffMatchIndex> to_calculate;
+  to_calculate.push({0, 0});
+
+  while (!to_calculate.empty()) {
+    DiffMatchIndex current = to_calculate.top();
+    to_calculate.pop();
+    assert(IsInBound(current));
+
+    // If already calculated through another path, ignore it.
+    if (IsCalculated(current)) {
+      continue;
+    }
+
+    if (match(src_[current.src_offset], dst_[current.dst_offset])) {
+      // If the current elements match, advance both indices and calculate the
+      // LCS if not already.  Visit `current` again afterwards, so its
+      // corresponding entry will be updated.
+      DiffMatchIndex next = {current.src_offset + 1, current.dst_offset + 1};
+      if (IsCalculatedOrOutOfBound(next)) {
+        MarkMatched(current, GetMemoizedLength(next) + 1, true);
+      } else {
+        to_calculate.push(current);
+        to_calculate.push(next);
+      }
+      continue;
+    }
+
+    // We've reached a pair of elements that don't match.  Calculate the LCS for
+    // both cases of either being left unmatched and take the max.  Visit
+    // `current` again afterwards, so its corresponding entry will be updated.
+    DiffMatchIndex next_src = {current.src_offset + 1, current.dst_offset};
+    DiffMatchIndex next_dst = {current.src_offset, current.dst_offset + 1};
+
+    if (IsCalculatedOrOutOfBound(next_src) &&
+        IsCalculatedOrOutOfBound(next_dst)) {
+      uint32_t best_match_length =
+          std::max(GetMemoizedLength(next_src), GetMemoizedLength(next_dst));
+      MarkMatched(current, best_match_length, false);
+      continue;
+    }
+
+    to_calculate.push(current);
+    if (!IsCalculatedOrOutOfBound(next_src)) {
+      to_calculate.push(next_src);
+    }
+    if (!IsCalculatedOrOutOfBound(next_dst)) {
+      to_calculate.push(next_dst);
+    }
+  }
+}
+
+template <typename Sequence>
+void LongestCommonSubsequence<Sequence>::RetrieveMatch(
+    DiffMatch* src_match_result, DiffMatch* dst_match_result) {
+  src_match_result->clear();
+  dst_match_result->clear();
+
+  src_match_result->resize(src_.size(), false);
+  dst_match_result->resize(dst_.size(), false);
+
+  DiffMatchIndex current = {0, 0};
+  while (IsInBound(current)) {
+    if (IsMatched(current)) {
+      (*src_match_result)[current.src_offset++] = true;
+      (*dst_match_result)[current.dst_offset++] = true;
+      continue;
+    }
+
+    if (GetMemoizedLength({current.src_offset + 1, current.dst_offset}) >=
+        GetMemoizedLength({current.src_offset, current.dst_offset + 1})) {
+      ++current.src_offset;
+    } else {
+      ++current.dst_offset;
+    }
+  }
+}
+
+}  // namespace diff
+}  // namespace spvtools
+
+#endif  // SOURCE_DIFF_LCS_H_

+ 26 - 0
ThirdParty/Glslang/External/spirv-tools/test/diff/CMakeLists.txt

@@ -0,0 +1,26 @@
+# 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(diff_files/diff_test_files_autogen.cmake)
+
+add_spvtools_unittest(TARGET lcs
+  SRCS lcs_test.cpp
+  LIBS SPIRV-Tools-diff
+)
+
+add_spvtools_unittest(TARGET diff
+  SRCS diff_test.cpp diff_test_utils.h diff_test_utils.cpp
+       ${DIFF_TEST_FILES} ${spirv-tools_SOURCE_DIR}/tools/util/cli_consumer.cpp
+  LIBS SPIRV-Tools-diff
+)

+ 242 - 0
ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/OpExtInst_in_dst_only_autogen.cpp

@@ -0,0 +1,242 @@
+// GENERATED FILE - DO NOT EDIT.
+// Generated by generate_tests.py
+//
+// 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 "../diff_test_utils.h"
+
+#include "gtest/gtest.h"
+
+namespace spvtools {
+namespace diff {
+namespace {
+
+// Tests a diff where the src shader doesn't have OpExtImport while the
+// dst shader does (and uses OpExtInst).  This test ensures that when matching,
+// the OpExtImport instruction from the correct module is referenced.
+constexpr char kSrc[] = R"(               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %4 "main" %9 %11
+               OpExecutionMode %4 OriginUpperLeft
+               OpSource ESSL 310
+               OpName %4 "main"
+               OpName %9 "color"
+               OpName %11 "v"
+               OpDecorate %9 RelaxedPrecision
+               OpDecorate %9 Location 0
+               OpDecorate %11 RelaxedPrecision
+               OpDecorate %11 Location 0
+               OpDecorate %12 RelaxedPrecision
+               OpDecorate %13 RelaxedPrecision
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeFloat 32
+          %7 = OpTypeVector %6 4
+          %8 = OpTypePointer Output %7
+          %9 = OpVariable %8 Output
+         %10 = OpTypePointer Input %6
+         %11 = OpVariable %10 Input
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+         %12 = OpLoad %6 %11
+         %13 = OpCompositeConstruct %7 %12 %12 %12 %12
+               OpStore %9 %13
+               OpReturn
+               OpFunctionEnd
+)";
+constexpr char kDst[] = R"(               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %4 "main" %9 %11
+               OpExecutionMode %4 OriginUpperLeft
+               OpSource ESSL 310
+               OpName %4 "main"
+               OpName %9 "color"
+               OpName %11 "v"
+               OpDecorate %9 RelaxedPrecision
+               OpDecorate %9 Location 0
+               OpDecorate %11 RelaxedPrecision
+               OpDecorate %11 Location 0
+               OpDecorate %12 RelaxedPrecision
+               OpDecorate %13 RelaxedPrecision
+               OpDecorate %14 RelaxedPrecision
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeFloat 32
+          %7 = OpTypeVector %6 4
+          %8 = OpTypePointer Output %7
+          %9 = OpVariable %8 Output
+         %10 = OpTypePointer Input %6
+         %11 = OpVariable %10 Input
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+         %12 = OpLoad %6 %11
+         %13 = OpExtInst %6 %1 Log2 %12
+         %14 = OpCompositeConstruct %7 %13 %13 %13 %13
+               OpStore %9 %14
+               OpReturn
+               OpFunctionEnd
+
+)";
+
+TEST(DiffTest, OpextinstInDstOnly) {
+  constexpr char kDiff[] = R"( ; SPIR-V
+ ; Version: 1.6
+ ; Generator: Khronos SPIR-V Tools Assembler; 0
+-; Bound: 14
++; Bound: 16
+ ; Schema: 0
+ OpCapability Shader
++%14 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main" %9 %11
+ OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 310
+ OpName %4 "main"
+ OpName %9 "color"
+ OpName %11 "v"
+ OpDecorate %9 RelaxedPrecision
+ OpDecorate %9 Location 0
+ OpDecorate %11 RelaxedPrecision
+ OpDecorate %11 Location 0
+ OpDecorate %12 RelaxedPrecision
++OpDecorate %15 RelaxedPrecision
+ OpDecorate %13 RelaxedPrecision
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %6 = OpTypeFloat 32
+ %7 = OpTypeVector %6 4
+ %8 = OpTypePointer Output %7
+ %9 = OpVariable %8 Output
+ %10 = OpTypePointer Input %6
+ %11 = OpVariable %10 Input
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ %12 = OpLoad %6 %11
++%15 = OpExtInst %6 %14 Log2 %12
+-%13 = OpCompositeConstruct %7 %12 %12 %12 %12
++%13 = OpCompositeConstruct %7 %15 %15 %15 %15
+ OpStore %9 %13
+ OpReturn
+ OpFunctionEnd
+)";
+  Options options;
+  DoStringDiffTest(kSrc, kDst, kDiff, options);
+}
+
+TEST(DiffTest, OpextinstInDstOnlyNoDebug) {
+  constexpr char kSrcNoDebug[] = R"(               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %4 "main" %9 %11
+               OpExecutionMode %4 OriginUpperLeft
+               OpSource ESSL 310
+               OpDecorate %9 RelaxedPrecision
+               OpDecorate %9 Location 0
+               OpDecorate %11 RelaxedPrecision
+               OpDecorate %11 Location 0
+               OpDecorate %12 RelaxedPrecision
+               OpDecorate %13 RelaxedPrecision
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeFloat 32
+          %7 = OpTypeVector %6 4
+          %8 = OpTypePointer Output %7
+          %9 = OpVariable %8 Output
+         %10 = OpTypePointer Input %6
+         %11 = OpVariable %10 Input
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+         %12 = OpLoad %6 %11
+         %13 = OpCompositeConstruct %7 %12 %12 %12 %12
+               OpStore %9 %13
+               OpReturn
+               OpFunctionEnd
+
+)";
+  constexpr char kDstNoDebug[] = R"(               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %4 "main" %9 %11
+               OpExecutionMode %4 OriginUpperLeft
+               OpSource ESSL 310
+               OpDecorate %9 RelaxedPrecision
+               OpDecorate %9 Location 0
+               OpDecorate %11 RelaxedPrecision
+               OpDecorate %11 Location 0
+               OpDecorate %12 RelaxedPrecision
+               OpDecorate %13 RelaxedPrecision
+               OpDecorate %14 RelaxedPrecision
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeFloat 32
+          %7 = OpTypeVector %6 4
+          %8 = OpTypePointer Output %7
+          %9 = OpVariable %8 Output
+         %10 = OpTypePointer Input %6
+         %11 = OpVariable %10 Input
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+         %12 = OpLoad %6 %11
+         %13 = OpExtInst %6 %1 Log2 %12
+         %14 = OpCompositeConstruct %7 %13 %13 %13 %13
+               OpStore %9 %14
+               OpReturn
+               OpFunctionEnd
+
+)";
+  constexpr char kDiff[] = R"( ; SPIR-V
+ ; Version: 1.6
+ ; Generator: Khronos SPIR-V Tools Assembler; 0
+-; Bound: 14
++; Bound: 16
+ ; Schema: 0
+ OpCapability Shader
++%14 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main" %9 %11
+ OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 310
+ OpDecorate %9 RelaxedPrecision
+ OpDecorate %9 Location 0
+ OpDecorate %11 RelaxedPrecision
+ OpDecorate %11 Location 0
+ OpDecorate %12 RelaxedPrecision
++OpDecorate %15 RelaxedPrecision
+ OpDecorate %13 RelaxedPrecision
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %6 = OpTypeFloat 32
+ %7 = OpTypeVector %6 4
+ %8 = OpTypePointer Output %7
+ %9 = OpVariable %8 Output
+ %10 = OpTypePointer Input %6
+ %11 = OpVariable %10 Input
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ %12 = OpLoad %6 %11
++%15 = OpExtInst %6 %14 Log2 %12
+-%13 = OpCompositeConstruct %7 %12 %12 %12 %12
++%13 = OpCompositeConstruct %7 %15 %15 %15 %15
+ OpStore %9 %13
+ OpReturn
+ OpFunctionEnd
+)";
+  Options options;
+  DoStringDiffTest(kSrcNoDebug, kDstNoDebug, kDiff, options);
+}
+
+}  // namespace
+}  // namespace diff
+}  // namespace spvtools

+ 33 - 0
ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/OpExtInst_in_dst_only_dst.spvasm

@@ -0,0 +1,33 @@
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %4 "main" %9 %11
+               OpExecutionMode %4 OriginUpperLeft
+               OpSource ESSL 310
+               OpName %4 "main"
+               OpName %9 "color"
+               OpName %11 "v"
+               OpDecorate %9 RelaxedPrecision
+               OpDecorate %9 Location 0
+               OpDecorate %11 RelaxedPrecision
+               OpDecorate %11 Location 0
+               OpDecorate %12 RelaxedPrecision
+               OpDecorate %13 RelaxedPrecision
+               OpDecorate %14 RelaxedPrecision
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeFloat 32
+          %7 = OpTypeVector %6 4
+          %8 = OpTypePointer Output %7
+          %9 = OpVariable %8 Output
+         %10 = OpTypePointer Input %6
+         %11 = OpVariable %10 Input
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+         %12 = OpLoad %6 %11
+         %13 = OpExtInst %6 %1 Log2 %12
+         %14 = OpCompositeConstruct %7 %13 %13 %13 %13
+               OpStore %9 %14
+               OpReturn
+               OpFunctionEnd
+

+ 33 - 0
ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/OpExtInst_in_dst_only_src.spvasm

@@ -0,0 +1,33 @@
+;; Tests a diff where the src shader doesn't have OpExtImport while the
+;; dst shader does (and uses OpExtInst).  This test ensures that when matching,
+;; the OpExtImport instruction from the correct module is referenced.
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %4 "main" %9 %11
+               OpExecutionMode %4 OriginUpperLeft
+               OpSource ESSL 310
+               OpName %4 "main"
+               OpName %9 "color"
+               OpName %11 "v"
+               OpDecorate %9 RelaxedPrecision
+               OpDecorate %9 Location 0
+               OpDecorate %11 RelaxedPrecision
+               OpDecorate %11 Location 0
+               OpDecorate %12 RelaxedPrecision
+               OpDecorate %13 RelaxedPrecision
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeFloat 32
+          %7 = OpTypeVector %6 4
+          %8 = OpTypePointer Output %7
+          %9 = OpVariable %8 Output
+         %10 = OpTypePointer Input %6
+         %11 = OpVariable %10 Input
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+         %12 = OpLoad %6 %11
+         %13 = OpCompositeConstruct %7 %12 %12 %12 %12
+               OpStore %9 %13
+               OpReturn
+               OpFunctionEnd
+

+ 242 - 0
ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/OpExtInst_in_src_only_autogen.cpp

@@ -0,0 +1,242 @@
+// GENERATED FILE - DO NOT EDIT.
+// Generated by generate_tests.py
+//
+// 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 "../diff_test_utils.h"
+
+#include "gtest/gtest.h"
+
+namespace spvtools {
+namespace diff {
+namespace {
+
+// Tests a diff where the dst shader doesn't have OpExtImport while the
+// src shader does (and uses OpExtInst).  This test ensures that when matching,
+// the OpExtImport instruction from the correct module is referenced.
+constexpr char kSrc[] = R"(               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %4 "main" %9 %11
+               OpExecutionMode %4 OriginUpperLeft
+               OpSource ESSL 310
+               OpName %4 "main"
+               OpName %9 "color"
+               OpName %11 "v"
+               OpDecorate %9 RelaxedPrecision
+               OpDecorate %9 Location 0
+               OpDecorate %11 RelaxedPrecision
+               OpDecorate %11 Location 0
+               OpDecorate %12 RelaxedPrecision
+               OpDecorate %13 RelaxedPrecision
+               OpDecorate %14 RelaxedPrecision
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeFloat 32
+          %7 = OpTypeVector %6 4
+          %8 = OpTypePointer Output %7
+          %9 = OpVariable %8 Output
+         %10 = OpTypePointer Input %6
+         %11 = OpVariable %10 Input
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+         %12 = OpLoad %6 %11
+         %13 = OpExtInst %6 %1 Log2 %12
+         %14 = OpCompositeConstruct %7 %13 %13 %13 %13
+               OpStore %9 %14
+               OpReturn
+               OpFunctionEnd
+)";
+constexpr char kDst[] = R"(               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %4 "main" %9 %11
+               OpExecutionMode %4 OriginUpperLeft
+               OpSource ESSL 310
+               OpName %4 "main"
+               OpName %9 "color"
+               OpName %11 "v"
+               OpDecorate %9 RelaxedPrecision
+               OpDecorate %9 Location 0
+               OpDecorate %11 RelaxedPrecision
+               OpDecorate %11 Location 0
+               OpDecorate %12 RelaxedPrecision
+               OpDecorate %13 RelaxedPrecision
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeFloat 32
+          %7 = OpTypeVector %6 4
+          %8 = OpTypePointer Output %7
+          %9 = OpVariable %8 Output
+         %10 = OpTypePointer Input %6
+         %11 = OpVariable %10 Input
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+         %12 = OpLoad %6 %11
+         %13 = OpCompositeConstruct %7 %12 %12 %12 %12
+               OpStore %9 %13
+               OpReturn
+               OpFunctionEnd
+
+)";
+
+TEST(DiffTest, OpextinstInSrcOnly) {
+  constexpr char kDiff[] = R"( ; SPIR-V
+ ; Version: 1.6
+ ; Generator: Khronos SPIR-V Tools Assembler; 0
+-; Bound: 15
++; Bound: 16
+ ; Schema: 0
+ OpCapability Shader
+-%1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main" %9 %11
+ OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 310
+ OpName %4 "main"
+ OpName %9 "color"
+ OpName %11 "v"
+ OpDecorate %9 RelaxedPrecision
+ OpDecorate %9 Location 0
+ OpDecorate %11 RelaxedPrecision
+ OpDecorate %11 Location 0
+ OpDecorate %12 RelaxedPrecision
+-OpDecorate %13 RelaxedPrecision
+ OpDecorate %14 RelaxedPrecision
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %6 = OpTypeFloat 32
+ %7 = OpTypeVector %6 4
+ %8 = OpTypePointer Output %7
+ %9 = OpVariable %8 Output
+ %10 = OpTypePointer Input %6
+ %11 = OpVariable %10 Input
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ %12 = OpLoad %6 %11
+-%13 = OpExtInst %6 %1 Log2 %12
+-%14 = OpCompositeConstruct %7 %13 %13 %13 %13
++%14 = OpCompositeConstruct %7 %12 %12 %12 %12
+ OpStore %9 %14
+ OpReturn
+ OpFunctionEnd
+)";
+  Options options;
+  DoStringDiffTest(kSrc, kDst, kDiff, options);
+}
+
+TEST(DiffTest, OpextinstInSrcOnlyNoDebug) {
+  constexpr char kSrcNoDebug[] = R"(               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %4 "main" %9 %11
+               OpExecutionMode %4 OriginUpperLeft
+               OpSource ESSL 310
+               OpDecorate %9 RelaxedPrecision
+               OpDecorate %9 Location 0
+               OpDecorate %11 RelaxedPrecision
+               OpDecorate %11 Location 0
+               OpDecorate %12 RelaxedPrecision
+               OpDecorate %13 RelaxedPrecision
+               OpDecorate %14 RelaxedPrecision
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeFloat 32
+          %7 = OpTypeVector %6 4
+          %8 = OpTypePointer Output %7
+          %9 = OpVariable %8 Output
+         %10 = OpTypePointer Input %6
+         %11 = OpVariable %10 Input
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+         %12 = OpLoad %6 %11
+         %13 = OpExtInst %6 %1 Log2 %12
+         %14 = OpCompositeConstruct %7 %13 %13 %13 %13
+               OpStore %9 %14
+               OpReturn
+               OpFunctionEnd
+
+)";
+  constexpr char kDstNoDebug[] = R"(               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %4 "main" %9 %11
+               OpExecutionMode %4 OriginUpperLeft
+               OpSource ESSL 310
+               OpDecorate %9 RelaxedPrecision
+               OpDecorate %9 Location 0
+               OpDecorate %11 RelaxedPrecision
+               OpDecorate %11 Location 0
+               OpDecorate %12 RelaxedPrecision
+               OpDecorate %13 RelaxedPrecision
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeFloat 32
+          %7 = OpTypeVector %6 4
+          %8 = OpTypePointer Output %7
+          %9 = OpVariable %8 Output
+         %10 = OpTypePointer Input %6
+         %11 = OpVariable %10 Input
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+         %12 = OpLoad %6 %11
+         %13 = OpCompositeConstruct %7 %12 %12 %12 %12
+               OpStore %9 %13
+               OpReturn
+               OpFunctionEnd
+
+)";
+  constexpr char kDiff[] = R"( ; SPIR-V
+ ; Version: 1.6
+ ; Generator: Khronos SPIR-V Tools Assembler; 0
+-; Bound: 15
++; Bound: 16
+ ; Schema: 0
+ OpCapability Shader
+-%1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main" %9 %11
+ OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 310
+ OpDecorate %9 RelaxedPrecision
+ OpDecorate %9 Location 0
+ OpDecorate %11 RelaxedPrecision
+ OpDecorate %11 Location 0
+ OpDecorate %12 RelaxedPrecision
+-OpDecorate %13 RelaxedPrecision
+ OpDecorate %14 RelaxedPrecision
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %6 = OpTypeFloat 32
+ %7 = OpTypeVector %6 4
+ %8 = OpTypePointer Output %7
+ %9 = OpVariable %8 Output
+ %10 = OpTypePointer Input %6
+ %11 = OpVariable %10 Input
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ %12 = OpLoad %6 %11
+-%13 = OpExtInst %6 %1 Log2 %12
+-%14 = OpCompositeConstruct %7 %13 %13 %13 %13
++%14 = OpCompositeConstruct %7 %12 %12 %12 %12
+ OpStore %9 %14
+ OpReturn
+ OpFunctionEnd
+)";
+  Options options;
+  DoStringDiffTest(kSrcNoDebug, kDstNoDebug, kDiff, options);
+}
+
+}  // namespace
+}  // namespace diff
+}  // namespace spvtools

+ 30 - 0
ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/OpExtInst_in_src_only_dst.spvasm

@@ -0,0 +1,30 @@
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %4 "main" %9 %11
+               OpExecutionMode %4 OriginUpperLeft
+               OpSource ESSL 310
+               OpName %4 "main"
+               OpName %9 "color"
+               OpName %11 "v"
+               OpDecorate %9 RelaxedPrecision
+               OpDecorate %9 Location 0
+               OpDecorate %11 RelaxedPrecision
+               OpDecorate %11 Location 0
+               OpDecorate %12 RelaxedPrecision
+               OpDecorate %13 RelaxedPrecision
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeFloat 32
+          %7 = OpTypeVector %6 4
+          %8 = OpTypePointer Output %7
+          %9 = OpVariable %8 Output
+         %10 = OpTypePointer Input %6
+         %11 = OpVariable %10 Input
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+         %12 = OpLoad %6 %11
+         %13 = OpCompositeConstruct %7 %12 %12 %12 %12
+               OpStore %9 %13
+               OpReturn
+               OpFunctionEnd
+

+ 36 - 0
ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/OpExtInst_in_src_only_src.spvasm

@@ -0,0 +1,36 @@
+;; Tests a diff where the dst shader doesn't have OpExtImport while the
+;; src shader does (and uses OpExtInst).  This test ensures that when matching,
+;; the OpExtImport instruction from the correct module is referenced.
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %4 "main" %9 %11
+               OpExecutionMode %4 OriginUpperLeft
+               OpSource ESSL 310
+               OpName %4 "main"
+               OpName %9 "color"
+               OpName %11 "v"
+               OpDecorate %9 RelaxedPrecision
+               OpDecorate %9 Location 0
+               OpDecorate %11 RelaxedPrecision
+               OpDecorate %11 Location 0
+               OpDecorate %12 RelaxedPrecision
+               OpDecorate %13 RelaxedPrecision
+               OpDecorate %14 RelaxedPrecision
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeFloat 32
+          %7 = OpTypeVector %6 4
+          %8 = OpTypePointer Output %7
+          %9 = OpVariable %8 Output
+         %10 = OpTypePointer Input %6
+         %11 = OpVariable %10 Input
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+         %12 = OpLoad %6 %11
+         %13 = OpExtInst %6 %1 Log2 %12
+         %14 = OpCompositeConstruct %7 %13 %13 %13 %13
+               OpStore %9 %14
+               OpReturn
+               OpFunctionEnd
+

+ 136 - 0
ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/OpTypeForwardPointer_basic_autogen.cpp

@@ -0,0 +1,136 @@
+// GENERATED FILE - DO NOT EDIT.
+// Generated by generate_tests.py
+//
+// 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 "../diff_test_utils.h"
+
+#include "gtest/gtest.h"
+
+namespace spvtools {
+namespace diff {
+namespace {
+
+// Basic test that OpTypeForwardPointer is matched
+constexpr char kSrc[] = R"(               OpCapability Kernel
+               OpCapability Addresses
+               OpCapability Linkage
+               OpMemoryModel Logical OpenCL
+               OpName %structptr "structptr"
+               OpTypeForwardPointer %structptr UniformConstant
+       %uint = OpTypeInt 32 0
+   %structt1 = OpTypeStruct %structptr %uint
+   %structt2 = OpTypeStruct %uint %structptr
+   %structt3 = OpTypeStruct %uint %uint %structptr
+   %structt4 = OpTypeStruct %uint %uint %uint %structptr
+  %structptr = OpTypePointer UniformConstant %structt1)";
+constexpr char kDst[] = R"(               OpCapability Kernel
+               OpCapability Addresses
+               OpCapability Linkage
+               OpMemoryModel Logical OpenCL
+               OpName %structptr "structptr"
+               OpName %structptr2 "structptr2"
+               OpTypeForwardPointer %structptr UniformConstant
+               OpTypeForwardPointer %structptr2 Function
+       %uint = OpTypeInt 32 0
+   %structt1 = OpTypeStruct %structptr %uint
+   %structt2 = OpTypeStruct %uint %structptr
+   %structt3 = OpTypeStruct %uint %uint %structptr
+   %structt4 = OpTypeStruct %uint %uint %uint %structptr
+  %structptr = OpTypePointer UniformConstant %structt1
+  %structptr2 = OpTypePointer Function %structt1
+)";
+
+TEST(DiffTest, OptypeforwardpointerBasic) {
+  constexpr char kDiff[] = R"( ; SPIR-V
+ ; Version: 1.6
+ ; Generator: Khronos SPIR-V Tools Assembler; 0
+-; Bound: 7
++; Bound: 8
+ ; Schema: 0
+ OpCapability Kernel
+ OpCapability Addresses
+ OpCapability Linkage
+ OpMemoryModel Logical OpenCL
+ OpName %1 "structptr"
++OpName %7 "structptr2"
+ OpTypeForwardPointer %1 UniformConstant
++OpTypeForwardPointer %7 Function
+ %2 = OpTypeInt 32 0
+ %3 = OpTypeStruct %1 %2
+ %4 = OpTypeStruct %2 %1
+ %5 = OpTypeStruct %2 %2 %1
+ %6 = OpTypeStruct %2 %2 %2 %1
+ %1 = OpTypePointer UniformConstant %3
++%7 = OpTypePointer Function %3
+)";
+  Options options;
+  DoStringDiffTest(kSrc, kDst, kDiff, options);
+}
+
+TEST(DiffTest, OptypeforwardpointerBasicNoDebug) {
+  constexpr char kSrcNoDebug[] = R"(               OpCapability Kernel
+               OpCapability Addresses
+               OpCapability Linkage
+               OpMemoryModel Logical OpenCL
+               OpTypeForwardPointer %structptr UniformConstant
+       %uint = OpTypeInt 32 0
+   %structt1 = OpTypeStruct %structptr %uint
+   %structt2 = OpTypeStruct %uint %structptr
+   %structt3 = OpTypeStruct %uint %uint %structptr
+   %structt4 = OpTypeStruct %uint %uint %uint %structptr
+  %structptr = OpTypePointer UniformConstant %structt1
+)";
+  constexpr char kDstNoDebug[] = R"(               OpCapability Kernel
+               OpCapability Addresses
+               OpCapability Linkage
+               OpMemoryModel Logical OpenCL
+               OpTypeForwardPointer %structptr UniformConstant
+               OpTypeForwardPointer %structptr2 Function
+       %uint = OpTypeInt 32 0
+   %structt1 = OpTypeStruct %structptr %uint
+   %structt2 = OpTypeStruct %uint %structptr
+   %structt3 = OpTypeStruct %uint %uint %structptr
+   %structt4 = OpTypeStruct %uint %uint %uint %structptr
+  %structptr = OpTypePointer UniformConstant %structt1
+  %structptr2 = OpTypePointer Function %structt1
+)";
+  constexpr char kDiff[] = R"( ; SPIR-V
+ ; Version: 1.6
+ ; Generator: Khronos SPIR-V Tools Assembler; 0
+-; Bound: 7
++; Bound: 8
+ ; Schema: 0
+ OpCapability Kernel
+ OpCapability Addresses
+ OpCapability Linkage
+ OpMemoryModel Logical OpenCL
+ OpTypeForwardPointer %1 UniformConstant
++OpTypeForwardPointer %7 Function
+ %2 = OpTypeInt 32 0
+ %3 = OpTypeStruct %1 %2
+ %4 = OpTypeStruct %2 %1
+ %5 = OpTypeStruct %2 %2 %1
+ %6 = OpTypeStruct %2 %2 %2 %1
+ %1 = OpTypePointer UniformConstant %3
++%7 = OpTypePointer Function %3
+)";
+  Options options;
+  DoStringDiffTest(kSrcNoDebug, kDstNoDebug, kDiff, options);
+}
+
+}  // namespace
+}  // namespace diff
+}  // namespace spvtools

+ 15 - 0
ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/OpTypeForwardPointer_basic_dst.spvasm

@@ -0,0 +1,15 @@
+               OpCapability Kernel
+               OpCapability Addresses
+               OpCapability Linkage
+               OpMemoryModel Logical OpenCL
+               OpName %structptr "structptr"
+               OpName %structptr2 "structptr2"
+               OpTypeForwardPointer %structptr UniformConstant
+               OpTypeForwardPointer %structptr2 Function
+       %uint = OpTypeInt 32 0
+   %structt1 = OpTypeStruct %structptr %uint
+   %structt2 = OpTypeStruct %uint %structptr
+   %structt3 = OpTypeStruct %uint %uint %structptr
+   %structt4 = OpTypeStruct %uint %uint %uint %structptr
+  %structptr = OpTypePointer UniformConstant %structt1
+  %structptr2 = OpTypePointer Function %structt1

+ 13 - 0
ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/OpTypeForwardPointer_basic_src.spvasm

@@ -0,0 +1,13 @@
+;; Basic test that OpTypeForwardPointer is matched
+               OpCapability Kernel
+               OpCapability Addresses
+               OpCapability Linkage
+               OpMemoryModel Logical OpenCL
+               OpName %structptr "structptr"
+               OpTypeForwardPointer %structptr UniformConstant
+       %uint = OpTypeInt 32 0
+   %structt1 = OpTypeStruct %structptr %uint
+   %structt2 = OpTypeStruct %uint %structptr
+   %structt3 = OpTypeStruct %uint %uint %structptr
+   %structt4 = OpTypeStruct %uint %uint %uint %structptr
+  %structptr = OpTypePointer UniformConstant %structt1

+ 138 - 0
ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/OpTypeForwardPointer_intertwined_autogen.cpp

@@ -0,0 +1,138 @@
+// GENERATED FILE - DO NOT EDIT.
+// Generated by generate_tests.py
+//
+// 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 "../diff_test_utils.h"
+
+#include "gtest/gtest.h"
+
+namespace spvtools {
+namespace diff {
+namespace {
+
+// Tests that two forwarded types whose declarations are intertwined match
+// correctly
+constexpr char kSrc[] = R"(               OpCapability Kernel
+               OpCapability Addresses
+               OpCapability Linkage
+               OpMemoryModel Logical OpenCL
+               OpName %Aptr "Aptr"
+               OpName %Bptr "Bptr"
+               OpTypeForwardPointer %Aptr UniformConstant
+               OpTypeForwardPointer %Bptr UniformConstant
+       %uint = OpTypeInt 32 0
+          %A = OpTypeStruct %Aptr %uint %Bptr
+          %B = OpTypeStruct %uint %Aptr %Bptr
+  %Aptr = OpTypePointer UniformConstant %A
+  %Bptr = OpTypePointer UniformConstant %B)";
+constexpr char kDst[] = R"(               OpCapability Kernel
+               OpCapability Addresses
+               OpCapability Linkage
+               OpMemoryModel Logical OpenCL
+               OpName %Aptr "Aptr"
+               OpName %Bptr "Bptr"
+               OpTypeForwardPointer %Bptr UniformConstant
+               OpTypeForwardPointer %Aptr UniformConstant
+       %uint = OpTypeInt 32 0
+          %B = OpTypeStruct %uint %Aptr %Bptr %uint
+          %A = OpTypeStruct %Aptr %uint %Bptr
+  %Aptr = OpTypePointer UniformConstant %A
+  %Bptr = OpTypePointer UniformConstant %B
+)";
+
+TEST(DiffTest, OptypeforwardpointerIntertwined) {
+  constexpr char kDiff[] = R"( ; SPIR-V
+ ; Version: 1.6
+ ; Generator: Khronos SPIR-V Tools Assembler; 0
+-; Bound: 6
++; Bound: 7
+ ; Schema: 0
+ OpCapability Kernel
+ OpCapability Addresses
+ OpCapability Linkage
+ OpMemoryModel Logical OpenCL
+ OpName %1 "Aptr"
+ OpName %2 "Bptr"
+ OpTypeForwardPointer %1 UniformConstant
+ OpTypeForwardPointer %2 UniformConstant
+ %3 = OpTypeInt 32 0
++%6 = OpTypeStruct %3 %1 %2 %3
+ %4 = OpTypeStruct %1 %3 %2
+-%5 = OpTypeStruct %3 %1 %2
+ %1 = OpTypePointer UniformConstant %4
+-%2 = OpTypePointer UniformConstant %5
++%2 = OpTypePointer UniformConstant %6
+)";
+  Options options;
+  DoStringDiffTest(kSrc, kDst, kDiff, options);
+}
+
+TEST(DiffTest, OptypeforwardpointerIntertwinedNoDebug) {
+  constexpr char kSrcNoDebug[] = R"(               OpCapability Kernel
+               OpCapability Addresses
+               OpCapability Linkage
+               OpMemoryModel Logical OpenCL
+               OpTypeForwardPointer %Aptr UniformConstant
+               OpTypeForwardPointer %Bptr UniformConstant
+       %uint = OpTypeInt 32 0
+          %A = OpTypeStruct %Aptr %uint %Bptr
+          %B = OpTypeStruct %uint %Aptr %Bptr
+  %Aptr = OpTypePointer UniformConstant %A
+  %Bptr = OpTypePointer UniformConstant %B
+)";
+  constexpr char kDstNoDebug[] = R"(               OpCapability Kernel
+               OpCapability Addresses
+               OpCapability Linkage
+               OpMemoryModel Logical OpenCL
+               OpTypeForwardPointer %Bptr UniformConstant
+               OpTypeForwardPointer %Aptr UniformConstant
+       %uint = OpTypeInt 32 0
+          %B = OpTypeStruct %uint %Aptr %Bptr %uint
+          %A = OpTypeStruct %Aptr %uint %Bptr
+  %Aptr = OpTypePointer UniformConstant %A
+  %Bptr = OpTypePointer UniformConstant %B
+)";
+  constexpr char kDiff[] = R"( ; SPIR-V
+ ; Version: 1.6
+ ; Generator: Khronos SPIR-V Tools Assembler; 0
+-; Bound: 6
++; Bound: 10
+ ; Schema: 0
+ OpCapability Kernel
+ OpCapability Addresses
+ OpCapability Linkage
+ OpMemoryModel Logical OpenCL
+-OpTypeForwardPointer %1 UniformConstant
+-OpTypeForwardPointer %2 UniformConstant
++OpTypeForwardPointer %6 UniformConstant
++OpTypeForwardPointer %7 UniformConstant
+ %3 = OpTypeInt 32 0
+-%4 = OpTypeStruct %1 %3 %2
+-%5 = OpTypeStruct %3 %1 %2
+-%1 = OpTypePointer UniformConstant %4
+-%2 = OpTypePointer UniformConstant %5
++%8 = OpTypeStruct %3 %7 %6 %3
++%9 = OpTypeStruct %7 %3 %6
++%7 = OpTypePointer UniformConstant %9
++%6 = OpTypePointer UniformConstant %8
+)";
+  Options options;
+  DoStringDiffTest(kSrcNoDebug, kDstNoDebug, kDiff, options);
+}
+
+}  // namespace
+}  // namespace diff
+}  // namespace spvtools

+ 13 - 0
ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/OpTypeForwardPointer_intertwined_dst.spvasm

@@ -0,0 +1,13 @@
+               OpCapability Kernel
+               OpCapability Addresses
+               OpCapability Linkage
+               OpMemoryModel Logical OpenCL
+               OpName %Aptr "Aptr"
+               OpName %Bptr "Bptr"
+               OpTypeForwardPointer %Bptr UniformConstant
+               OpTypeForwardPointer %Aptr UniformConstant
+       %uint = OpTypeInt 32 0
+          %B = OpTypeStruct %uint %Aptr %Bptr %uint
+          %A = OpTypeStruct %Aptr %uint %Bptr
+  %Aptr = OpTypePointer UniformConstant %A
+  %Bptr = OpTypePointer UniformConstant %B

+ 15 - 0
ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/OpTypeForwardPointer_intertwined_src.spvasm

@@ -0,0 +1,15 @@
+;; Tests that two forwarded types whose declarations are intertwined match
+;; correctly
+               OpCapability Kernel
+               OpCapability Addresses
+               OpCapability Linkage
+               OpMemoryModel Logical OpenCL
+               OpName %Aptr "Aptr"
+               OpName %Bptr "Bptr"
+               OpTypeForwardPointer %Aptr UniformConstant
+               OpTypeForwardPointer %Bptr UniformConstant
+       %uint = OpTypeInt 32 0
+          %A = OpTypeStruct %Aptr %uint %Bptr
+          %B = OpTypeStruct %uint %Aptr %Bptr
+  %Aptr = OpTypePointer UniformConstant %A
+  %Bptr = OpTypePointer UniformConstant %B

+ 116 - 0
ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/OpTypeForwardPointer_mismatching_class_autogen.cpp

@@ -0,0 +1,116 @@
+// GENERATED FILE - DO NOT EDIT.
+// Generated by generate_tests.py
+//
+// 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 "../diff_test_utils.h"
+
+#include "gtest/gtest.h"
+
+namespace spvtools {
+namespace diff {
+namespace {
+
+// Tests that two forwarded type pointers with mismatching storage classes
+// aren't matched
+constexpr char kSrc[] = R"(               OpCapability Kernel
+               OpCapability Addresses
+               OpCapability Linkage
+               OpMemoryModel Logical OpenCL
+               OpName %Aptr "Aptr"
+               OpTypeForwardPointer %Aptr UniformConstant
+       %uint = OpTypeInt 32 0
+          %A = OpTypeStruct %Aptr %uint
+  %Aptr = OpTypePointer UniformConstant %A)";
+constexpr char kDst[] = R"(               OpCapability Kernel
+               OpCapability Addresses
+               OpCapability Linkage
+               OpMemoryModel Logical OpenCL
+               OpName %Aptr "Aptr"
+               OpTypeForwardPointer %Aptr Function
+       %uint = OpTypeInt 32 0
+          %A = OpTypeStruct %Aptr %uint
+  %Aptr = OpTypePointer Function %A
+)";
+
+TEST(DiffTest, OptypeforwardpointerMismatchingClass) {
+  constexpr char kDiff[] = R"( ; SPIR-V
+ ; Version: 1.6
+ ; Generator: Khronos SPIR-V Tools Assembler; 0
+-; Bound: 4
++; Bound: 6
+ ; Schema: 0
+ OpCapability Kernel
+ OpCapability Addresses
+ OpCapability Linkage
+ OpMemoryModel Logical OpenCL
+-OpName %1 "Aptr"
++OpName %4 "Aptr"
+-OpTypeForwardPointer %1 UniformConstant
++OpTypeForwardPointer %4 Function
+ %2 = OpTypeInt 32 0
+-%3 = OpTypeStruct %1 %2
+-%1 = OpTypePointer UniformConstant %3
++%5 = OpTypeStruct %4 %2
++%4 = OpTypePointer Function %5
+)";
+  Options options;
+  DoStringDiffTest(kSrc, kDst, kDiff, options);
+}
+
+TEST(DiffTest, OptypeforwardpointerMismatchingClassNoDebug) {
+  constexpr char kSrcNoDebug[] = R"(               OpCapability Kernel
+               OpCapability Addresses
+               OpCapability Linkage
+               OpMemoryModel Logical OpenCL
+               OpTypeForwardPointer %Aptr UniformConstant
+       %uint = OpTypeInt 32 0
+          %A = OpTypeStruct %Aptr %uint
+  %Aptr = OpTypePointer UniformConstant %A
+)";
+  constexpr char kDstNoDebug[] = R"(               OpCapability Kernel
+               OpCapability Addresses
+               OpCapability Linkage
+               OpMemoryModel Logical OpenCL
+               OpTypeForwardPointer %Aptr Function
+       %uint = OpTypeInt 32 0
+          %A = OpTypeStruct %Aptr %uint
+  %Aptr = OpTypePointer Function %A
+)";
+  constexpr char kDiff[] = R"( ; SPIR-V
+ ; Version: 1.6
+ ; Generator: Khronos SPIR-V Tools Assembler; 0
+-; Bound: 4
++; Bound: 6
+ ; Schema: 0
+ OpCapability Kernel
+ OpCapability Addresses
+ OpCapability Linkage
+ OpMemoryModel Logical OpenCL
+-OpTypeForwardPointer %1 UniformConstant
++OpTypeForwardPointer %4 Function
+ %2 = OpTypeInt 32 0
+-%3 = OpTypeStruct %1 %2
+-%1 = OpTypePointer UniformConstant %3
++%5 = OpTypeStruct %4 %2
++%4 = OpTypePointer Function %5
+)";
+  Options options;
+  DoStringDiffTest(kSrcNoDebug, kDstNoDebug, kDiff, options);
+}
+
+}  // namespace
+}  // namespace diff
+}  // namespace spvtools

+ 9 - 0
ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/OpTypeForwardPointer_mismatching_class_dst.spvasm

@@ -0,0 +1,9 @@
+               OpCapability Kernel
+               OpCapability Addresses
+               OpCapability Linkage
+               OpMemoryModel Logical OpenCL
+               OpName %Aptr "Aptr"
+               OpTypeForwardPointer %Aptr Function
+       %uint = OpTypeInt 32 0
+          %A = OpTypeStruct %Aptr %uint
+  %Aptr = OpTypePointer Function %A

+ 11 - 0
ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/OpTypeForwardPointer_mismatching_class_src.spvasm

@@ -0,0 +1,11 @@
+;; Tests that two forwarded type pointers with mismatching storage classes
+;; aren't matched
+               OpCapability Kernel
+               OpCapability Addresses
+               OpCapability Linkage
+               OpMemoryModel Logical OpenCL
+               OpName %Aptr "Aptr"
+               OpTypeForwardPointer %Aptr UniformConstant
+       %uint = OpTypeInt 32 0
+          %A = OpTypeStruct %Aptr %uint
+  %Aptr = OpTypePointer UniformConstant %A

+ 111 - 0
ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/OpTypeForwardPointer_mismatching_type_autogen.cpp

@@ -0,0 +1,111 @@
+// GENERATED FILE - DO NOT EDIT.
+// Generated by generate_tests.py
+//
+// 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 "../diff_test_utils.h"
+
+#include "gtest/gtest.h"
+
+namespace spvtools {
+namespace diff {
+namespace {
+
+// Tests that two forwarded type pointers with mismatching types aren't matched
+constexpr char kSrc[] = R"(               OpCapability Kernel
+               OpCapability Addresses
+               OpCapability Linkage
+               OpMemoryModel Logical OpenCL
+               OpName %Aptr "Aptr"
+               OpTypeForwardPointer %Aptr UniformConstant
+       %uint = OpTypeInt 32 0
+          %A = OpTypeStruct %Aptr %uint
+  %Aptr = OpTypePointer UniformConstant %A)";
+constexpr char kDst[] = R"(               OpCapability Kernel
+               OpCapability Addresses
+               OpCapability Linkage
+               OpMemoryModel Logical OpenCL
+               OpName %Aptr "Aptr"
+               OpTypeForwardPointer %Aptr UniformConstant
+       %uint = OpTypeInt 32 0
+  %Aptr = OpTypePointer UniformConstant %uint
+)";
+
+TEST(DiffTest, OptypeforwardpointerMismatchingType) {
+  constexpr char kDiff[] = R"( ; SPIR-V
+ ; Version: 1.6
+ ; Generator: Khronos SPIR-V Tools Assembler; 0
+-; Bound: 4
++; Bound: 5
+ ; Schema: 0
+ OpCapability Kernel
+ OpCapability Addresses
+ OpCapability Linkage
+ OpMemoryModel Logical OpenCL
+-OpName %1 "Aptr"
++OpName %4 "Aptr"
+-OpTypeForwardPointer %1 UniformConstant
++OpTypeForwardPointer %4 UniformConstant
+ %2 = OpTypeInt 32 0
+-%3 = OpTypeStruct %1 %2
+-%1 = OpTypePointer UniformConstant %3
++%4 = OpTypePointer UniformConstant %2
+)";
+  Options options;
+  DoStringDiffTest(kSrc, kDst, kDiff, options);
+}
+
+TEST(DiffTest, OptypeforwardpointerMismatchingTypeNoDebug) {
+  constexpr char kSrcNoDebug[] = R"(               OpCapability Kernel
+               OpCapability Addresses
+               OpCapability Linkage
+               OpMemoryModel Logical OpenCL
+               OpTypeForwardPointer %Aptr UniformConstant
+       %uint = OpTypeInt 32 0
+          %A = OpTypeStruct %Aptr %uint
+  %Aptr = OpTypePointer UniformConstant %A
+)";
+  constexpr char kDstNoDebug[] = R"(               OpCapability Kernel
+               OpCapability Addresses
+               OpCapability Linkage
+               OpMemoryModel Logical OpenCL
+               OpTypeForwardPointer %Aptr UniformConstant
+       %uint = OpTypeInt 32 0
+  %Aptr = OpTypePointer UniformConstant %uint
+)";
+  constexpr char kDiff[] = R"( ; SPIR-V
+ ; Version: 1.6
+ ; Generator: Khronos SPIR-V Tools Assembler; 0
+-; Bound: 4
++; Bound: 5
+ ; Schema: 0
+ OpCapability Kernel
+ OpCapability Addresses
+ OpCapability Linkage
+ OpMemoryModel Logical OpenCL
+-OpTypeForwardPointer %1 UniformConstant
++OpTypeForwardPointer %4 UniformConstant
+ %2 = OpTypeInt 32 0
+-%3 = OpTypeStruct %1 %2
+-%1 = OpTypePointer UniformConstant %3
++%4 = OpTypePointer UniformConstant %2
+)";
+  Options options;
+  DoStringDiffTest(kSrcNoDebug, kDstNoDebug, kDiff, options);
+}
+
+}  // namespace
+}  // namespace diff
+}  // namespace spvtools

+ 8 - 0
ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/OpTypeForwardPointer_mismatching_type_dst.spvasm

@@ -0,0 +1,8 @@
+               OpCapability Kernel
+               OpCapability Addresses
+               OpCapability Linkage
+               OpMemoryModel Logical OpenCL
+               OpName %Aptr "Aptr"
+               OpTypeForwardPointer %Aptr UniformConstant
+       %uint = OpTypeInt 32 0
+  %Aptr = OpTypePointer UniformConstant %uint

+ 10 - 0
ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/OpTypeForwardPointer_mismatching_type_src.spvasm

@@ -0,0 +1,10 @@
+;; Tests that two forwarded type pointers with mismatching types aren't matched
+               OpCapability Kernel
+               OpCapability Addresses
+               OpCapability Linkage
+               OpMemoryModel Logical OpenCL
+               OpName %Aptr "Aptr"
+               OpTypeForwardPointer %Aptr UniformConstant
+       %uint = OpTypeInt 32 0
+          %A = OpTypeStruct %Aptr %uint
+  %Aptr = OpTypePointer UniformConstant %A

+ 127 - 0
ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/OpTypeForwardPointer_nested_autogen.cpp

@@ -0,0 +1,127 @@
+// GENERATED FILE - DO NOT EDIT.
+// Generated by generate_tests.py
+//
+// 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 "../diff_test_utils.h"
+
+#include "gtest/gtest.h"
+
+namespace spvtools {
+namespace diff {
+namespace {
+
+// Tests that two forwarded declarations match even if the type pointer is used
+// in a nested struct declaration, and in multiple places
+constexpr char kSrc[] = R"(               OpCapability Kernel
+               OpCapability Addresses
+               OpCapability Linkage
+               OpMemoryModel Logical OpenCL
+               OpName %Aptr "Aptr"
+               OpTypeForwardPointer %Aptr UniformConstant
+       %uint = OpTypeInt 32 0
+          %C = OpTypeStruct %Aptr %uint %Aptr
+          %B = OpTypeStruct %C %Aptr %uint
+          %A = OpTypeStruct %B %C %B
+  %Aptr = OpTypePointer UniformConstant %A)";
+constexpr char kDst[] = R"(               OpCapability Kernel
+               OpCapability Addresses
+               OpCapability Linkage
+               OpMemoryModel Logical OpenCL
+               OpName %Aptr "Aptr"
+               OpTypeForwardPointer %Aptr UniformConstant
+       %uint = OpTypeInt 32 0
+          %C = OpTypeStruct %Aptr %uint %Aptr
+          %B = OpTypeStruct %C %Aptr
+          %A = OpTypeStruct %B %C %B
+  %Aptr = OpTypePointer UniformConstant %A
+)";
+
+TEST(DiffTest, OptypeforwardpointerNested) {
+  constexpr char kDiff[] = R"( ; SPIR-V
+ ; Version: 1.6
+ ; Generator: Khronos SPIR-V Tools Assembler; 0
+-; Bound: 6
++; Bound: 8
+ ; Schema: 0
+ OpCapability Kernel
+ OpCapability Addresses
+ OpCapability Linkage
+ OpMemoryModel Logical OpenCL
+ OpName %1 "Aptr"
+ OpTypeForwardPointer %1 UniformConstant
+ %2 = OpTypeInt 32 0
+ %3 = OpTypeStruct %1 %2 %1
+-%4 = OpTypeStruct %3 %1 %2
+-%5 = OpTypeStruct %4 %3 %4
++%6 = OpTypeStruct %3 %1
++%7 = OpTypeStruct %6 %3 %6
+-%1 = OpTypePointer UniformConstant %5
++%1 = OpTypePointer UniformConstant %7
+)";
+  Options options;
+  DoStringDiffTest(kSrc, kDst, kDiff, options);
+}
+
+TEST(DiffTest, OptypeforwardpointerNestedNoDebug) {
+  constexpr char kSrcNoDebug[] = R"(               OpCapability Kernel
+               OpCapability Addresses
+               OpCapability Linkage
+               OpMemoryModel Logical OpenCL
+               OpTypeForwardPointer %Aptr UniformConstant
+       %uint = OpTypeInt 32 0
+          %C = OpTypeStruct %Aptr %uint %Aptr
+          %B = OpTypeStruct %C %Aptr %uint
+          %A = OpTypeStruct %B %C %B
+  %Aptr = OpTypePointer UniformConstant %A
+)";
+  constexpr char kDstNoDebug[] = R"(               OpCapability Kernel
+               OpCapability Addresses
+               OpCapability Linkage
+               OpMemoryModel Logical OpenCL
+               OpTypeForwardPointer %Aptr UniformConstant
+       %uint = OpTypeInt 32 0
+          %C = OpTypeStruct %Aptr %uint %Aptr
+          %B = OpTypeStruct %C %Aptr
+          %A = OpTypeStruct %B %C %B
+  %Aptr = OpTypePointer UniformConstant %A
+)";
+  constexpr char kDiff[] = R"( ; SPIR-V
+ ; Version: 1.6
+ ; Generator: Khronos SPIR-V Tools Assembler; 0
+-; Bound: 6
++; Bound: 8
+ ; Schema: 0
+ OpCapability Kernel
+ OpCapability Addresses
+ OpCapability Linkage
+ OpMemoryModel Logical OpenCL
+ OpTypeForwardPointer %1 UniformConstant
+ %2 = OpTypeInt 32 0
+ %3 = OpTypeStruct %1 %2 %1
+-%4 = OpTypeStruct %3 %1 %2
+-%5 = OpTypeStruct %4 %3 %4
++%6 = OpTypeStruct %3 %1
++%7 = OpTypeStruct %6 %3 %6
+-%1 = OpTypePointer UniformConstant %5
++%1 = OpTypePointer UniformConstant %7
+)";
+  Options options;
+  DoStringDiffTest(kSrcNoDebug, kDstNoDebug, kDiff, options);
+}
+
+}  // namespace
+}  // namespace diff
+}  // namespace spvtools

+ 11 - 0
ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/OpTypeForwardPointer_nested_dst.spvasm

@@ -0,0 +1,11 @@
+               OpCapability Kernel
+               OpCapability Addresses
+               OpCapability Linkage
+               OpMemoryModel Logical OpenCL
+               OpName %Aptr "Aptr"
+               OpTypeForwardPointer %Aptr UniformConstant
+       %uint = OpTypeInt 32 0
+          %C = OpTypeStruct %Aptr %uint %Aptr
+          %B = OpTypeStruct %C %Aptr
+          %A = OpTypeStruct %B %C %B
+  %Aptr = OpTypePointer UniformConstant %A

+ 13 - 0
ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/OpTypeForwardPointer_nested_src.spvasm

@@ -0,0 +1,13 @@
+;; Tests that two forwarded declarations match even if the type pointer is used
+;; in a nested struct declaration, and in multiple places
+               OpCapability Kernel
+               OpCapability Addresses
+               OpCapability Linkage
+               OpMemoryModel Logical OpenCL
+               OpName %Aptr "Aptr"
+               OpTypeForwardPointer %Aptr UniformConstant
+       %uint = OpTypeInt 32 0
+          %C = OpTypeStruct %Aptr %uint %Aptr
+          %B = OpTypeStruct %C %Aptr %uint
+          %A = OpTypeStruct %B %C %B
+  %Aptr = OpTypePointer UniformConstant %A

+ 124 - 0
ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/OpTypeForwardPointer_onesided_debug_autogen.cpp

@@ -0,0 +1,124 @@
+// GENERATED FILE - DO NOT EDIT.
+// Generated by generate_tests.py
+//
+// 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 "../diff_test_utils.h"
+
+#include "gtest/gtest.h"
+
+namespace spvtools {
+namespace diff {
+namespace {
+
+// Test that OpTypeForwardPointer is matched when one SPIR-V doesn't have debug
+// info
+constexpr char kSrc[] = R"(               OpCapability Kernel
+               OpCapability Addresses
+               OpCapability Linkage
+               OpMemoryModel Logical OpenCL
+               OpName %structptr "structptr"
+               OpTypeForwardPointer %structptr UniformConstant
+       %uint = OpTypeInt 32 0
+   %structt1 = OpTypeStruct %structptr %uint
+   %structt2 = OpTypeStruct %uint %structptr
+   %structt3 = OpTypeStruct %uint %uint %structptr
+   %structt4 = OpTypeStruct %uint %uint %uint %structptr
+  %structptr = OpTypePointer UniformConstant %structt1)";
+constexpr char kDst[] = R"(               OpCapability Kernel
+               OpCapability Addresses
+               OpCapability Linkage
+               OpMemoryModel Logical OpenCL
+               OpTypeForwardPointer %structptr UniformConstant
+       %uint = OpTypeInt 32 0
+   %structt1 = OpTypeStruct %structptr %uint
+   %structt2 = OpTypeStruct %uint %structptr
+   %structt3 = OpTypeStruct %uint %uint %structptr
+   %structt4 = OpTypeStruct %uint %uint %uint %structptr
+  %structptr = OpTypePointer UniformConstant %structt1
+)";
+
+TEST(DiffTest, OptypeforwardpointerOnesidedDebug) {
+  constexpr char kDiff[] = R"( ; SPIR-V
+ ; Version: 1.6
+ ; Generator: Khronos SPIR-V Tools Assembler; 0
+ ; Bound: 7
+ ; Schema: 0
+ OpCapability Kernel
+ OpCapability Addresses
+ OpCapability Linkage
+ OpMemoryModel Logical OpenCL
+-OpName %1 "structptr"
+ OpTypeForwardPointer %1 UniformConstant
+ %2 = OpTypeInt 32 0
+ %3 = OpTypeStruct %1 %2
+ %4 = OpTypeStruct %2 %1
+ %5 = OpTypeStruct %2 %2 %1
+ %6 = OpTypeStruct %2 %2 %2 %1
+ %1 = OpTypePointer UniformConstant %3
+)";
+  Options options;
+  DoStringDiffTest(kSrc, kDst, kDiff, options);
+}
+
+TEST(DiffTest, OptypeforwardpointerOnesidedDebugNoDebug) {
+  constexpr char kSrcNoDebug[] = R"(               OpCapability Kernel
+               OpCapability Addresses
+               OpCapability Linkage
+               OpMemoryModel Logical OpenCL
+               OpTypeForwardPointer %structptr UniformConstant
+       %uint = OpTypeInt 32 0
+   %structt1 = OpTypeStruct %structptr %uint
+   %structt2 = OpTypeStruct %uint %structptr
+   %structt3 = OpTypeStruct %uint %uint %structptr
+   %structt4 = OpTypeStruct %uint %uint %uint %structptr
+  %structptr = OpTypePointer UniformConstant %structt1
+)";
+  constexpr char kDstNoDebug[] = R"(               OpCapability Kernel
+               OpCapability Addresses
+               OpCapability Linkage
+               OpMemoryModel Logical OpenCL
+               OpTypeForwardPointer %structptr UniformConstant
+       %uint = OpTypeInt 32 0
+   %structt1 = OpTypeStruct %structptr %uint
+   %structt2 = OpTypeStruct %uint %structptr
+   %structt3 = OpTypeStruct %uint %uint %structptr
+   %structt4 = OpTypeStruct %uint %uint %uint %structptr
+  %structptr = OpTypePointer UniformConstant %structt1
+)";
+  constexpr char kDiff[] = R"( ; SPIR-V
+ ; Version: 1.6
+ ; Generator: Khronos SPIR-V Tools Assembler; 0
+ ; Bound: 7
+ ; Schema: 0
+ OpCapability Kernel
+ OpCapability Addresses
+ OpCapability Linkage
+ OpMemoryModel Logical OpenCL
+ OpTypeForwardPointer %1 UniformConstant
+ %2 = OpTypeInt 32 0
+ %3 = OpTypeStruct %1 %2
+ %4 = OpTypeStruct %2 %1
+ %5 = OpTypeStruct %2 %2 %1
+ %6 = OpTypeStruct %2 %2 %2 %1
+ %1 = OpTypePointer UniformConstant %3
+)";
+  Options options;
+  DoStringDiffTest(kSrcNoDebug, kDstNoDebug, kDiff, options);
+}
+
+}  // namespace
+}  // namespace diff
+}  // namespace spvtools

+ 11 - 0
ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/OpTypeForwardPointer_onesided_debug_dst.spvasm

@@ -0,0 +1,11 @@
+               OpCapability Kernel
+               OpCapability Addresses
+               OpCapability Linkage
+               OpMemoryModel Logical OpenCL
+               OpTypeForwardPointer %structptr UniformConstant
+       %uint = OpTypeInt 32 0
+   %structt1 = OpTypeStruct %structptr %uint
+   %structt2 = OpTypeStruct %uint %structptr
+   %structt3 = OpTypeStruct %uint %uint %structptr
+   %structt4 = OpTypeStruct %uint %uint %uint %structptr
+  %structptr = OpTypePointer UniformConstant %structt1

+ 14 - 0
ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/OpTypeForwardPointer_onesided_debug_src.spvasm

@@ -0,0 +1,14 @@
+;; Test that OpTypeForwardPointer is matched when one SPIR-V doesn't have debug
+;; info
+               OpCapability Kernel
+               OpCapability Addresses
+               OpCapability Linkage
+               OpMemoryModel Logical OpenCL
+               OpName %structptr "structptr"
+               OpTypeForwardPointer %structptr UniformConstant
+       %uint = OpTypeInt 32 0
+   %structt1 = OpTypeStruct %structptr %uint
+   %structt2 = OpTypeStruct %uint %structptr
+   %structt3 = OpTypeStruct %uint %uint %structptr
+   %structt4 = OpTypeStruct %uint %uint %uint %structptr
+  %structptr = OpTypePointer UniformConstant %structt1

+ 17 - 0
ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/README.md

@@ -0,0 +1,17 @@
+# Diff tests
+
+This directory contains files used to ensure correctness of the `spirv-diff` implementation.  The
+`generate_tests.py` script takes `name_src.spvasm` and `name_dst.spvasm` (for each `name`) and
+produces unit test files in the form of `name_autogen.cpp`.
+
+The unit test files test the diff between the src and dst inputs, as well as between debug-stripped
+versions of those.  Additionally, based on the `{variant}_TESTS` lists defined in
+`generate_tests.py`, extra unit tests are added to exercise different options of spirv-diff.
+
+New tests are added simply by placing a new `name_src.spvasm` and `name_dst.spvasm` pair in this
+directory and running `generate_tests.py`.  Note that this script needs the path to the spirv-diff
+executable that is built.
+
+The `generate_tests.py` script additionally expects `name_src.spvasm` to include a heading where the
+purpose of the test is explained.  This heading is parsed as a block of lines starting with `;;` at
+the top of the file.

+ 407 - 0
ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/basic_autogen.cpp

@@ -0,0 +1,407 @@
+// GENERATED FILE - DO NOT EDIT.
+// Generated by generate_tests.py
+//
+// 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 "../diff_test_utils.h"
+
+#include "gtest/gtest.h"
+
+namespace spvtools {
+namespace diff {
+namespace {
+
+// Basic test for spirv-diff
+constexpr char kSrc[] = R"(; SPIR-V
+; Version: 1.0
+; Generator: Google ANGLE Shader Compiler; 0
+; Bound: 27
+; Schema: 0
+OpCapability Shader
+  OpMemoryModel Logical GLSL450
+  OpEntryPoint Vertex %22 "main" %4 %14 %19
+  OpSource GLSL 450
+  OpName %4 "_ua_position"
+  OpName %14 "ANGLEXfbPosition"
+  OpName %17 "gl_PerVertex"
+  OpMemberName %17 0 "gl_Position"
+OpMemberName %17 1 "gl_PointSize"
+OpMemberName %17 2 "gl_ClipDistance"
+  OpMemberName %17 3 "gl_CullDistance"
+  OpName %19 ""
+  OpName %22 "main"
+  OpDecorate %4 Location 0
+  OpDecorate %14 Location 0
+  OpMemberDecorate %17 1 RelaxedPrecision
+  OpMemberDecorate %17 0 BuiltIn Position
+  OpMemberDecorate %17 1 BuiltIn PointSize
+OpMemberDecorate %17 2 BuiltIn ClipDistance
+OpMemberDecorate %17 3 BuiltIn CullDistance
+OpDecorate %17 Block
+%1 = OpTypeFloat 32
+%2 = OpTypeVector %1 4
+%5 = OpTypeInt 32 0
+%6 = OpTypeInt 32 1
+%15 = OpConstant %5 8
+%16 = OpTypeArray %1 %15
+%17 = OpTypeStruct %2 %1 %16 %16
+%20 = OpTypeVoid
+%25 = OpConstant %6 0
+%3 = OpTypePointer Input %2
+%13 = OpTypePointer Output %2
+%18 = OpTypePointer Output %17
+%21 = OpTypeFunction %20
+%4 = OpVariable %3 Input
+%14 = OpVariable %13 Output
+%19 = OpVariable %18 Output
+%22 = OpFunction %20 None %21
+%23 = OpLabel
+%24 = OpLoad %2 %4
+%26 = OpAccessChain %13 %19 %25
+OpStore %26 %24
+OpReturn
+OpFunctionEnd)";
+constexpr char kDst[] = R"(; SPIR-V
+; Version: 1.0
+; Generator: Khronos Glslang Reference Front End; 10
+; Bound: 28
+; Schema: 0
+OpCapability Shader
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint Vertex %4 "main" %13 %17 %27
+OpSource GLSL 450
+OpName %4 "main"
+OpName %11 "gl_PerVertex"
+OpMemberName %11 0 "gl_Position"
+OpMemberName %11 1 "gl_PointSize"
+OpMemberName %11 2 "gl_ClipDistance"
+OpMemberName %11 3 "gl_CullDistance"
+OpName %13 ""
+OpName %17 "_ua_position"
+OpName %27 "ANGLEXfbPosition"
+OpMemberDecorate %11 0 BuiltIn Position
+OpMemberDecorate %11 1 BuiltIn PointSize
+OpMemberDecorate %11 2 BuiltIn ClipDistance
+OpMemberDecorate %11 3 BuiltIn CullDistance
+OpDecorate %11 Block
+OpDecorate %17 Location 0
+OpDecorate %27 Location 0
+%2 = OpTypeVoid
+%3 = OpTypeFunction %2
+%6 = OpTypeFloat 32
+%7 = OpTypeVector %6 4
+%8 = OpTypeInt 32 0
+%9 = OpConstant %8 1
+%10 = OpTypeArray %6 %9
+%11 = OpTypeStruct %7 %6 %10 %10
+%12 = OpTypePointer Output %11
+%13 = OpVariable %12 Output
+%14 = OpTypeInt 32 1
+%15 = OpConstant %14 0
+%16 = OpTypePointer Input %7
+%17 = OpVariable %16 Input
+%19 = OpTypePointer Output %7
+%27 = OpVariable %19 Output
+%4 = OpFunction %2 None %3
+%5 = OpLabel
+%18 = OpLoad %7 %17
+%20 = OpAccessChain %19 %13 %15
+OpStore %20 %18
+OpReturn
+OpFunctionEnd
+)";
+
+TEST(DiffTest, Basic) {
+  constexpr char kDiff[] = R"( ; SPIR-V
+ ; Version: 1.6
+ ; Generator: Khronos SPIR-V Tools Assembler; 0
+-; Bound: 27
++; Bound: 36
+ ; Schema: 0
+ OpCapability Shader
++%27 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+-OpEntryPoint Vertex %22 "main" %4 %14 %19
++OpEntryPoint Vertex %22 "main" %19 %4 %14
+ OpSource GLSL 450
+ OpName %4 "_ua_position"
+ OpName %14 "ANGLEXfbPosition"
+ OpName %17 "gl_PerVertex"
+ OpMemberName %17 0 "gl_Position"
+ OpMemberName %17 1 "gl_PointSize"
+ OpMemberName %17 2 "gl_ClipDistance"
+ OpMemberName %17 3 "gl_CullDistance"
+ OpName %19 ""
+ OpName %22 "main"
+ OpDecorate %4 Location 0
+ OpDecorate %14 Location 0
+-OpMemberDecorate %17 1 RelaxedPrecision
+ OpMemberDecorate %17 0 BuiltIn Position
+ OpMemberDecorate %17 1 BuiltIn PointSize
+ OpMemberDecorate %17 2 BuiltIn ClipDistance
+ OpMemberDecorate %17 3 BuiltIn CullDistance
+ OpDecorate %17 Block
+ %1 = OpTypeFloat 32
+ %2 = OpTypeVector %1 4
+ %5 = OpTypeInt 32 0
+ %6 = OpTypeInt 32 1
+-%15 = OpConstant %5 8
+-%16 = OpTypeArray %1 %15
+-%17 = OpTypeStruct %2 %1 %16 %16
++%17 = OpTypeStruct %2 %1 %29 %29
++%28 = OpConstant %5 1
++%29 = OpTypeArray %1 %28
+ %20 = OpTypeVoid
+ %25 = OpConstant %6 0
+ %3 = OpTypePointer Input %2
+ %13 = OpTypePointer Output %2
+ %18 = OpTypePointer Output %17
+ %21 = OpTypeFunction %20
+ %4 = OpVariable %3 Input
+ %14 = OpVariable %13 Output
+ %19 = OpVariable %18 Output
+ %22 = OpFunction %20 None %21
+ %23 = OpLabel
+ %24 = OpLoad %2 %4
+ %26 = OpAccessChain %13 %19 %25
+ OpStore %26 %24
+ OpReturn
+ OpFunctionEnd
+)";
+  Options options;
+  DoStringDiffTest(kSrc, kDst, kDiff, options);
+}
+
+TEST(DiffTest, BasicNoDebug) {
+  constexpr char kSrcNoDebug[] = R"(; SPIR-V
+; Version: 1.0
+; Generator: Google ANGLE Shader Compiler; 0
+; Bound: 27
+; Schema: 0
+OpCapability Shader
+  OpMemoryModel Logical GLSL450
+  OpEntryPoint Vertex %22 "main" %4 %14 %19
+  OpSource GLSL 450
+  OpDecorate %4 Location 0
+  OpDecorate %14 Location 0
+  OpMemberDecorate %17 1 RelaxedPrecision
+  OpMemberDecorate %17 0 BuiltIn Position
+  OpMemberDecorate %17 1 BuiltIn PointSize
+OpMemberDecorate %17 2 BuiltIn ClipDistance
+OpMemberDecorate %17 3 BuiltIn CullDistance
+OpDecorate %17 Block
+%1 = OpTypeFloat 32
+%2 = OpTypeVector %1 4
+%5 = OpTypeInt 32 0
+%6 = OpTypeInt 32 1
+%15 = OpConstant %5 8
+%16 = OpTypeArray %1 %15
+%17 = OpTypeStruct %2 %1 %16 %16
+%20 = OpTypeVoid
+%25 = OpConstant %6 0
+%3 = OpTypePointer Input %2
+%13 = OpTypePointer Output %2
+%18 = OpTypePointer Output %17
+%21 = OpTypeFunction %20
+%4 = OpVariable %3 Input
+%14 = OpVariable %13 Output
+%19 = OpVariable %18 Output
+%22 = OpFunction %20 None %21
+%23 = OpLabel
+%24 = OpLoad %2 %4
+%26 = OpAccessChain %13 %19 %25
+OpStore %26 %24
+OpReturn
+OpFunctionEnd
+)";
+  constexpr char kDstNoDebug[] = R"(; SPIR-V
+; Version: 1.0
+; Generator: Khronos Glslang Reference Front End; 10
+; Bound: 28
+; Schema: 0
+OpCapability Shader
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint Vertex %4 "main" %13 %17 %27
+OpSource GLSL 450
+OpMemberDecorate %11 0 BuiltIn Position
+OpMemberDecorate %11 1 BuiltIn PointSize
+OpMemberDecorate %11 2 BuiltIn ClipDistance
+OpMemberDecorate %11 3 BuiltIn CullDistance
+OpDecorate %11 Block
+OpDecorate %17 Location 0
+OpDecorate %27 Location 0
+%2 = OpTypeVoid
+%3 = OpTypeFunction %2
+%6 = OpTypeFloat 32
+%7 = OpTypeVector %6 4
+%8 = OpTypeInt 32 0
+%9 = OpConstant %8 1
+%10 = OpTypeArray %6 %9
+%11 = OpTypeStruct %7 %6 %10 %10
+%12 = OpTypePointer Output %11
+%13 = OpVariable %12 Output
+%14 = OpTypeInt 32 1
+%15 = OpConstant %14 0
+%16 = OpTypePointer Input %7
+%17 = OpVariable %16 Input
+%19 = OpTypePointer Output %7
+%27 = OpVariable %19 Output
+%4 = OpFunction %2 None %3
+%5 = OpLabel
+%18 = OpLoad %7 %17
+%20 = OpAccessChain %19 %13 %15
+OpStore %20 %18
+OpReturn
+OpFunctionEnd
+)";
+  constexpr char kDiff[] = R"( ; SPIR-V
+ ; Version: 1.6
+ ; Generator: Khronos SPIR-V Tools Assembler; 0
+-; Bound: 27
++; Bound: 36
+ ; Schema: 0
+ OpCapability Shader
++%27 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+-OpEntryPoint Vertex %22 "main" %4 %14 %19
++OpEntryPoint Vertex %22 "main" %19 %4 %14
+ OpSource GLSL 450
+ OpDecorate %4 Location 0
+ OpDecorate %14 Location 0
+-OpMemberDecorate %17 1 RelaxedPrecision
+ OpMemberDecorate %17 0 BuiltIn Position
+ OpMemberDecorate %17 1 BuiltIn PointSize
+ OpMemberDecorate %17 2 BuiltIn ClipDistance
+ OpMemberDecorate %17 3 BuiltIn CullDistance
+ OpDecorate %17 Block
+ %1 = OpTypeFloat 32
+ %2 = OpTypeVector %1 4
+ %5 = OpTypeInt 32 0
+ %6 = OpTypeInt 32 1
+-%15 = OpConstant %5 8
+-%16 = OpTypeArray %1 %15
+-%17 = OpTypeStruct %2 %1 %16 %16
++%17 = OpTypeStruct %2 %1 %29 %29
++%28 = OpConstant %5 1
++%29 = OpTypeArray %1 %28
+ %20 = OpTypeVoid
+ %25 = OpConstant %6 0
+ %3 = OpTypePointer Input %2
+ %13 = OpTypePointer Output %2
+ %18 = OpTypePointer Output %17
+ %21 = OpTypeFunction %20
+ %4 = OpVariable %3 Input
+ %14 = OpVariable %13 Output
+ %19 = OpVariable %18 Output
+ %22 = OpFunction %20 None %21
+ %23 = OpLabel
+ %24 = OpLoad %2 %4
+ %26 = OpAccessChain %13 %19 %25
+ OpStore %26 %24
+ OpReturn
+ OpFunctionEnd
+)";
+  Options options;
+  DoStringDiffTest(kSrcNoDebug, kDstNoDebug, kDiff, options);
+}
+
+TEST(DiffTest, BasicDumpIds) {
+  constexpr char kDiff[] = R"( ; SPIR-V
+ ; Version: 1.6
+ ; Generator: Khronos SPIR-V Tools Assembler; 0
+-; Bound: 27
++; Bound: 36
+ ; Schema: 0
+ OpCapability Shader
++%27 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+-OpEntryPoint Vertex %22 "main" %4 %14 %19
++OpEntryPoint Vertex %22 "main" %19 %4 %14
+ OpSource GLSL 450
+ OpName %4 "_ua_position"
+ OpName %14 "ANGLEXfbPosition"
+ OpName %17 "gl_PerVertex"
+ OpMemberName %17 0 "gl_Position"
+ OpMemberName %17 1 "gl_PointSize"
+ OpMemberName %17 2 "gl_ClipDistance"
+ OpMemberName %17 3 "gl_CullDistance"
+ OpName %19 ""
+ OpName %22 "main"
+ OpDecorate %4 Location 0
+ OpDecorate %14 Location 0
+-OpMemberDecorate %17 1 RelaxedPrecision
+ OpMemberDecorate %17 0 BuiltIn Position
+ OpMemberDecorate %17 1 BuiltIn PointSize
+ OpMemberDecorate %17 2 BuiltIn ClipDistance
+ OpMemberDecorate %17 3 BuiltIn CullDistance
+ OpDecorate %17 Block
+ %1 = OpTypeFloat 32
+ %2 = OpTypeVector %1 4
+ %5 = OpTypeInt 32 0
+ %6 = OpTypeInt 32 1
+-%15 = OpConstant %5 8
+-%16 = OpTypeArray %1 %15
+-%17 = OpTypeStruct %2 %1 %16 %16
++%17 = OpTypeStruct %2 %1 %29 %29
++%28 = OpConstant %5 1
++%29 = OpTypeArray %1 %28
+ %20 = OpTypeVoid
+ %25 = OpConstant %6 0
+ %3 = OpTypePointer Input %2
+ %13 = OpTypePointer Output %2
+ %18 = OpTypePointer Output %17
+ %21 = OpTypeFunction %20
+ %4 = OpVariable %3 Input
+ %14 = OpVariable %13 Output
+ %19 = OpVariable %18 Output
+ %22 = OpFunction %20 None %21
+ %23 = OpLabel
+ %24 = OpLoad %2 %4
+ %26 = OpAccessChain %13 %19 %25
+ OpStore %26 %24
+ OpReturn
+ OpFunctionEnd
+ Src ->  Dst
+   1 ->    6 [TypeFloat]
+   2 ->    7 [TypeVector]
+   3 ->   16 [TypePointer]
+   4 ->   17 [Variable]
+   5 ->    8 [TypeInt]
+   6 ->   14 [TypeInt]
+  13 ->   19 [TypePointer]
+  14 ->   27 [Variable]
+  15 ->   34 [Constant]
+  16 ->   35 [TypeArray]
+  17 ->   11 [TypeStruct]
+  18 ->   12 [TypePointer]
+  19 ->   13 [Variable]
+  20 ->    2 [TypeVoid]
+  21 ->    3 [TypeFunction]
+  22 ->    4 [Function]
+  23 ->    5 [Label]
+  24 ->   18 [Load]
+  25 ->   15 [Constant]
+  26 ->   20 [AccessChain]
+)";
+  Options options;
+  options.dump_id_map = true;
+  DoStringDiffTest(kSrc, kDst, kDiff, options);
+}
+
+}  // namespace
+}  // namespace diff
+}  // namespace spvtools

+ 49 - 0
ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/basic_dst.spvasm

@@ -0,0 +1,49 @@
+; SPIR-V
+; Version: 1.0
+; Generator: Khronos Glslang Reference Front End; 10
+; Bound: 28
+; Schema: 0
+OpCapability Shader
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint Vertex %4 "main" %13 %17 %27
+OpSource GLSL 450
+OpName %4 "main"
+OpName %11 "gl_PerVertex"
+OpMemberName %11 0 "gl_Position"
+OpMemberName %11 1 "gl_PointSize"
+OpMemberName %11 2 "gl_ClipDistance"
+OpMemberName %11 3 "gl_CullDistance"
+OpName %13 ""
+OpName %17 "_ua_position"
+OpName %27 "ANGLEXfbPosition"
+OpMemberDecorate %11 0 BuiltIn Position
+OpMemberDecorate %11 1 BuiltIn PointSize
+OpMemberDecorate %11 2 BuiltIn ClipDistance
+OpMemberDecorate %11 3 BuiltIn CullDistance
+OpDecorate %11 Block
+OpDecorate %17 Location 0
+OpDecorate %27 Location 0
+%2 = OpTypeVoid
+%3 = OpTypeFunction %2
+%6 = OpTypeFloat 32
+%7 = OpTypeVector %6 4
+%8 = OpTypeInt 32 0
+%9 = OpConstant %8 1
+%10 = OpTypeArray %6 %9
+%11 = OpTypeStruct %7 %6 %10 %10
+%12 = OpTypePointer Output %11
+%13 = OpVariable %12 Output
+%14 = OpTypeInt 32 1
+%15 = OpConstant %14 0
+%16 = OpTypePointer Input %7
+%17 = OpVariable %16 Input
+%19 = OpTypePointer Output %7
+%27 = OpVariable %19 Output
+%4 = OpFunction %2 None %3
+%5 = OpLabel
+%18 = OpLoad %7 %17
+%20 = OpAccessChain %19 %13 %15
+OpStore %20 %18
+OpReturn
+OpFunctionEnd

+ 50 - 0
ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/basic_src.spvasm

@@ -0,0 +1,50 @@
+;; Basic test for spirv-diff
+; SPIR-V
+; Version: 1.0
+; Generator: Google ANGLE Shader Compiler; 0
+; Bound: 27
+; Schema: 0
+OpCapability Shader
+  OpMemoryModel Logical GLSL450
+  OpEntryPoint Vertex %22 "main" %4 %14 %19
+  OpSource GLSL 450
+  OpName %4 "_ua_position"
+  OpName %14 "ANGLEXfbPosition"
+  OpName %17 "gl_PerVertex"
+  OpMemberName %17 0 "gl_Position"
+OpMemberName %17 1 "gl_PointSize"
+OpMemberName %17 2 "gl_ClipDistance"
+  OpMemberName %17 3 "gl_CullDistance"
+  OpName %19 ""
+  OpName %22 "main"
+  OpDecorate %4 Location 0
+  OpDecorate %14 Location 0
+  OpMemberDecorate %17 1 RelaxedPrecision
+  OpMemberDecorate %17 0 BuiltIn Position
+  OpMemberDecorate %17 1 BuiltIn PointSize
+OpMemberDecorate %17 2 BuiltIn ClipDistance
+OpMemberDecorate %17 3 BuiltIn CullDistance
+OpDecorate %17 Block
+%1 = OpTypeFloat 32
+%2 = OpTypeVector %1 4
+%5 = OpTypeInt 32 0
+%6 = OpTypeInt 32 1
+%15 = OpConstant %5 8
+%16 = OpTypeArray %1 %15
+%17 = OpTypeStruct %2 %1 %16 %16
+%20 = OpTypeVoid
+%25 = OpConstant %6 0
+%3 = OpTypePointer Input %2
+%13 = OpTypePointer Output %2
+%18 = OpTypePointer Output %17
+%21 = OpTypeFunction %20
+%4 = OpVariable %3 Input
+%14 = OpVariable %13 Output
+%19 = OpVariable %18 Output
+%22 = OpFunction %20 None %21
+%23 = OpLabel
+%24 = OpLoad %2 %4
+%26 = OpAccessChain %13 %19 %25
+OpStore %26 %24
+OpReturn
+OpFunctionEnd

+ 306 - 0
ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/constant_array_size_autogen.cpp

@@ -0,0 +1,306 @@
+// GENERATED FILE - DO NOT EDIT.
+// Generated by generate_tests.py
+//
+// 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 "../diff_test_utils.h"
+
+#include "gtest/gtest.h"
+
+namespace spvtools {
+namespace diff {
+namespace {
+
+// Tests that identical integer constants are matched when used as array size,
+// regardless of int or uint.
+constexpr char kSrc[] = R"(; SPIR-V
+; Version: 1.0
+; Generator: Google ANGLE Shader Compiler; 0
+; Bound: 27
+; Schema: 0
+OpCapability Shader
+OpMemoryModel Logical GLSL450
+OpEntryPoint Vertex %22 "main" %4 %19
+OpSource GLSL 450
+OpName %4 "_ua_position"
+OpName %17 "gl_PerVertex"
+OpMemberName %17 0 "gl_Position"
+OpMemberName %17 1 "gl_PointSize"
+OpMemberName %17 2 "gl_ClipDistance"
+OpMemberName %17 3 "gl_CullDistance"
+OpName %19 ""
+OpName %22 "main"
+OpDecorate %4 Location 0
+OpMemberDecorate %17 1 RelaxedPrecision
+OpMemberDecorate %17 0 BuiltIn Position
+OpMemberDecorate %17 1 BuiltIn PointSize
+OpMemberDecorate %17 2 BuiltIn ClipDistance
+OpMemberDecorate %17 3 BuiltIn CullDistance
+OpDecorate %17 Block
+%1 = OpTypeFloat 32
+%2 = OpTypeVector %1 4
+%5 = OpTypeInt 32 0
+%8 = OpTypeVector %5 4
+%15 = OpConstant %5 8
+%16 = OpTypeArray %1 %15
+%17 = OpTypeStruct %2 %1 %16 %16
+%20 = OpTypeVoid
+%25 = OpConstant %5 0
+%3 = OpTypePointer Input %2
+%13 = OpTypePointer Output %2
+%18 = OpTypePointer Output %17
+%21 = OpTypeFunction %20
+%4 = OpVariable %3 Input
+%19 = OpVariable %18 Output
+%22 = OpFunction %20 None %21
+%23 = OpLabel
+%24 = OpLoad %2 %4
+%26 = OpAccessChain %13 %19 %25
+OpStore %26 %24
+OpReturn
+OpFunctionEnd)";
+constexpr char kDst[] = R"(; SPIR-V
+; Version: 1.0
+; Generator: Google ANGLE Shader Compiler; 0
+; Bound: 27
+; Schema: 0
+OpCapability Shader
+OpMemoryModel Logical GLSL450
+OpEntryPoint Vertex %22 "main" %4 %19
+OpSource GLSL 450
+OpName %4 "_ua_position"
+OpName %17 "gl_PerVertex"
+OpMemberName %17 0 "gl_Position"
+OpMemberName %17 1 "gl_PointSize"
+OpMemberName %17 2 "gl_ClipDistance"
+OpMemberName %17 3 "gl_CullDistance"
+OpName %19 ""
+OpName %22 "main"
+OpDecorate %4 Location 0
+OpMemberDecorate %17 1 RelaxedPrecision
+OpMemberDecorate %17 0 BuiltIn Position
+OpMemberDecorate %17 1 BuiltIn PointSize
+OpMemberDecorate %17 2 BuiltIn ClipDistance
+OpMemberDecorate %17 3 BuiltIn CullDistance
+OpDecorate %17 Block
+%1 = OpTypeFloat 32
+%2 = OpTypeVector %1 4
+%5 = OpTypeInt 32 0
+%6 = OpTypeInt 32 1
+%8 = OpTypeVector %5 4
+%15 = OpConstant %6 8
+%16 = OpTypeArray %1 %15
+%17 = OpTypeStruct %2 %1 %16 %16
+%20 = OpTypeVoid
+%25 = OpConstant %5 0
+%3 = OpTypePointer Input %2
+%13 = OpTypePointer Output %2
+%18 = OpTypePointer Output %17
+%21 = OpTypeFunction %20
+%4 = OpVariable %3 Input
+%19 = OpVariable %18 Output
+%22 = OpFunction %20 None %21
+%23 = OpLabel
+%24 = OpLoad %2 %4
+%26 = OpAccessChain %13 %19 %25
+OpStore %26 %24
+OpReturn
+OpFunctionEnd
+)";
+
+TEST(DiffTest, ConstantArraySize) {
+  constexpr char kDiff[] = R"( ; SPIR-V
+ ; Version: 1.6
+ ; Generator: Khronos SPIR-V Tools Assembler; 0
+-; Bound: 27
++; Bound: 34
+ ; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Vertex %22 "main" %4 %19
+ OpSource GLSL 450
+ OpName %4 "_ua_position"
+ OpName %17 "gl_PerVertex"
+ OpMemberName %17 0 "gl_Position"
+ OpMemberName %17 1 "gl_PointSize"
+ OpMemberName %17 2 "gl_ClipDistance"
+ OpMemberName %17 3 "gl_CullDistance"
+ OpName %19 ""
+ OpName %22 "main"
+ OpDecorate %4 Location 0
+ OpMemberDecorate %17 1 RelaxedPrecision
+ OpMemberDecorate %17 0 BuiltIn Position
+ OpMemberDecorate %17 1 BuiltIn PointSize
+ OpMemberDecorate %17 2 BuiltIn ClipDistance
+ OpMemberDecorate %17 3 BuiltIn CullDistance
+ OpDecorate %17 Block
+ %1 = OpTypeFloat 32
+ %2 = OpTypeVector %1 4
+ %5 = OpTypeInt 32 0
++%27 = OpTypeInt 32 1
+ %8 = OpTypeVector %5 4
+-%15 = OpConstant %5 8
++%15 = OpConstant %27 8
+ %16 = OpTypeArray %1 %15
+ %17 = OpTypeStruct %2 %1 %16 %16
+ %20 = OpTypeVoid
+ %25 = OpConstant %5 0
+ %3 = OpTypePointer Input %2
+ %13 = OpTypePointer Output %2
+ %18 = OpTypePointer Output %17
+ %21 = OpTypeFunction %20
+ %4 = OpVariable %3 Input
+ %19 = OpVariable %18 Output
+ %22 = OpFunction %20 None %21
+ %23 = OpLabel
+ %24 = OpLoad %2 %4
+ %26 = OpAccessChain %13 %19 %25
+ OpStore %26 %24
+ OpReturn
+ OpFunctionEnd
+)";
+  Options options;
+  DoStringDiffTest(kSrc, kDst, kDiff, options);
+}
+
+TEST(DiffTest, ConstantArraySizeNoDebug) {
+  constexpr char kSrcNoDebug[] = R"(; SPIR-V
+; Version: 1.0
+; Generator: Google ANGLE Shader Compiler; 0
+; Bound: 27
+; Schema: 0
+OpCapability Shader
+OpMemoryModel Logical GLSL450
+OpEntryPoint Vertex %22 "main" %4 %19
+OpSource GLSL 450
+OpDecorate %4 Location 0
+OpMemberDecorate %17 1 RelaxedPrecision
+OpMemberDecorate %17 0 BuiltIn Position
+OpMemberDecorate %17 1 BuiltIn PointSize
+OpMemberDecorate %17 2 BuiltIn ClipDistance
+OpMemberDecorate %17 3 BuiltIn CullDistance
+OpDecorate %17 Block
+%1 = OpTypeFloat 32
+%2 = OpTypeVector %1 4
+%5 = OpTypeInt 32 0
+%8 = OpTypeVector %5 4
+%15 = OpConstant %5 8
+%16 = OpTypeArray %1 %15
+%17 = OpTypeStruct %2 %1 %16 %16
+%20 = OpTypeVoid
+%25 = OpConstant %5 0
+%3 = OpTypePointer Input %2
+%13 = OpTypePointer Output %2
+%18 = OpTypePointer Output %17
+%21 = OpTypeFunction %20
+%4 = OpVariable %3 Input
+%19 = OpVariable %18 Output
+%22 = OpFunction %20 None %21
+%23 = OpLabel
+%24 = OpLoad %2 %4
+%26 = OpAccessChain %13 %19 %25
+OpStore %26 %24
+OpReturn
+OpFunctionEnd
+)";
+  constexpr char kDstNoDebug[] = R"(; SPIR-V
+; Version: 1.0
+; Generator: Google ANGLE Shader Compiler; 0
+; Bound: 27
+; Schema: 0
+OpCapability Shader
+OpMemoryModel Logical GLSL450
+OpEntryPoint Vertex %22 "main" %4 %19
+OpSource GLSL 450
+OpDecorate %4 Location 0
+OpMemberDecorate %17 1 RelaxedPrecision
+OpMemberDecorate %17 0 BuiltIn Position
+OpMemberDecorate %17 1 BuiltIn PointSize
+OpMemberDecorate %17 2 BuiltIn ClipDistance
+OpMemberDecorate %17 3 BuiltIn CullDistance
+OpDecorate %17 Block
+%1 = OpTypeFloat 32
+%2 = OpTypeVector %1 4
+%5 = OpTypeInt 32 0
+%6 = OpTypeInt 32 1
+%8 = OpTypeVector %5 4
+%15 = OpConstant %6 8
+%16 = OpTypeArray %1 %15
+%17 = OpTypeStruct %2 %1 %16 %16
+%20 = OpTypeVoid
+%25 = OpConstant %5 0
+%3 = OpTypePointer Input %2
+%13 = OpTypePointer Output %2
+%18 = OpTypePointer Output %17
+%21 = OpTypeFunction %20
+%4 = OpVariable %3 Input
+%19 = OpVariable %18 Output
+%22 = OpFunction %20 None %21
+%23 = OpLabel
+%24 = OpLoad %2 %4
+%26 = OpAccessChain %13 %19 %25
+OpStore %26 %24
+OpReturn
+OpFunctionEnd
+)";
+  constexpr char kDiff[] = R"( ; SPIR-V
+ ; Version: 1.6
+ ; Generator: Khronos SPIR-V Tools Assembler; 0
+-; Bound: 27
++; Bound: 34
+ ; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Vertex %22 "main" %4 %19
+ OpSource GLSL 450
+ OpDecorate %4 Location 0
+ OpMemberDecorate %17 1 RelaxedPrecision
+ OpMemberDecorate %17 0 BuiltIn Position
+ OpMemberDecorate %17 1 BuiltIn PointSize
+ OpMemberDecorate %17 2 BuiltIn ClipDistance
+ OpMemberDecorate %17 3 BuiltIn CullDistance
+ OpDecorate %17 Block
+ %1 = OpTypeFloat 32
+ %2 = OpTypeVector %1 4
+ %5 = OpTypeInt 32 0
++%27 = OpTypeInt 32 1
+ %8 = OpTypeVector %5 4
+-%15 = OpConstant %5 8
++%15 = OpConstant %27 8
+ %16 = OpTypeArray %1 %15
+ %17 = OpTypeStruct %2 %1 %16 %16
+ %20 = OpTypeVoid
+ %25 = OpConstant %5 0
+ %3 = OpTypePointer Input %2
+ %13 = OpTypePointer Output %2
+ %18 = OpTypePointer Output %17
+ %21 = OpTypeFunction %20
+ %4 = OpVariable %3 Input
+ %19 = OpVariable %18 Output
+ %22 = OpFunction %20 None %21
+ %23 = OpLabel
+ %24 = OpLoad %2 %4
+ %26 = OpAccessChain %13 %19 %25
+ OpStore %26 %24
+ OpReturn
+ OpFunctionEnd
+)";
+  Options options;
+  DoStringDiffTest(kSrcNoDebug, kDstNoDebug, kDiff, options);
+}
+
+}  // namespace
+}  // namespace diff
+}  // namespace spvtools

+ 47 - 0
ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/constant_array_size_dst.spvasm

@@ -0,0 +1,47 @@
+; SPIR-V
+; Version: 1.0
+; Generator: Google ANGLE Shader Compiler; 0
+; Bound: 27
+; Schema: 0
+OpCapability Shader
+OpMemoryModel Logical GLSL450
+OpEntryPoint Vertex %22 "main" %4 %19
+OpSource GLSL 450
+OpName %4 "_ua_position"
+OpName %17 "gl_PerVertex"
+OpMemberName %17 0 "gl_Position"
+OpMemberName %17 1 "gl_PointSize"
+OpMemberName %17 2 "gl_ClipDistance"
+OpMemberName %17 3 "gl_CullDistance"
+OpName %19 ""
+OpName %22 "main"
+OpDecorate %4 Location 0
+OpMemberDecorate %17 1 RelaxedPrecision
+OpMemberDecorate %17 0 BuiltIn Position
+OpMemberDecorate %17 1 BuiltIn PointSize
+OpMemberDecorate %17 2 BuiltIn ClipDistance
+OpMemberDecorate %17 3 BuiltIn CullDistance
+OpDecorate %17 Block
+%1 = OpTypeFloat 32
+%2 = OpTypeVector %1 4
+%5 = OpTypeInt 32 0
+%6 = OpTypeInt 32 1
+%8 = OpTypeVector %5 4
+%15 = OpConstant %6 8
+%16 = OpTypeArray %1 %15
+%17 = OpTypeStruct %2 %1 %16 %16
+%20 = OpTypeVoid
+%25 = OpConstant %5 0
+%3 = OpTypePointer Input %2
+%13 = OpTypePointer Output %2
+%18 = OpTypePointer Output %17
+%21 = OpTypeFunction %20
+%4 = OpVariable %3 Input
+%19 = OpVariable %18 Output
+%22 = OpFunction %20 None %21
+%23 = OpLabel
+%24 = OpLoad %2 %4
+%26 = OpAccessChain %13 %19 %25
+OpStore %26 %24
+OpReturn
+OpFunctionEnd

+ 48 - 0
ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/constant_array_size_src.spvasm

@@ -0,0 +1,48 @@
+;; Tests that identical integer constants are matched when used as array size,
+;; regardless of int or uint.
+; SPIR-V
+; Version: 1.0
+; Generator: Google ANGLE Shader Compiler; 0
+; Bound: 27
+; Schema: 0
+OpCapability Shader
+OpMemoryModel Logical GLSL450
+OpEntryPoint Vertex %22 "main" %4 %19
+OpSource GLSL 450
+OpName %4 "_ua_position"
+OpName %17 "gl_PerVertex"
+OpMemberName %17 0 "gl_Position"
+OpMemberName %17 1 "gl_PointSize"
+OpMemberName %17 2 "gl_ClipDistance"
+OpMemberName %17 3 "gl_CullDistance"
+OpName %19 ""
+OpName %22 "main"
+OpDecorate %4 Location 0
+OpMemberDecorate %17 1 RelaxedPrecision
+OpMemberDecorate %17 0 BuiltIn Position
+OpMemberDecorate %17 1 BuiltIn PointSize
+OpMemberDecorate %17 2 BuiltIn ClipDistance
+OpMemberDecorate %17 3 BuiltIn CullDistance
+OpDecorate %17 Block
+%1 = OpTypeFloat 32
+%2 = OpTypeVector %1 4
+%5 = OpTypeInt 32 0
+%8 = OpTypeVector %5 4
+%15 = OpConstant %5 8
+%16 = OpTypeArray %1 %15
+%17 = OpTypeStruct %2 %1 %16 %16
+%20 = OpTypeVoid
+%25 = OpConstant %5 0
+%3 = OpTypePointer Input %2
+%13 = OpTypePointer Output %2
+%18 = OpTypePointer Output %17
+%21 = OpTypeFunction %20
+%4 = OpVariable %3 Input
+%19 = OpVariable %18 Output
+%22 = OpFunction %20 None %21
+%23 = OpLabel
+%24 = OpLoad %2 %4
+%26 = OpAccessChain %13 %19 %25
+OpStore %26 %24
+OpReturn
+OpFunctionEnd

+ 45 - 0
ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/diff_test_files_autogen.cmake

@@ -0,0 +1,45 @@
+# GENERATED FILE - DO NOT EDIT.
+# Generated by generate_tests.py
+#
+# 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.
+
+list(APPEND DIFF_TEST_FILES
+"diff_files/OpExtInst_in_dst_only_autogen.cpp"
+"diff_files/OpExtInst_in_src_only_autogen.cpp"
+"diff_files/OpTypeForwardPointer_basic_autogen.cpp"
+"diff_files/OpTypeForwardPointer_intertwined_autogen.cpp"
+"diff_files/OpTypeForwardPointer_mismatching_class_autogen.cpp"
+"diff_files/OpTypeForwardPointer_mismatching_type_autogen.cpp"
+"diff_files/OpTypeForwardPointer_nested_autogen.cpp"
+"diff_files/OpTypeForwardPointer_onesided_debug_autogen.cpp"
+"diff_files/basic_autogen.cpp"
+"diff_files/constant_array_size_autogen.cpp"
+"diff_files/different_decorations_fragment_autogen.cpp"
+"diff_files/different_decorations_vertex_autogen.cpp"
+"diff_files/different_function_parameter_count_autogen.cpp"
+"diff_files/extra_if_block_autogen.cpp"
+"diff_files/index_signedness_autogen.cpp"
+"diff_files/int_vs_uint_constants_autogen.cpp"
+"diff_files/large_functions_large_diffs_autogen.cpp"
+"diff_files/large_functions_small_diffs_autogen.cpp"
+"diff_files/multiple_different_entry_points_autogen.cpp"
+"diff_files/multiple_same_entry_points_autogen.cpp"
+"diff_files/reordered_if_blocks_autogen.cpp"
+"diff_files/reordered_switch_blocks_autogen.cpp"
+"diff_files/small_functions_small_diffs_autogen.cpp"
+"diff_files/spec_constant_array_size_autogen.cpp"
+"diff_files/spec_constant_composite_autogen.cpp"
+"diff_files/unrelated_shaders_autogen.cpp"
+)

+ 1626 - 0
ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/different_decorations_fragment_autogen.cpp

@@ -0,0 +1,1626 @@
+// GENERATED FILE - DO NOT EDIT.
+// Generated by generate_tests.py
+//
+// 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 "../diff_test_utils.h"
+
+#include "gtest/gtest.h"
+
+namespace spvtools {
+namespace diff {
+namespace {
+
+// Test where variable set/binding/location decorations are different between
+// src and dst fragment shaders.
+constexpr char kSrc[] = R"(OpCapability Shader
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %63 "main" %4 %22
+OpExecutionMode %63 OriginUpperLeft
+OpSource GLSL 450
+OpName %4 "_ue"
+OpName %8 "_uf"
+OpName %11 "_ug"
+OpName %12 "_uA"
+OpMemberName %12 0 "_ux"
+OpName %14 "_uc"
+OpName %15 "_uB"
+OpMemberName %15 0 "_ux"
+OpName %20 "_ud"
+OpName %22 "_ucol"
+OpName %26 "ANGLEDepthRangeParams"
+OpMemberName %26 0 "near"
+OpMemberName %26 1 "far"
+OpMemberName %26 2 "diff"
+OpMemberName %26 3 "reserved"
+OpName %27 "ANGLEUniformBlock"
+OpMemberName %27 0 "viewport"
+OpMemberName %27 1 "clipDistancesEnabled"
+OpMemberName %27 2 "xfbActiveUnpaused"
+OpMemberName %27 3 "xfbVerticesPerInstance"
+OpMemberName %27 4 "numSamples"
+OpMemberName %27 5 "xfbBufferOffsets"
+OpMemberName %27 6 "acbBufferOffsets"
+OpMemberName %27 7 "depthRange"
+OpName %29 "ANGLEUniforms"
+OpName %33 "_uc"
+OpName %32 "_uh"
+OpName %49 "_ux"
+OpName %50 "_uy"
+OpName %48 "_ui"
+OpName %63 "main"
+OpName %65 "param"
+OpName %68 "param"
+OpName %73 "param"
+OpDecorate %4 Location 0
+OpDecorate %8 RelaxedPrecision
+OpDecorate %8 DescriptorSet 0
+OpDecorate %8 Binding 0
+OpDecorate %11 DescriptorSet 0
+OpDecorate %11 Binding 1
+OpMemberDecorate %12 0 Offset 0
+OpMemberDecorate %12 0 RelaxedPrecision
+OpDecorate %12 Block
+OpDecorate %14 DescriptorSet 0
+OpDecorate %14 Binding 2
+OpMemberDecorate %15 0 Offset 0
+OpMemberDecorate %15 0 RelaxedPrecision
+OpDecorate %15 BufferBlock
+OpDecorate %20 DescriptorSet 0
+OpDecorate %20 Binding 3
+OpDecorate %22 RelaxedPrecision
+OpDecorate %22 Location 0
+OpMemberDecorate %26 0 Offset 0
+OpMemberDecorate %26 1 Offset 4
+OpMemberDecorate %26 2 Offset 8
+OpMemberDecorate %26 3 Offset 12
+OpMemberDecorate %27 0 Offset 0
+OpMemberDecorate %27 1 Offset 16
+OpMemberDecorate %27 2 Offset 20
+OpMemberDecorate %27 3 Offset 24
+OpMemberDecorate %27 4 Offset 28
+OpMemberDecorate %27 5 Offset 32
+OpMemberDecorate %27 6 Offset 48
+OpMemberDecorate %27 7 Offset 64
+OpMemberDecorate %27 2 RelaxedPrecision
+OpMemberDecorate %27 4 RelaxedPrecision
+OpDecorate %27 Block
+OpDecorate %29 DescriptorSet 0
+OpDecorate %29 Binding 4
+OpDecorate %32 RelaxedPrecision
+OpDecorate %33 RelaxedPrecision
+OpDecorate %36 RelaxedPrecision
+OpDecorate %37 RelaxedPrecision
+OpDecorate %38 RelaxedPrecision
+OpDecorate %39 RelaxedPrecision
+OpDecorate %41 RelaxedPrecision
+OpDecorate %42 RelaxedPrecision
+OpDecorate %43 RelaxedPrecision
+OpDecorate %48 RelaxedPrecision
+OpDecorate %49 RelaxedPrecision
+OpDecorate %50 RelaxedPrecision
+OpDecorate %52 RelaxedPrecision
+OpDecorate %53 RelaxedPrecision
+OpDecorate %54 RelaxedPrecision
+OpDecorate %55 RelaxedPrecision
+OpDecorate %56 RelaxedPrecision
+OpDecorate %57 RelaxedPrecision
+OpDecorate %58 RelaxedPrecision
+OpDecorate %59 RelaxedPrecision
+OpDecorate %60 RelaxedPrecision
+OpDecorate %67 RelaxedPrecision
+OpDecorate %68 RelaxedPrecision
+OpDecorate %72 RelaxedPrecision
+OpDecorate %73 RelaxedPrecision
+OpDecorate %75 RelaxedPrecision
+OpDecorate %76 RelaxedPrecision
+OpDecorate %77 RelaxedPrecision
+OpDecorate %80 RelaxedPrecision
+OpDecorate %81 RelaxedPrecision
+%1 = OpTypeFloat 32
+%2 = OpTypeVector %1 4
+%5 = OpTypeImage %1 2D 0 0 0 1 Unknown
+%6 = OpTypeSampledImage %5
+%9 = OpTypeImage %1 2D 0 0 0 2 Rgba8
+%12 = OpTypeStruct %2
+%15 = OpTypeStruct %2
+%16 = OpTypeInt 32 0
+%17 = OpConstant %16 2
+%18 = OpTypeArray %15 %17
+%23 = OpTypeInt 32 1
+%24 = OpTypeVector %23 4
+%25 = OpTypeVector %16 4
+%26 = OpTypeStruct %1 %1 %1 %1
+%27 = OpTypeStruct %2 %16 %16 %23 %23 %24 %25 %26
+%35 = OpTypeVector %1 2
+%40 = OpTypeVector %23 2
+%61 = OpTypeVoid
+%69 = OpConstant %16 0
+%78 = OpConstant %16 1
+%3 = OpTypePointer Input %2
+%7 = OpTypePointer UniformConstant %6
+%10 = OpTypePointer UniformConstant %9
+%13 = OpTypePointer Uniform %12
+%19 = OpTypePointer Uniform %18
+%21 = OpTypePointer Output %2
+%28 = OpTypePointer Uniform %27
+%30 = OpTypePointer Function %2
+%70 = OpTypePointer Uniform %2
+%31 = OpTypeFunction %2 %30
+%47 = OpTypeFunction %2 %30 %30
+%62 = OpTypeFunction %61
+%4 = OpVariable %3 Input
+%8 = OpVariable %7 UniformConstant
+%11 = OpVariable %10 UniformConstant
+%14 = OpVariable %13 Uniform
+%20 = OpVariable %19 Uniform
+%22 = OpVariable %21 Output
+%29 = OpVariable %28 Uniform
+%32 = OpFunction %2 None %31
+%33 = OpFunctionParameter %30
+%34 = OpLabel
+%36 = OpLoad %6 %8
+%37 = OpLoad %2 %33
+%38 = OpVectorShuffle %35 %37 %37 0 1
+%39 = OpImageSampleImplicitLod %2 %36 %38
+%41 = OpLoad %2 %33
+%42 = OpVectorShuffle %35 %41 %41 2 3
+%43 = OpConvertFToS %40 %42
+%44 = OpLoad %9 %11
+%45 = OpImageRead %2 %44 %43
+%46 = OpFAdd %2 %39 %45
+OpReturnValue %46
+OpFunctionEnd
+%48 = OpFunction %2 None %47
+%49 = OpFunctionParameter %30
+%50 = OpFunctionParameter %30
+%51 = OpLabel
+%52 = OpLoad %2 %49
+%53 = OpVectorShuffle %35 %52 %52 0 1
+%54 = OpLoad %2 %50
+%55 = OpVectorShuffle %35 %54 %54 2 3
+%56 = OpCompositeExtract %1 %53 0
+%57 = OpCompositeExtract %1 %53 1
+%58 = OpCompositeExtract %1 %55 0
+%59 = OpCompositeExtract %1 %55 1
+%60 = OpCompositeConstruct %2 %56 %57 %58 %59
+OpReturnValue %60
+OpFunctionEnd
+%63 = OpFunction %61 None %62
+%64 = OpLabel
+%65 = OpVariable %30 Function
+%68 = OpVariable %30 Function
+%73 = OpVariable %30 Function
+%66 = OpLoad %2 %4
+OpStore %65 %66
+%67 = OpFunctionCall %2 %32 %65
+%71 = OpAccessChain %70 %14 %69
+%72 = OpLoad %2 %71
+OpStore %68 %72
+%74 = OpAccessChain %70 %20 %69 %69
+%75 = OpLoad %2 %74
+OpStore %73 %75
+%76 = OpFunctionCall %2 %48 %68 %73
+%77 = OpFAdd %2 %67 %76
+%79 = OpAccessChain %70 %20 %78 %69
+%80 = OpLoad %2 %79
+%81 = OpFAdd %2 %77 %80
+OpStore %22 %81
+OpReturn
+OpFunctionEnd
+)";
+constexpr char kDst[] = R"(OpCapability Shader
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %63 "main" %4 %22
+OpExecutionMode %63 OriginUpperLeft
+OpSource GLSL 450
+OpName %4 "_ue"
+OpName %8 "_uf"
+OpName %11 "_ug"
+OpName %12 "_uA"
+OpMemberName %12 0 "_ux"
+OpName %14 "_uc"
+OpName %15 "_uB"
+OpMemberName %15 0 "_ux"
+OpName %20 "_ud"
+OpName %22 "_ucol"
+OpName %26 "ANGLEDepthRangeParams"
+OpMemberName %26 0 "near"
+OpMemberName %26 1 "far"
+OpMemberName %26 2 "diff"
+OpMemberName %26 3 "reserved"
+OpName %27 "ANGLEUniformBlock"
+OpMemberName %27 0 "viewport"
+OpMemberName %27 1 "clipDistancesEnabled"
+OpMemberName %27 2 "xfbActiveUnpaused"
+OpMemberName %27 3 "xfbVerticesPerInstance"
+OpMemberName %27 4 "numSamples"
+OpMemberName %27 5 "xfbBufferOffsets"
+OpMemberName %27 6 "acbBufferOffsets"
+OpMemberName %27 7 "depthRange"
+OpName %29 "ANGLEUniforms"
+OpName %33 "_uc"
+OpName %32 "_uh"
+OpName %49 "_ux"
+OpName %50 "_uy"
+OpName %48 "_ui"
+OpName %63 "main"
+OpName %65 "param"
+OpName %68 "param"
+OpName %73 "param"
+OpDecorate %4 Location 1
+OpDecorate %8 RelaxedPrecision
+OpDecorate %8 DescriptorSet 2
+OpDecorate %8 Binding 0
+OpDecorate %11 DescriptorSet 3
+OpDecorate %11 Binding 0
+OpMemberDecorate %12 0 Offset 0
+OpMemberDecorate %12 0 RelaxedPrecision
+OpDecorate %12 Block
+OpDecorate %14 DescriptorSet 3
+OpDecorate %14 Binding 1
+OpMemberDecorate %15 0 Offset 0
+OpMemberDecorate %15 0 RelaxedPrecision
+OpDecorate %15 BufferBlock
+OpDecorate %20 DescriptorSet 3
+OpDecorate %20 Binding 2
+OpDecorate %22 RelaxedPrecision
+OpDecorate %22 Location 1
+OpMemberDecorate %26 0 Offset 0
+OpMemberDecorate %26 1 Offset 4
+OpMemberDecorate %26 2 Offset 8
+OpMemberDecorate %26 3 Offset 12
+OpMemberDecorate %27 0 Offset 0
+OpMemberDecorate %27 1 Offset 16
+OpMemberDecorate %27 2 Offset 20
+OpMemberDecorate %27 3 Offset 24
+OpMemberDecorate %27 4 Offset 28
+OpMemberDecorate %27 5 Offset 32
+OpMemberDecorate %27 6 Offset 48
+OpMemberDecorate %27 7 Offset 64
+OpMemberDecorate %27 2 RelaxedPrecision
+OpMemberDecorate %27 4 RelaxedPrecision
+OpDecorate %27 Block
+OpDecorate %29 DescriptorSet 0
+OpDecorate %29 Binding 0
+OpDecorate %32 RelaxedPrecision
+OpDecorate %33 RelaxedPrecision
+OpDecorate %36 RelaxedPrecision
+OpDecorate %37 RelaxedPrecision
+OpDecorate %38 RelaxedPrecision
+OpDecorate %39 RelaxedPrecision
+OpDecorate %41 RelaxedPrecision
+OpDecorate %42 RelaxedPrecision
+OpDecorate %43 RelaxedPrecision
+OpDecorate %48 RelaxedPrecision
+OpDecorate %49 RelaxedPrecision
+OpDecorate %50 RelaxedPrecision
+OpDecorate %52 RelaxedPrecision
+OpDecorate %53 RelaxedPrecision
+OpDecorate %54 RelaxedPrecision
+OpDecorate %55 RelaxedPrecision
+OpDecorate %56 RelaxedPrecision
+OpDecorate %57 RelaxedPrecision
+OpDecorate %58 RelaxedPrecision
+OpDecorate %59 RelaxedPrecision
+OpDecorate %60 RelaxedPrecision
+OpDecorate %67 RelaxedPrecision
+OpDecorate %68 RelaxedPrecision
+OpDecorate %72 RelaxedPrecision
+OpDecorate %73 RelaxedPrecision
+OpDecorate %75 RelaxedPrecision
+OpDecorate %76 RelaxedPrecision
+OpDecorate %77 RelaxedPrecision
+OpDecorate %80 RelaxedPrecision
+OpDecorate %81 RelaxedPrecision
+%1 = OpTypeFloat 32
+%2 = OpTypeVector %1 4
+%5 = OpTypeImage %1 2D 0 0 0 1 Unknown
+%6 = OpTypeSampledImage %5
+%9 = OpTypeImage %1 2D 0 0 0 2 Rgba8
+%12 = OpTypeStruct %2
+%15 = OpTypeStruct %2
+%16 = OpTypeInt 32 0
+%17 = OpConstant %16 2
+%18 = OpTypeArray %15 %17
+%23 = OpTypeInt 32 1
+%24 = OpTypeVector %23 4
+%25 = OpTypeVector %16 4
+%26 = OpTypeStruct %1 %1 %1 %1
+%27 = OpTypeStruct %2 %16 %16 %23 %23 %24 %25 %26
+%35 = OpTypeVector %1 2
+%40 = OpTypeVector %23 2
+%61 = OpTypeVoid
+%69 = OpConstant %16 0
+%78 = OpConstant %16 1
+%82 = OpTypePointer Private %2
+%3 = OpTypePointer Input %2
+%7 = OpTypePointer UniformConstant %6
+%10 = OpTypePointer UniformConstant %9
+%13 = OpTypePointer Uniform %12
+%19 = OpTypePointer Uniform %18
+%83 = OpTypePointer Private %2
+%21 = OpTypePointer Output %2
+%28 = OpTypePointer Uniform %27
+%30 = OpTypePointer Function %2
+%70 = OpTypePointer Uniform %2
+%31 = OpTypeFunction %2 %30
+%47 = OpTypeFunction %2 %30 %30
+%62 = OpTypeFunction %61
+%4 = OpVariable %3 Input
+%8 = OpVariable %7 UniformConstant
+%11 = OpVariable %10 UniformConstant
+%14 = OpVariable %13 Uniform
+%20 = OpVariable %19 Uniform
+%22 = OpVariable %21 Output
+%29 = OpVariable %28 Uniform
+%84 = OpConstant %23 0
+%85 = OpConstant %1 0.5
+%32 = OpFunction %2 None %31
+%33 = OpFunctionParameter %30
+%34 = OpLabel
+%36 = OpLoad %6 %8
+%37 = OpLoad %2 %33
+%38 = OpVectorShuffle %35 %37 %37 0 1
+%39 = OpImageSampleImplicitLod %2 %36 %38
+%41 = OpLoad %2 %33
+%42 = OpVectorShuffle %35 %41 %41 2 3
+%43 = OpConvertFToS %40 %42
+%44 = OpLoad %9 %11
+%45 = OpImageRead %2 %44 %43
+%46 = OpFAdd %2 %39 %45
+OpReturnValue %46
+OpFunctionEnd
+%48 = OpFunction %2 None %47
+%49 = OpFunctionParameter %30
+%50 = OpFunctionParameter %30
+%51 = OpLabel
+%52 = OpLoad %2 %49
+%53 = OpVectorShuffle %35 %52 %52 0 1
+%54 = OpLoad %2 %50
+%55 = OpVectorShuffle %35 %54 %54 2 3
+%56 = OpCompositeExtract %1 %53 0
+%57 = OpCompositeExtract %1 %53 1
+%58 = OpCompositeExtract %1 %55 0
+%59 = OpCompositeExtract %1 %55 1
+%60 = OpCompositeConstruct %2 %56 %57 %58 %59
+OpReturnValue %60
+OpFunctionEnd
+%63 = OpFunction %61 None %62
+%64 = OpLabel
+%65 = OpVariable %30 Function
+%68 = OpVariable %30 Function
+%73 = OpVariable %30 Function
+%66 = OpLoad %2 %4
+OpStore %65 %66
+%67 = OpFunctionCall %2 %32 %65
+%71 = OpAccessChain %70 %14 %69
+%72 = OpLoad %2 %71
+OpStore %68 %72
+%74 = OpAccessChain %70 %20 %69 %69
+%75 = OpLoad %2 %74
+OpStore %73 %75
+%76 = OpFunctionCall %2 %48 %68 %73
+%77 = OpFAdd %2 %67 %76
+%79 = OpAccessChain %70 %20 %78 %69
+%80 = OpLoad %2 %79
+%81 = OpFAdd %2 %77 %80
+OpStore %22 %81
+OpReturn
+OpFunctionEnd
+)";
+
+TEST(DiffTest, DifferentDecorationsFragment) {
+  constexpr char kDiff[] = R"( ; SPIR-V
+ ; Version: 1.6
+ ; Generator: Khronos SPIR-V Tools Assembler; 0
+-; Bound: 82
++; Bound: 86
+ ; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %63 "main" %4 %22
+ OpExecutionMode %63 OriginUpperLeft
+ OpSource GLSL 450
+ OpName %4 "_ue"
+ OpName %8 "_uf"
+ OpName %11 "_ug"
+ OpName %12 "_uA"
+ OpMemberName %12 0 "_ux"
+ OpName %14 "_uc"
+ OpName %15 "_uB"
+ OpMemberName %15 0 "_ux"
+ OpName %20 "_ud"
+ OpName %22 "_ucol"
+ OpName %26 "ANGLEDepthRangeParams"
+ OpMemberName %26 0 "near"
+ OpMemberName %26 1 "far"
+ OpMemberName %26 2 "diff"
+ OpMemberName %26 3 "reserved"
+ OpName %27 "ANGLEUniformBlock"
+ OpMemberName %27 0 "viewport"
+ OpMemberName %27 1 "clipDistancesEnabled"
+ OpMemberName %27 2 "xfbActiveUnpaused"
+ OpMemberName %27 3 "xfbVerticesPerInstance"
+ OpMemberName %27 4 "numSamples"
+ OpMemberName %27 5 "xfbBufferOffsets"
+ OpMemberName %27 6 "acbBufferOffsets"
+ OpMemberName %27 7 "depthRange"
+ OpName %29 "ANGLEUniforms"
+ OpName %33 "_uc"
+ OpName %32 "_uh"
+ OpName %49 "_ux"
+ OpName %50 "_uy"
+ OpName %48 "_ui"
+ OpName %63 "main"
+ OpName %65 "param"
+ OpName %68 "param"
+ OpName %73 "param"
+-OpDecorate %4 Location 0
++OpDecorate %4 Location 1
+ OpDecorate %8 RelaxedPrecision
+-OpDecorate %8 DescriptorSet 0
++OpDecorate %8 DescriptorSet 2
+ OpDecorate %8 Binding 0
+-OpDecorate %11 DescriptorSet 0
++OpDecorate %11 DescriptorSet 3
+-OpDecorate %11 Binding 1
++OpDecorate %11 Binding 0
+ OpMemberDecorate %12 0 Offset 0
+ OpMemberDecorate %12 0 RelaxedPrecision
+ OpDecorate %12 Block
+-OpDecorate %14 DescriptorSet 0
++OpDecorate %14 DescriptorSet 3
+-OpDecorate %14 Binding 2
++OpDecorate %14 Binding 1
+ OpMemberDecorate %15 0 Offset 0
+ OpMemberDecorate %15 0 RelaxedPrecision
+ OpDecorate %15 BufferBlock
+-OpDecorate %20 DescriptorSet 0
++OpDecorate %20 DescriptorSet 3
+-OpDecorate %20 Binding 3
++OpDecorate %20 Binding 2
+ OpDecorate %22 RelaxedPrecision
+-OpDecorate %22 Location 0
++OpDecorate %22 Location 1
+ OpMemberDecorate %26 0 Offset 0
+ OpMemberDecorate %26 1 Offset 4
+ OpMemberDecorate %26 2 Offset 8
+ OpMemberDecorate %26 3 Offset 12
+ OpMemberDecorate %27 0 Offset 0
+ OpMemberDecorate %27 1 Offset 16
+ OpMemberDecorate %27 2 Offset 20
+ OpMemberDecorate %27 3 Offset 24
+ OpMemberDecorate %27 4 Offset 28
+ OpMemberDecorate %27 5 Offset 32
+ OpMemberDecorate %27 6 Offset 48
+ OpMemberDecorate %27 7 Offset 64
+ OpMemberDecorate %27 2 RelaxedPrecision
+ OpMemberDecorate %27 4 RelaxedPrecision
+ OpDecorate %27 Block
+ OpDecorate %29 DescriptorSet 0
+-OpDecorate %29 Binding 4
++OpDecorate %29 Binding 0
+ OpDecorate %32 RelaxedPrecision
+ OpDecorate %33 RelaxedPrecision
+ OpDecorate %36 RelaxedPrecision
+ OpDecorate %37 RelaxedPrecision
+ OpDecorate %38 RelaxedPrecision
+ OpDecorate %39 RelaxedPrecision
+ OpDecorate %41 RelaxedPrecision
+ OpDecorate %42 RelaxedPrecision
+ OpDecorate %43 RelaxedPrecision
+ OpDecorate %48 RelaxedPrecision
+ OpDecorate %49 RelaxedPrecision
+ OpDecorate %50 RelaxedPrecision
+ OpDecorate %52 RelaxedPrecision
+ OpDecorate %53 RelaxedPrecision
+ OpDecorate %54 RelaxedPrecision
+ OpDecorate %55 RelaxedPrecision
+ OpDecorate %56 RelaxedPrecision
+ OpDecorate %57 RelaxedPrecision
+ OpDecorate %58 RelaxedPrecision
+ OpDecorate %59 RelaxedPrecision
+ OpDecorate %60 RelaxedPrecision
+ OpDecorate %67 RelaxedPrecision
+ OpDecorate %68 RelaxedPrecision
+ OpDecorate %72 RelaxedPrecision
+ OpDecorate %73 RelaxedPrecision
+ OpDecorate %75 RelaxedPrecision
+ OpDecorate %76 RelaxedPrecision
+ OpDecorate %77 RelaxedPrecision
+ OpDecorate %80 RelaxedPrecision
+ OpDecorate %81 RelaxedPrecision
+ %1 = OpTypeFloat 32
+ %2 = OpTypeVector %1 4
+ %5 = OpTypeImage %1 2D 0 0 0 1 Unknown
+ %6 = OpTypeSampledImage %5
+ %9 = OpTypeImage %1 2D 0 0 0 2 Rgba8
+ %12 = OpTypeStruct %2
+ %15 = OpTypeStruct %2
+ %16 = OpTypeInt 32 0
+ %17 = OpConstant %16 2
+ %18 = OpTypeArray %15 %17
+ %23 = OpTypeInt 32 1
+ %24 = OpTypeVector %23 4
+ %25 = OpTypeVector %16 4
+ %26 = OpTypeStruct %1 %1 %1 %1
+ %27 = OpTypeStruct %2 %16 %16 %23 %23 %24 %25 %26
+ %35 = OpTypeVector %1 2
+ %40 = OpTypeVector %23 2
+ %61 = OpTypeVoid
+ %69 = OpConstant %16 0
+ %78 = OpConstant %16 1
++%82 = OpTypePointer Private %2
+ %3 = OpTypePointer Input %2
+ %7 = OpTypePointer UniformConstant %6
+ %10 = OpTypePointer UniformConstant %9
+ %13 = OpTypePointer Uniform %12
+ %19 = OpTypePointer Uniform %18
++%83 = OpTypePointer Private %2
+ %21 = OpTypePointer Output %2
+ %28 = OpTypePointer Uniform %27
+ %30 = OpTypePointer Function %2
+ %70 = OpTypePointer Uniform %2
+ %31 = OpTypeFunction %2 %30
+ %47 = OpTypeFunction %2 %30 %30
+ %62 = OpTypeFunction %61
+ %4 = OpVariable %3 Input
+ %8 = OpVariable %7 UniformConstant
+ %11 = OpVariable %10 UniformConstant
+ %14 = OpVariable %13 Uniform
+ %20 = OpVariable %19 Uniform
+ %22 = OpVariable %21 Output
+ %29 = OpVariable %28 Uniform
++%84 = OpConstant %23 0
++%85 = OpConstant %1 0.5
+ %32 = OpFunction %2 None %31
+ %33 = OpFunctionParameter %30
+ %34 = OpLabel
+ %36 = OpLoad %6 %8
+ %37 = OpLoad %2 %33
+ %38 = OpVectorShuffle %35 %37 %37 0 1
+ %39 = OpImageSampleImplicitLod %2 %36 %38
+ %41 = OpLoad %2 %33
+ %42 = OpVectorShuffle %35 %41 %41 2 3
+ %43 = OpConvertFToS %40 %42
+ %44 = OpLoad %9 %11
+ %45 = OpImageRead %2 %44 %43
+ %46 = OpFAdd %2 %39 %45
+ OpReturnValue %46
+ OpFunctionEnd
+ %48 = OpFunction %2 None %47
+ %49 = OpFunctionParameter %30
+ %50 = OpFunctionParameter %30
+ %51 = OpLabel
+ %52 = OpLoad %2 %49
+ %53 = OpVectorShuffle %35 %52 %52 0 1
+ %54 = OpLoad %2 %50
+ %55 = OpVectorShuffle %35 %54 %54 2 3
+ %56 = OpCompositeExtract %1 %53 0
+ %57 = OpCompositeExtract %1 %53 1
+ %58 = OpCompositeExtract %1 %55 0
+ %59 = OpCompositeExtract %1 %55 1
+ %60 = OpCompositeConstruct %2 %56 %57 %58 %59
+ OpReturnValue %60
+ OpFunctionEnd
+ %63 = OpFunction %61 None %62
+ %64 = OpLabel
+ %65 = OpVariable %30 Function
+ %68 = OpVariable %30 Function
+ %73 = OpVariable %30 Function
+ %66 = OpLoad %2 %4
+ OpStore %65 %66
+ %67 = OpFunctionCall %2 %32 %65
+ %71 = OpAccessChain %70 %14 %69
+ %72 = OpLoad %2 %71
+ OpStore %68 %72
+ %74 = OpAccessChain %70 %20 %69 %69
+ %75 = OpLoad %2 %74
+ OpStore %73 %75
+ %76 = OpFunctionCall %2 %48 %68 %73
+ %77 = OpFAdd %2 %67 %76
+ %79 = OpAccessChain %70 %20 %78 %69
+ %80 = OpLoad %2 %79
+ %81 = OpFAdd %2 %77 %80
+ OpStore %22 %81
+ OpReturn
+ OpFunctionEnd
+)";
+  Options options;
+  DoStringDiffTest(kSrc, kDst, kDiff, options);
+}
+
+TEST(DiffTest, DifferentDecorationsFragmentNoDebug) {
+  constexpr char kSrcNoDebug[] = R"(OpCapability Shader
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %63 "main" %4 %22
+OpExecutionMode %63 OriginUpperLeft
+OpSource GLSL 450
+OpDecorate %4 Location 0
+OpDecorate %8 RelaxedPrecision
+OpDecorate %8 DescriptorSet 0
+OpDecorate %8 Binding 0
+OpDecorate %11 DescriptorSet 0
+OpDecorate %11 Binding 1
+OpMemberDecorate %12 0 Offset 0
+OpMemberDecorate %12 0 RelaxedPrecision
+OpDecorate %12 Block
+OpDecorate %14 DescriptorSet 0
+OpDecorate %14 Binding 2
+OpMemberDecorate %15 0 Offset 0
+OpMemberDecorate %15 0 RelaxedPrecision
+OpDecorate %15 BufferBlock
+OpDecorate %20 DescriptorSet 0
+OpDecorate %20 Binding 3
+OpDecorate %22 RelaxedPrecision
+OpDecorate %22 Location 0
+OpMemberDecorate %26 0 Offset 0
+OpMemberDecorate %26 1 Offset 4
+OpMemberDecorate %26 2 Offset 8
+OpMemberDecorate %26 3 Offset 12
+OpMemberDecorate %27 0 Offset 0
+OpMemberDecorate %27 1 Offset 16
+OpMemberDecorate %27 2 Offset 20
+OpMemberDecorate %27 3 Offset 24
+OpMemberDecorate %27 4 Offset 28
+OpMemberDecorate %27 5 Offset 32
+OpMemberDecorate %27 6 Offset 48
+OpMemberDecorate %27 7 Offset 64
+OpMemberDecorate %27 2 RelaxedPrecision
+OpMemberDecorate %27 4 RelaxedPrecision
+OpDecorate %27 Block
+OpDecorate %29 DescriptorSet 0
+OpDecorate %29 Binding 4
+OpDecorate %32 RelaxedPrecision
+OpDecorate %33 RelaxedPrecision
+OpDecorate %36 RelaxedPrecision
+OpDecorate %37 RelaxedPrecision
+OpDecorate %38 RelaxedPrecision
+OpDecorate %39 RelaxedPrecision
+OpDecorate %41 RelaxedPrecision
+OpDecorate %42 RelaxedPrecision
+OpDecorate %43 RelaxedPrecision
+OpDecorate %48 RelaxedPrecision
+OpDecorate %49 RelaxedPrecision
+OpDecorate %50 RelaxedPrecision
+OpDecorate %52 RelaxedPrecision
+OpDecorate %53 RelaxedPrecision
+OpDecorate %54 RelaxedPrecision
+OpDecorate %55 RelaxedPrecision
+OpDecorate %56 RelaxedPrecision
+OpDecorate %57 RelaxedPrecision
+OpDecorate %58 RelaxedPrecision
+OpDecorate %59 RelaxedPrecision
+OpDecorate %60 RelaxedPrecision
+OpDecorate %67 RelaxedPrecision
+OpDecorate %68 RelaxedPrecision
+OpDecorate %72 RelaxedPrecision
+OpDecorate %73 RelaxedPrecision
+OpDecorate %75 RelaxedPrecision
+OpDecorate %76 RelaxedPrecision
+OpDecorate %77 RelaxedPrecision
+OpDecorate %80 RelaxedPrecision
+OpDecorate %81 RelaxedPrecision
+%1 = OpTypeFloat 32
+%2 = OpTypeVector %1 4
+%5 = OpTypeImage %1 2D 0 0 0 1 Unknown
+%6 = OpTypeSampledImage %5
+%9 = OpTypeImage %1 2D 0 0 0 2 Rgba8
+%12 = OpTypeStruct %2
+%15 = OpTypeStruct %2
+%16 = OpTypeInt 32 0
+%17 = OpConstant %16 2
+%18 = OpTypeArray %15 %17
+%23 = OpTypeInt 32 1
+%24 = OpTypeVector %23 4
+%25 = OpTypeVector %16 4
+%26 = OpTypeStruct %1 %1 %1 %1
+%27 = OpTypeStruct %2 %16 %16 %23 %23 %24 %25 %26
+%35 = OpTypeVector %1 2
+%40 = OpTypeVector %23 2
+%61 = OpTypeVoid
+%69 = OpConstant %16 0
+%78 = OpConstant %16 1
+%3 = OpTypePointer Input %2
+%7 = OpTypePointer UniformConstant %6
+%10 = OpTypePointer UniformConstant %9
+%13 = OpTypePointer Uniform %12
+%19 = OpTypePointer Uniform %18
+%21 = OpTypePointer Output %2
+%28 = OpTypePointer Uniform %27
+%30 = OpTypePointer Function %2
+%70 = OpTypePointer Uniform %2
+%31 = OpTypeFunction %2 %30
+%47 = OpTypeFunction %2 %30 %30
+%62 = OpTypeFunction %61
+%4 = OpVariable %3 Input
+%8 = OpVariable %7 UniformConstant
+%11 = OpVariable %10 UniformConstant
+%14 = OpVariable %13 Uniform
+%20 = OpVariable %19 Uniform
+%22 = OpVariable %21 Output
+%29 = OpVariable %28 Uniform
+%32 = OpFunction %2 None %31
+%33 = OpFunctionParameter %30
+%34 = OpLabel
+%36 = OpLoad %6 %8
+%37 = OpLoad %2 %33
+%38 = OpVectorShuffle %35 %37 %37 0 1
+%39 = OpImageSampleImplicitLod %2 %36 %38
+%41 = OpLoad %2 %33
+%42 = OpVectorShuffle %35 %41 %41 2 3
+%43 = OpConvertFToS %40 %42
+%44 = OpLoad %9 %11
+%45 = OpImageRead %2 %44 %43
+%46 = OpFAdd %2 %39 %45
+OpReturnValue %46
+OpFunctionEnd
+%48 = OpFunction %2 None %47
+%49 = OpFunctionParameter %30
+%50 = OpFunctionParameter %30
+%51 = OpLabel
+%52 = OpLoad %2 %49
+%53 = OpVectorShuffle %35 %52 %52 0 1
+%54 = OpLoad %2 %50
+%55 = OpVectorShuffle %35 %54 %54 2 3
+%56 = OpCompositeExtract %1 %53 0
+%57 = OpCompositeExtract %1 %53 1
+%58 = OpCompositeExtract %1 %55 0
+%59 = OpCompositeExtract %1 %55 1
+%60 = OpCompositeConstruct %2 %56 %57 %58 %59
+OpReturnValue %60
+OpFunctionEnd
+%63 = OpFunction %61 None %62
+%64 = OpLabel
+%65 = OpVariable %30 Function
+%68 = OpVariable %30 Function
+%73 = OpVariable %30 Function
+%66 = OpLoad %2 %4
+OpStore %65 %66
+%67 = OpFunctionCall %2 %32 %65
+%71 = OpAccessChain %70 %14 %69
+%72 = OpLoad %2 %71
+OpStore %68 %72
+%74 = OpAccessChain %70 %20 %69 %69
+%75 = OpLoad %2 %74
+OpStore %73 %75
+%76 = OpFunctionCall %2 %48 %68 %73
+%77 = OpFAdd %2 %67 %76
+%79 = OpAccessChain %70 %20 %78 %69
+%80 = OpLoad %2 %79
+%81 = OpFAdd %2 %77 %80
+OpStore %22 %81
+OpReturn
+OpFunctionEnd
+
+)";
+  constexpr char kDstNoDebug[] = R"(OpCapability Shader
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %63 "main" %4 %22
+OpExecutionMode %63 OriginUpperLeft
+OpSource GLSL 450
+OpDecorate %4 Location 1
+OpDecorate %8 RelaxedPrecision
+OpDecorate %8 DescriptorSet 2
+OpDecorate %8 Binding 0
+OpDecorate %11 DescriptorSet 3
+OpDecorate %11 Binding 0
+OpMemberDecorate %12 0 Offset 0
+OpMemberDecorate %12 0 RelaxedPrecision
+OpDecorate %12 Block
+OpDecorate %14 DescriptorSet 3
+OpDecorate %14 Binding 1
+OpMemberDecorate %15 0 Offset 0
+OpMemberDecorate %15 0 RelaxedPrecision
+OpDecorate %15 BufferBlock
+OpDecorate %20 DescriptorSet 3
+OpDecorate %20 Binding 2
+OpDecorate %22 RelaxedPrecision
+OpDecorate %22 Location 1
+OpMemberDecorate %26 0 Offset 0
+OpMemberDecorate %26 1 Offset 4
+OpMemberDecorate %26 2 Offset 8
+OpMemberDecorate %26 3 Offset 12
+OpMemberDecorate %27 0 Offset 0
+OpMemberDecorate %27 1 Offset 16
+OpMemberDecorate %27 2 Offset 20
+OpMemberDecorate %27 3 Offset 24
+OpMemberDecorate %27 4 Offset 28
+OpMemberDecorate %27 5 Offset 32
+OpMemberDecorate %27 6 Offset 48
+OpMemberDecorate %27 7 Offset 64
+OpMemberDecorate %27 2 RelaxedPrecision
+OpMemberDecorate %27 4 RelaxedPrecision
+OpDecorate %27 Block
+OpDecorate %29 DescriptorSet 0
+OpDecorate %29 Binding 0
+OpDecorate %32 RelaxedPrecision
+OpDecorate %33 RelaxedPrecision
+OpDecorate %36 RelaxedPrecision
+OpDecorate %37 RelaxedPrecision
+OpDecorate %38 RelaxedPrecision
+OpDecorate %39 RelaxedPrecision
+OpDecorate %41 RelaxedPrecision
+OpDecorate %42 RelaxedPrecision
+OpDecorate %43 RelaxedPrecision
+OpDecorate %48 RelaxedPrecision
+OpDecorate %49 RelaxedPrecision
+OpDecorate %50 RelaxedPrecision
+OpDecorate %52 RelaxedPrecision
+OpDecorate %53 RelaxedPrecision
+OpDecorate %54 RelaxedPrecision
+OpDecorate %55 RelaxedPrecision
+OpDecorate %56 RelaxedPrecision
+OpDecorate %57 RelaxedPrecision
+OpDecorate %58 RelaxedPrecision
+OpDecorate %59 RelaxedPrecision
+OpDecorate %60 RelaxedPrecision
+OpDecorate %67 RelaxedPrecision
+OpDecorate %68 RelaxedPrecision
+OpDecorate %72 RelaxedPrecision
+OpDecorate %73 RelaxedPrecision
+OpDecorate %75 RelaxedPrecision
+OpDecorate %76 RelaxedPrecision
+OpDecorate %77 RelaxedPrecision
+OpDecorate %80 RelaxedPrecision
+OpDecorate %81 RelaxedPrecision
+%1 = OpTypeFloat 32
+%2 = OpTypeVector %1 4
+%5 = OpTypeImage %1 2D 0 0 0 1 Unknown
+%6 = OpTypeSampledImage %5
+%9 = OpTypeImage %1 2D 0 0 0 2 Rgba8
+%12 = OpTypeStruct %2
+%15 = OpTypeStruct %2
+%16 = OpTypeInt 32 0
+%17 = OpConstant %16 2
+%18 = OpTypeArray %15 %17
+%23 = OpTypeInt 32 1
+%24 = OpTypeVector %23 4
+%25 = OpTypeVector %16 4
+%26 = OpTypeStruct %1 %1 %1 %1
+%27 = OpTypeStruct %2 %16 %16 %23 %23 %24 %25 %26
+%35 = OpTypeVector %1 2
+%40 = OpTypeVector %23 2
+%61 = OpTypeVoid
+%69 = OpConstant %16 0
+%78 = OpConstant %16 1
+%82 = OpTypePointer Private %2
+%3 = OpTypePointer Input %2
+%7 = OpTypePointer UniformConstant %6
+%10 = OpTypePointer UniformConstant %9
+%13 = OpTypePointer Uniform %12
+%19 = OpTypePointer Uniform %18
+%83 = OpTypePointer Private %2
+%21 = OpTypePointer Output %2
+%28 = OpTypePointer Uniform %27
+%30 = OpTypePointer Function %2
+%70 = OpTypePointer Uniform %2
+%31 = OpTypeFunction %2 %30
+%47 = OpTypeFunction %2 %30 %30
+%62 = OpTypeFunction %61
+%4 = OpVariable %3 Input
+%8 = OpVariable %7 UniformConstant
+%11 = OpVariable %10 UniformConstant
+%14 = OpVariable %13 Uniform
+%20 = OpVariable %19 Uniform
+%22 = OpVariable %21 Output
+%29 = OpVariable %28 Uniform
+%84 = OpConstant %23 0
+%85 = OpConstant %1 0.5
+%32 = OpFunction %2 None %31
+%33 = OpFunctionParameter %30
+%34 = OpLabel
+%36 = OpLoad %6 %8
+%37 = OpLoad %2 %33
+%38 = OpVectorShuffle %35 %37 %37 0 1
+%39 = OpImageSampleImplicitLod %2 %36 %38
+%41 = OpLoad %2 %33
+%42 = OpVectorShuffle %35 %41 %41 2 3
+%43 = OpConvertFToS %40 %42
+%44 = OpLoad %9 %11
+%45 = OpImageRead %2 %44 %43
+%46 = OpFAdd %2 %39 %45
+OpReturnValue %46
+OpFunctionEnd
+%48 = OpFunction %2 None %47
+%49 = OpFunctionParameter %30
+%50 = OpFunctionParameter %30
+%51 = OpLabel
+%52 = OpLoad %2 %49
+%53 = OpVectorShuffle %35 %52 %52 0 1
+%54 = OpLoad %2 %50
+%55 = OpVectorShuffle %35 %54 %54 2 3
+%56 = OpCompositeExtract %1 %53 0
+%57 = OpCompositeExtract %1 %53 1
+%58 = OpCompositeExtract %1 %55 0
+%59 = OpCompositeExtract %1 %55 1
+%60 = OpCompositeConstruct %2 %56 %57 %58 %59
+OpReturnValue %60
+OpFunctionEnd
+%63 = OpFunction %61 None %62
+%64 = OpLabel
+%65 = OpVariable %30 Function
+%68 = OpVariable %30 Function
+%73 = OpVariable %30 Function
+%66 = OpLoad %2 %4
+OpStore %65 %66
+%67 = OpFunctionCall %2 %32 %65
+%71 = OpAccessChain %70 %14 %69
+%72 = OpLoad %2 %71
+OpStore %68 %72
+%74 = OpAccessChain %70 %20 %69 %69
+%75 = OpLoad %2 %74
+OpStore %73 %75
+%76 = OpFunctionCall %2 %48 %68 %73
+%77 = OpFAdd %2 %67 %76
+%79 = OpAccessChain %70 %20 %78 %69
+%80 = OpLoad %2 %79
+%81 = OpFAdd %2 %77 %80
+OpStore %22 %81
+OpReturn
+OpFunctionEnd
+)";
+  constexpr char kDiff[] = R"( ; SPIR-V
+ ; Version: 1.6
+ ; Generator: Khronos SPIR-V Tools Assembler; 0
+-; Bound: 82
++; Bound: 92
+ ; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %63 "main" %4 %22
+ OpExecutionMode %63 OriginUpperLeft
+ OpSource GLSL 450
+-OpDecorate %4 Location 0
++OpDecorate %4 Location 1
+ OpDecorate %8 RelaxedPrecision
+-OpDecorate %8 DescriptorSet 0
++OpDecorate %8 DescriptorSet 2
+ OpDecorate %8 Binding 0
+-OpDecorate %11 DescriptorSet 0
++OpDecorate %11 DescriptorSet 3
+-OpDecorate %11 Binding 1
++OpDecorate %11 Binding 0
+ OpMemberDecorate %12 0 Offset 0
+ OpMemberDecorate %12 0 RelaxedPrecision
+ OpDecorate %12 Block
++OpDecorate %82 DescriptorSet 3
++OpDecorate %82 Binding 1
+-OpDecorate %14 DescriptorSet 0
++OpDecorate %14 DescriptorSet 3
+ OpDecorate %14 Binding 2
+ OpMemberDecorate %15 0 Offset 0
+ OpMemberDecorate %15 0 RelaxedPrecision
+ OpDecorate %15 BufferBlock
+-OpDecorate %20 DescriptorSet 0
+-OpDecorate %20 Binding 3
+ OpDecorate %22 RelaxedPrecision
+-OpDecorate %22 Location 0
++OpDecorate %22 Location 1
+ OpMemberDecorate %26 0 Offset 0
+ OpMemberDecorate %26 1 Offset 4
+ OpMemberDecorate %26 2 Offset 8
+ OpMemberDecorate %26 3 Offset 12
+ OpMemberDecorate %27 0 Offset 0
+ OpMemberDecorate %27 1 Offset 16
+ OpMemberDecorate %27 2 Offset 20
+ OpMemberDecorate %27 3 Offset 24
+ OpMemberDecorate %27 4 Offset 28
+ OpMemberDecorate %27 5 Offset 32
+ OpMemberDecorate %27 6 Offset 48
+ OpMemberDecorate %27 7 Offset 64
+ OpMemberDecorate %27 2 RelaxedPrecision
+ OpMemberDecorate %27 4 RelaxedPrecision
+ OpDecorate %27 Block
+-OpDecorate %29 DescriptorSet 0
+-OpDecorate %29 Binding 4
++OpDecorate %83 DescriptorSet 0
++OpDecorate %83 Binding 0
+ OpDecorate %32 RelaxedPrecision
+-OpDecorate %33 RelaxedPrecision
++OpDecorate %84 RelaxedPrecision
+ OpDecorate %36 RelaxedPrecision
+ OpDecorate %37 RelaxedPrecision
+ OpDecorate %38 RelaxedPrecision
+ OpDecorate %39 RelaxedPrecision
+ OpDecorate %41 RelaxedPrecision
+ OpDecorate %42 RelaxedPrecision
+ OpDecorate %43 RelaxedPrecision
+ OpDecorate %48 RelaxedPrecision
+-OpDecorate %49 RelaxedPrecision
+-OpDecorate %50 RelaxedPrecision
++OpDecorate %85 RelaxedPrecision
++OpDecorate %86 RelaxedPrecision
+ OpDecorate %52 RelaxedPrecision
+ OpDecorate %53 RelaxedPrecision
+ OpDecorate %54 RelaxedPrecision
+ OpDecorate %55 RelaxedPrecision
+ OpDecorate %56 RelaxedPrecision
+ OpDecorate %57 RelaxedPrecision
+ OpDecorate %58 RelaxedPrecision
+ OpDecorate %59 RelaxedPrecision
+ OpDecorate %60 RelaxedPrecision
+ OpDecorate %67 RelaxedPrecision
+ OpDecorate %68 RelaxedPrecision
+ OpDecorate %72 RelaxedPrecision
+ OpDecorate %73 RelaxedPrecision
+ OpDecorate %75 RelaxedPrecision
+ OpDecorate %76 RelaxedPrecision
+ OpDecorate %77 RelaxedPrecision
+ OpDecorate %80 RelaxedPrecision
+ OpDecorate %81 RelaxedPrecision
+ %1 = OpTypeFloat 32
+ %2 = OpTypeVector %1 4
+ %5 = OpTypeImage %1 2D 0 0 0 1 Unknown
+ %6 = OpTypeSampledImage %5
+ %9 = OpTypeImage %1 2D 0 0 0 2 Rgba8
+ %12 = OpTypeStruct %2
+ %15 = OpTypeStruct %2
+ %16 = OpTypeInt 32 0
+ %17 = OpConstant %16 2
+ %18 = OpTypeArray %15 %17
+ %23 = OpTypeInt 32 1
+ %24 = OpTypeVector %23 4
+ %25 = OpTypeVector %16 4
+ %26 = OpTypeStruct %1 %1 %1 %1
+ %27 = OpTypeStruct %2 %16 %16 %23 %23 %24 %25 %26
+ %35 = OpTypeVector %1 2
+ %40 = OpTypeVector %23 2
+ %61 = OpTypeVoid
+ %69 = OpConstant %16 0
+ %78 = OpConstant %16 1
++%88 = OpTypePointer Private %2
+ %3 = OpTypePointer Input %2
+ %7 = OpTypePointer UniformConstant %6
+ %10 = OpTypePointer UniformConstant %9
+ %13 = OpTypePointer Uniform %12
+ %19 = OpTypePointer Uniform %18
++%89 = OpTypePointer Private %2
+ %21 = OpTypePointer Output %2
+ %28 = OpTypePointer Uniform %27
+ %30 = OpTypePointer Function %2
+ %70 = OpTypePointer Uniform %2
+ %31 = OpTypeFunction %2 %30
+ %47 = OpTypeFunction %2 %30 %30
+ %62 = OpTypeFunction %61
+ %4 = OpVariable %3 Input
+ %8 = OpVariable %7 UniformConstant
+ %11 = OpVariable %10 UniformConstant
++%82 = OpVariable %13 Uniform
+-%14 = OpVariable %13 Uniform
++%14 = OpVariable %19 Uniform
+-%20 = OpVariable %19 Uniform
+ %22 = OpVariable %21 Output
+-%29 = OpVariable %28 Uniform
++%83 = OpVariable %28 Uniform
++%90 = OpConstant %23 0
++%91 = OpConstant %1 0.5
+ %32 = OpFunction %2 None %31
+-%33 = OpFunctionParameter %30
++%84 = OpFunctionParameter %30
+ %34 = OpLabel
+ %36 = OpLoad %6 %8
+-%37 = OpLoad %2 %33
++%37 = OpLoad %2 %84
+ %38 = OpVectorShuffle %35 %37 %37 0 1
+ %39 = OpImageSampleImplicitLod %2 %36 %38
+-%41 = OpLoad %2 %33
++%41 = OpLoad %2 %84
+ %42 = OpVectorShuffle %35 %41 %41 2 3
+ %43 = OpConvertFToS %40 %42
+ %44 = OpLoad %9 %11
+ %45 = OpImageRead %2 %44 %43
+ %46 = OpFAdd %2 %39 %45
+ OpReturnValue %46
+ OpFunctionEnd
+ %48 = OpFunction %2 None %47
+-%49 = OpFunctionParameter %30
+-%50 = OpFunctionParameter %30
++%85 = OpFunctionParameter %30
++%86 = OpFunctionParameter %30
+ %51 = OpLabel
+-%52 = OpLoad %2 %49
++%52 = OpLoad %2 %85
+ %53 = OpVectorShuffle %35 %52 %52 0 1
+-%54 = OpLoad %2 %50
++%54 = OpLoad %2 %86
+ %55 = OpVectorShuffle %35 %54 %54 2 3
+ %56 = OpCompositeExtract %1 %53 0
+ %57 = OpCompositeExtract %1 %53 1
+ %58 = OpCompositeExtract %1 %55 0
+ %59 = OpCompositeExtract %1 %55 1
+ %60 = OpCompositeConstruct %2 %56 %57 %58 %59
+ OpReturnValue %60
+ OpFunctionEnd
+ %63 = OpFunction %61 None %62
+ %64 = OpLabel
+ %65 = OpVariable %30 Function
+ %68 = OpVariable %30 Function
+ %73 = OpVariable %30 Function
+ %66 = OpLoad %2 %4
+ OpStore %65 %66
+ %67 = OpFunctionCall %2 %32 %65
+-%71 = OpAccessChain %70 %14 %69
++%87 = OpAccessChain %70 %82 %69
+-%72 = OpLoad %2 %71
++%72 = OpLoad %2 %87
+ OpStore %68 %72
+-%74 = OpAccessChain %70 %20 %69 %69
++%74 = OpAccessChain %70 %14 %69 %69
+ %75 = OpLoad %2 %74
+ OpStore %73 %75
+ %76 = OpFunctionCall %2 %48 %68 %73
+ %77 = OpFAdd %2 %67 %76
+-%79 = OpAccessChain %70 %20 %78 %69
++%79 = OpAccessChain %70 %14 %78 %69
+ %80 = OpLoad %2 %79
+ %81 = OpFAdd %2 %77 %80
+ OpStore %22 %81
+ OpReturn
+ OpFunctionEnd
+)";
+  Options options;
+  DoStringDiffTest(kSrcNoDebug, kDstNoDebug, kDiff, options);
+}
+
+TEST(DiffTest, DifferentDecorationsFragmentIgnoreLocation) {
+  constexpr char kDiff[] = R"( ; SPIR-V
+ ; Version: 1.6
+ ; Generator: Khronos SPIR-V Tools Assembler; 0
+-; Bound: 82
++; Bound: 86
+ ; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %63 "main" %4 %22
+ OpExecutionMode %63 OriginUpperLeft
+ OpSource GLSL 450
+ OpName %4 "_ue"
+ OpName %8 "_uf"
+ OpName %11 "_ug"
+ OpName %12 "_uA"
+ OpMemberName %12 0 "_ux"
+ OpName %14 "_uc"
+ OpName %15 "_uB"
+ OpMemberName %15 0 "_ux"
+ OpName %20 "_ud"
+ OpName %22 "_ucol"
+ OpName %26 "ANGLEDepthRangeParams"
+ OpMemberName %26 0 "near"
+ OpMemberName %26 1 "far"
+ OpMemberName %26 2 "diff"
+ OpMemberName %26 3 "reserved"
+ OpName %27 "ANGLEUniformBlock"
+ OpMemberName %27 0 "viewport"
+ OpMemberName %27 1 "clipDistancesEnabled"
+ OpMemberName %27 2 "xfbActiveUnpaused"
+ OpMemberName %27 3 "xfbVerticesPerInstance"
+ OpMemberName %27 4 "numSamples"
+ OpMemberName %27 5 "xfbBufferOffsets"
+ OpMemberName %27 6 "acbBufferOffsets"
+ OpMemberName %27 7 "depthRange"
+ OpName %29 "ANGLEUniforms"
+ OpName %33 "_uc"
+ OpName %32 "_uh"
+ OpName %49 "_ux"
+ OpName %50 "_uy"
+ OpName %48 "_ui"
+ OpName %63 "main"
+ OpName %65 "param"
+ OpName %68 "param"
+ OpName %73 "param"
+-OpDecorate %4 Location 0
++OpDecorate %4 Location 1
+ OpDecorate %8 RelaxedPrecision
+-OpDecorate %8 DescriptorSet 0
++OpDecorate %8 DescriptorSet 2
+ OpDecorate %8 Binding 0
+-OpDecorate %11 DescriptorSet 0
++OpDecorate %11 DescriptorSet 3
+-OpDecorate %11 Binding 1
++OpDecorate %11 Binding 0
+ OpMemberDecorate %12 0 Offset 0
+ OpMemberDecorate %12 0 RelaxedPrecision
+ OpDecorate %12 Block
+-OpDecorate %14 DescriptorSet 0
++OpDecorate %14 DescriptorSet 3
+-OpDecorate %14 Binding 2
++OpDecorate %14 Binding 1
+ OpMemberDecorate %15 0 Offset 0
+ OpMemberDecorate %15 0 RelaxedPrecision
+ OpDecorate %15 BufferBlock
+-OpDecorate %20 DescriptorSet 0
++OpDecorate %20 DescriptorSet 3
+-OpDecorate %20 Binding 3
++OpDecorate %20 Binding 2
+ OpDecorate %22 RelaxedPrecision
+-OpDecorate %22 Location 0
++OpDecorate %22 Location 1
+ OpMemberDecorate %26 0 Offset 0
+ OpMemberDecorate %26 1 Offset 4
+ OpMemberDecorate %26 2 Offset 8
+ OpMemberDecorate %26 3 Offset 12
+ OpMemberDecorate %27 0 Offset 0
+ OpMemberDecorate %27 1 Offset 16
+ OpMemberDecorate %27 2 Offset 20
+ OpMemberDecorate %27 3 Offset 24
+ OpMemberDecorate %27 4 Offset 28
+ OpMemberDecorate %27 5 Offset 32
+ OpMemberDecorate %27 6 Offset 48
+ OpMemberDecorate %27 7 Offset 64
+ OpMemberDecorate %27 2 RelaxedPrecision
+ OpMemberDecorate %27 4 RelaxedPrecision
+ OpDecorate %27 Block
+ OpDecorate %29 DescriptorSet 0
+-OpDecorate %29 Binding 4
++OpDecorate %29 Binding 0
+ OpDecorate %32 RelaxedPrecision
+ OpDecorate %33 RelaxedPrecision
+ OpDecorate %36 RelaxedPrecision
+ OpDecorate %37 RelaxedPrecision
+ OpDecorate %38 RelaxedPrecision
+ OpDecorate %39 RelaxedPrecision
+ OpDecorate %41 RelaxedPrecision
+ OpDecorate %42 RelaxedPrecision
+ OpDecorate %43 RelaxedPrecision
+ OpDecorate %48 RelaxedPrecision
+ OpDecorate %49 RelaxedPrecision
+ OpDecorate %50 RelaxedPrecision
+ OpDecorate %52 RelaxedPrecision
+ OpDecorate %53 RelaxedPrecision
+ OpDecorate %54 RelaxedPrecision
+ OpDecorate %55 RelaxedPrecision
+ OpDecorate %56 RelaxedPrecision
+ OpDecorate %57 RelaxedPrecision
+ OpDecorate %58 RelaxedPrecision
+ OpDecorate %59 RelaxedPrecision
+ OpDecorate %60 RelaxedPrecision
+ OpDecorate %67 RelaxedPrecision
+ OpDecorate %68 RelaxedPrecision
+ OpDecorate %72 RelaxedPrecision
+ OpDecorate %73 RelaxedPrecision
+ OpDecorate %75 RelaxedPrecision
+ OpDecorate %76 RelaxedPrecision
+ OpDecorate %77 RelaxedPrecision
+ OpDecorate %80 RelaxedPrecision
+ OpDecorate %81 RelaxedPrecision
+ %1 = OpTypeFloat 32
+ %2 = OpTypeVector %1 4
+ %5 = OpTypeImage %1 2D 0 0 0 1 Unknown
+ %6 = OpTypeSampledImage %5
+ %9 = OpTypeImage %1 2D 0 0 0 2 Rgba8
+ %12 = OpTypeStruct %2
+ %15 = OpTypeStruct %2
+ %16 = OpTypeInt 32 0
+ %17 = OpConstant %16 2
+ %18 = OpTypeArray %15 %17
+ %23 = OpTypeInt 32 1
+ %24 = OpTypeVector %23 4
+ %25 = OpTypeVector %16 4
+ %26 = OpTypeStruct %1 %1 %1 %1
+ %27 = OpTypeStruct %2 %16 %16 %23 %23 %24 %25 %26
+ %35 = OpTypeVector %1 2
+ %40 = OpTypeVector %23 2
+ %61 = OpTypeVoid
+ %69 = OpConstant %16 0
+ %78 = OpConstant %16 1
++%82 = OpTypePointer Private %2
+ %3 = OpTypePointer Input %2
+ %7 = OpTypePointer UniformConstant %6
+ %10 = OpTypePointer UniformConstant %9
+ %13 = OpTypePointer Uniform %12
+ %19 = OpTypePointer Uniform %18
++%83 = OpTypePointer Private %2
+ %21 = OpTypePointer Output %2
+ %28 = OpTypePointer Uniform %27
+ %30 = OpTypePointer Function %2
+ %70 = OpTypePointer Uniform %2
+ %31 = OpTypeFunction %2 %30
+ %47 = OpTypeFunction %2 %30 %30
+ %62 = OpTypeFunction %61
+ %4 = OpVariable %3 Input
+ %8 = OpVariable %7 UniformConstant
+ %11 = OpVariable %10 UniformConstant
+ %14 = OpVariable %13 Uniform
+ %20 = OpVariable %19 Uniform
+ %22 = OpVariable %21 Output
+ %29 = OpVariable %28 Uniform
++%84 = OpConstant %23 0
++%85 = OpConstant %1 0.5
+ %32 = OpFunction %2 None %31
+ %33 = OpFunctionParameter %30
+ %34 = OpLabel
+ %36 = OpLoad %6 %8
+ %37 = OpLoad %2 %33
+ %38 = OpVectorShuffle %35 %37 %37 0 1
+ %39 = OpImageSampleImplicitLod %2 %36 %38
+ %41 = OpLoad %2 %33
+ %42 = OpVectorShuffle %35 %41 %41 2 3
+ %43 = OpConvertFToS %40 %42
+ %44 = OpLoad %9 %11
+ %45 = OpImageRead %2 %44 %43
+ %46 = OpFAdd %2 %39 %45
+ OpReturnValue %46
+ OpFunctionEnd
+ %48 = OpFunction %2 None %47
+ %49 = OpFunctionParameter %30
+ %50 = OpFunctionParameter %30
+ %51 = OpLabel
+ %52 = OpLoad %2 %49
+ %53 = OpVectorShuffle %35 %52 %52 0 1
+ %54 = OpLoad %2 %50
+ %55 = OpVectorShuffle %35 %54 %54 2 3
+ %56 = OpCompositeExtract %1 %53 0
+ %57 = OpCompositeExtract %1 %53 1
+ %58 = OpCompositeExtract %1 %55 0
+ %59 = OpCompositeExtract %1 %55 1
+ %60 = OpCompositeConstruct %2 %56 %57 %58 %59
+ OpReturnValue %60
+ OpFunctionEnd
+ %63 = OpFunction %61 None %62
+ %64 = OpLabel
+ %65 = OpVariable %30 Function
+ %68 = OpVariable %30 Function
+ %73 = OpVariable %30 Function
+ %66 = OpLoad %2 %4
+ OpStore %65 %66
+ %67 = OpFunctionCall %2 %32 %65
+ %71 = OpAccessChain %70 %14 %69
+ %72 = OpLoad %2 %71
+ OpStore %68 %72
+ %74 = OpAccessChain %70 %20 %69 %69
+ %75 = OpLoad %2 %74
+ OpStore %73 %75
+ %76 = OpFunctionCall %2 %48 %68 %73
+ %77 = OpFAdd %2 %67 %76
+ %79 = OpAccessChain %70 %20 %78 %69
+ %80 = OpLoad %2 %79
+ %81 = OpFAdd %2 %77 %80
+ OpStore %22 %81
+ OpReturn
+ OpFunctionEnd
+)";
+  Options options;
+  options.ignore_location = true;
+  DoStringDiffTest(kSrc, kDst, kDiff, options);
+}
+
+TEST(DiffTest, DifferentDecorationsFragmentIgnoreSetBindingLocation) {
+  constexpr char kDiff[] = R"( ; SPIR-V
+ ; Version: 1.6
+ ; Generator: Khronos SPIR-V Tools Assembler; 0
+-; Bound: 82
++; Bound: 86
+ ; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %63 "main" %4 %22
+ OpExecutionMode %63 OriginUpperLeft
+ OpSource GLSL 450
+ OpName %4 "_ue"
+ OpName %8 "_uf"
+ OpName %11 "_ug"
+ OpName %12 "_uA"
+ OpMemberName %12 0 "_ux"
+ OpName %14 "_uc"
+ OpName %15 "_uB"
+ OpMemberName %15 0 "_ux"
+ OpName %20 "_ud"
+ OpName %22 "_ucol"
+ OpName %26 "ANGLEDepthRangeParams"
+ OpMemberName %26 0 "near"
+ OpMemberName %26 1 "far"
+ OpMemberName %26 2 "diff"
+ OpMemberName %26 3 "reserved"
+ OpName %27 "ANGLEUniformBlock"
+ OpMemberName %27 0 "viewport"
+ OpMemberName %27 1 "clipDistancesEnabled"
+ OpMemberName %27 2 "xfbActiveUnpaused"
+ OpMemberName %27 3 "xfbVerticesPerInstance"
+ OpMemberName %27 4 "numSamples"
+ OpMemberName %27 5 "xfbBufferOffsets"
+ OpMemberName %27 6 "acbBufferOffsets"
+ OpMemberName %27 7 "depthRange"
+ OpName %29 "ANGLEUniforms"
+ OpName %33 "_uc"
+ OpName %32 "_uh"
+ OpName %49 "_ux"
+ OpName %50 "_uy"
+ OpName %48 "_ui"
+ OpName %63 "main"
+ OpName %65 "param"
+ OpName %68 "param"
+ OpName %73 "param"
+-OpDecorate %4 Location 0
++OpDecorate %4 Location 1
+ OpDecorate %8 RelaxedPrecision
+-OpDecorate %8 DescriptorSet 0
++OpDecorate %8 DescriptorSet 2
+ OpDecorate %8 Binding 0
+-OpDecorate %11 DescriptorSet 0
++OpDecorate %11 DescriptorSet 3
+-OpDecorate %11 Binding 1
++OpDecorate %11 Binding 0
+ OpMemberDecorate %12 0 Offset 0
+ OpMemberDecorate %12 0 RelaxedPrecision
+ OpDecorate %12 Block
+-OpDecorate %14 DescriptorSet 0
++OpDecorate %14 DescriptorSet 3
+-OpDecorate %14 Binding 2
++OpDecorate %14 Binding 1
+ OpMemberDecorate %15 0 Offset 0
+ OpMemberDecorate %15 0 RelaxedPrecision
+ OpDecorate %15 BufferBlock
+-OpDecorate %20 DescriptorSet 0
++OpDecorate %20 DescriptorSet 3
+-OpDecorate %20 Binding 3
++OpDecorate %20 Binding 2
+ OpDecorate %22 RelaxedPrecision
+-OpDecorate %22 Location 0
++OpDecorate %22 Location 1
+ OpMemberDecorate %26 0 Offset 0
+ OpMemberDecorate %26 1 Offset 4
+ OpMemberDecorate %26 2 Offset 8
+ OpMemberDecorate %26 3 Offset 12
+ OpMemberDecorate %27 0 Offset 0
+ OpMemberDecorate %27 1 Offset 16
+ OpMemberDecorate %27 2 Offset 20
+ OpMemberDecorate %27 3 Offset 24
+ OpMemberDecorate %27 4 Offset 28
+ OpMemberDecorate %27 5 Offset 32
+ OpMemberDecorate %27 6 Offset 48
+ OpMemberDecorate %27 7 Offset 64
+ OpMemberDecorate %27 2 RelaxedPrecision
+ OpMemberDecorate %27 4 RelaxedPrecision
+ OpDecorate %27 Block
+ OpDecorate %29 DescriptorSet 0
+-OpDecorate %29 Binding 4
++OpDecorate %29 Binding 0
+ OpDecorate %32 RelaxedPrecision
+ OpDecorate %33 RelaxedPrecision
+ OpDecorate %36 RelaxedPrecision
+ OpDecorate %37 RelaxedPrecision
+ OpDecorate %38 RelaxedPrecision
+ OpDecorate %39 RelaxedPrecision
+ OpDecorate %41 RelaxedPrecision
+ OpDecorate %42 RelaxedPrecision
+ OpDecorate %43 RelaxedPrecision
+ OpDecorate %48 RelaxedPrecision
+ OpDecorate %49 RelaxedPrecision
+ OpDecorate %50 RelaxedPrecision
+ OpDecorate %52 RelaxedPrecision
+ OpDecorate %53 RelaxedPrecision
+ OpDecorate %54 RelaxedPrecision
+ OpDecorate %55 RelaxedPrecision
+ OpDecorate %56 RelaxedPrecision
+ OpDecorate %57 RelaxedPrecision
+ OpDecorate %58 RelaxedPrecision
+ OpDecorate %59 RelaxedPrecision
+ OpDecorate %60 RelaxedPrecision
+ OpDecorate %67 RelaxedPrecision
+ OpDecorate %68 RelaxedPrecision
+ OpDecorate %72 RelaxedPrecision
+ OpDecorate %73 RelaxedPrecision
+ OpDecorate %75 RelaxedPrecision
+ OpDecorate %76 RelaxedPrecision
+ OpDecorate %77 RelaxedPrecision
+ OpDecorate %80 RelaxedPrecision
+ OpDecorate %81 RelaxedPrecision
+ %1 = OpTypeFloat 32
+ %2 = OpTypeVector %1 4
+ %5 = OpTypeImage %1 2D 0 0 0 1 Unknown
+ %6 = OpTypeSampledImage %5
+ %9 = OpTypeImage %1 2D 0 0 0 2 Rgba8
+ %12 = OpTypeStruct %2
+ %15 = OpTypeStruct %2
+ %16 = OpTypeInt 32 0
+ %17 = OpConstant %16 2
+ %18 = OpTypeArray %15 %17
+ %23 = OpTypeInt 32 1
+ %24 = OpTypeVector %23 4
+ %25 = OpTypeVector %16 4
+ %26 = OpTypeStruct %1 %1 %1 %1
+ %27 = OpTypeStruct %2 %16 %16 %23 %23 %24 %25 %26
+ %35 = OpTypeVector %1 2
+ %40 = OpTypeVector %23 2
+ %61 = OpTypeVoid
+ %69 = OpConstant %16 0
+ %78 = OpConstant %16 1
++%82 = OpTypePointer Private %2
+ %3 = OpTypePointer Input %2
+ %7 = OpTypePointer UniformConstant %6
+ %10 = OpTypePointer UniformConstant %9
+ %13 = OpTypePointer Uniform %12
+ %19 = OpTypePointer Uniform %18
++%83 = OpTypePointer Private %2
+ %21 = OpTypePointer Output %2
+ %28 = OpTypePointer Uniform %27
+ %30 = OpTypePointer Function %2
+ %70 = OpTypePointer Uniform %2
+ %31 = OpTypeFunction %2 %30
+ %47 = OpTypeFunction %2 %30 %30
+ %62 = OpTypeFunction %61
+ %4 = OpVariable %3 Input
+ %8 = OpVariable %7 UniformConstant
+ %11 = OpVariable %10 UniformConstant
+ %14 = OpVariable %13 Uniform
+ %20 = OpVariable %19 Uniform
+ %22 = OpVariable %21 Output
+ %29 = OpVariable %28 Uniform
++%84 = OpConstant %23 0
++%85 = OpConstant %1 0.5
+ %32 = OpFunction %2 None %31
+ %33 = OpFunctionParameter %30
+ %34 = OpLabel
+ %36 = OpLoad %6 %8
+ %37 = OpLoad %2 %33
+ %38 = OpVectorShuffle %35 %37 %37 0 1
+ %39 = OpImageSampleImplicitLod %2 %36 %38
+ %41 = OpLoad %2 %33
+ %42 = OpVectorShuffle %35 %41 %41 2 3
+ %43 = OpConvertFToS %40 %42
+ %44 = OpLoad %9 %11
+ %45 = OpImageRead %2 %44 %43
+ %46 = OpFAdd %2 %39 %45
+ OpReturnValue %46
+ OpFunctionEnd
+ %48 = OpFunction %2 None %47
+ %49 = OpFunctionParameter %30
+ %50 = OpFunctionParameter %30
+ %51 = OpLabel
+ %52 = OpLoad %2 %49
+ %53 = OpVectorShuffle %35 %52 %52 0 1
+ %54 = OpLoad %2 %50
+ %55 = OpVectorShuffle %35 %54 %54 2 3
+ %56 = OpCompositeExtract %1 %53 0
+ %57 = OpCompositeExtract %1 %53 1
+ %58 = OpCompositeExtract %1 %55 0
+ %59 = OpCompositeExtract %1 %55 1
+ %60 = OpCompositeConstruct %2 %56 %57 %58 %59
+ OpReturnValue %60
+ OpFunctionEnd
+ %63 = OpFunction %61 None %62
+ %64 = OpLabel
+ %65 = OpVariable %30 Function
+ %68 = OpVariable %30 Function
+ %73 = OpVariable %30 Function
+ %66 = OpLoad %2 %4
+ OpStore %65 %66
+ %67 = OpFunctionCall %2 %32 %65
+ %71 = OpAccessChain %70 %14 %69
+ %72 = OpLoad %2 %71
+ OpStore %68 %72
+ %74 = OpAccessChain %70 %20 %69 %69
+ %75 = OpLoad %2 %74
+ OpStore %73 %75
+ %76 = OpFunctionCall %2 %48 %68 %73
+ %77 = OpFAdd %2 %67 %76
+ %79 = OpAccessChain %70 %20 %78 %69
+ %80 = OpLoad %2 %79
+ %81 = OpFAdd %2 %77 %80
+ OpStore %22 %81
+ OpReturn
+ OpFunctionEnd
+)";
+  Options options;
+  options.ignore_set_binding = true;
+  options.ignore_location = true;
+  DoStringDiffTest(kSrc, kDst, kDiff, options);
+}
+
+}  // namespace
+}  // namespace diff
+}  // namespace spvtools

+ 199 - 0
ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/different_decorations_fragment_dst.spvasm

@@ -0,0 +1,199 @@
+OpCapability Shader
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %63 "main" %4 %22
+OpExecutionMode %63 OriginUpperLeft
+OpSource GLSL 450
+OpName %4 "_ue"
+OpName %8 "_uf"
+OpName %11 "_ug"
+OpName %12 "_uA"
+OpMemberName %12 0 "_ux"
+OpName %14 "_uc"
+OpName %15 "_uB"
+OpMemberName %15 0 "_ux"
+OpName %20 "_ud"
+OpName %22 "_ucol"
+OpName %26 "ANGLEDepthRangeParams"
+OpMemberName %26 0 "near"
+OpMemberName %26 1 "far"
+OpMemberName %26 2 "diff"
+OpMemberName %26 3 "reserved"
+OpName %27 "ANGLEUniformBlock"
+OpMemberName %27 0 "viewport"
+OpMemberName %27 1 "clipDistancesEnabled"
+OpMemberName %27 2 "xfbActiveUnpaused"
+OpMemberName %27 3 "xfbVerticesPerInstance"
+OpMemberName %27 4 "numSamples"
+OpMemberName %27 5 "xfbBufferOffsets"
+OpMemberName %27 6 "acbBufferOffsets"
+OpMemberName %27 7 "depthRange"
+OpName %29 "ANGLEUniforms"
+OpName %33 "_uc"
+OpName %32 "_uh"
+OpName %49 "_ux"
+OpName %50 "_uy"
+OpName %48 "_ui"
+OpName %63 "main"
+OpName %65 "param"
+OpName %68 "param"
+OpName %73 "param"
+OpDecorate %4 Location 1
+OpDecorate %8 RelaxedPrecision
+OpDecorate %8 DescriptorSet 2
+OpDecorate %8 Binding 0
+OpDecorate %11 DescriptorSet 3
+OpDecorate %11 Binding 0
+OpMemberDecorate %12 0 Offset 0
+OpMemberDecorate %12 0 RelaxedPrecision
+OpDecorate %12 Block
+OpDecorate %14 DescriptorSet 3
+OpDecorate %14 Binding 1
+OpMemberDecorate %15 0 Offset 0
+OpMemberDecorate %15 0 RelaxedPrecision
+OpDecorate %15 BufferBlock
+OpDecorate %20 DescriptorSet 3
+OpDecorate %20 Binding 2
+OpDecorate %22 RelaxedPrecision
+OpDecorate %22 Location 1
+OpMemberDecorate %26 0 Offset 0
+OpMemberDecorate %26 1 Offset 4
+OpMemberDecorate %26 2 Offset 8
+OpMemberDecorate %26 3 Offset 12
+OpMemberDecorate %27 0 Offset 0
+OpMemberDecorate %27 1 Offset 16
+OpMemberDecorate %27 2 Offset 20
+OpMemberDecorate %27 3 Offset 24
+OpMemberDecorate %27 4 Offset 28
+OpMemberDecorate %27 5 Offset 32
+OpMemberDecorate %27 6 Offset 48
+OpMemberDecorate %27 7 Offset 64
+OpMemberDecorate %27 2 RelaxedPrecision
+OpMemberDecorate %27 4 RelaxedPrecision
+OpDecorate %27 Block
+OpDecorate %29 DescriptorSet 0
+OpDecorate %29 Binding 0
+OpDecorate %32 RelaxedPrecision
+OpDecorate %33 RelaxedPrecision
+OpDecorate %36 RelaxedPrecision
+OpDecorate %37 RelaxedPrecision
+OpDecorate %38 RelaxedPrecision
+OpDecorate %39 RelaxedPrecision
+OpDecorate %41 RelaxedPrecision
+OpDecorate %42 RelaxedPrecision
+OpDecorate %43 RelaxedPrecision
+OpDecorate %48 RelaxedPrecision
+OpDecorate %49 RelaxedPrecision
+OpDecorate %50 RelaxedPrecision
+OpDecorate %52 RelaxedPrecision
+OpDecorate %53 RelaxedPrecision
+OpDecorate %54 RelaxedPrecision
+OpDecorate %55 RelaxedPrecision
+OpDecorate %56 RelaxedPrecision
+OpDecorate %57 RelaxedPrecision
+OpDecorate %58 RelaxedPrecision
+OpDecorate %59 RelaxedPrecision
+OpDecorate %60 RelaxedPrecision
+OpDecorate %67 RelaxedPrecision
+OpDecorate %68 RelaxedPrecision
+OpDecorate %72 RelaxedPrecision
+OpDecorate %73 RelaxedPrecision
+OpDecorate %75 RelaxedPrecision
+OpDecorate %76 RelaxedPrecision
+OpDecorate %77 RelaxedPrecision
+OpDecorate %80 RelaxedPrecision
+OpDecorate %81 RelaxedPrecision
+%1 = OpTypeFloat 32
+%2 = OpTypeVector %1 4
+%5 = OpTypeImage %1 2D 0 0 0 1 Unknown
+%6 = OpTypeSampledImage %5
+%9 = OpTypeImage %1 2D 0 0 0 2 Rgba8
+%12 = OpTypeStruct %2
+%15 = OpTypeStruct %2
+%16 = OpTypeInt 32 0
+%17 = OpConstant %16 2
+%18 = OpTypeArray %15 %17
+%23 = OpTypeInt 32 1
+%24 = OpTypeVector %23 4
+%25 = OpTypeVector %16 4
+%26 = OpTypeStruct %1 %1 %1 %1
+%27 = OpTypeStruct %2 %16 %16 %23 %23 %24 %25 %26
+%35 = OpTypeVector %1 2
+%40 = OpTypeVector %23 2
+%61 = OpTypeVoid
+%69 = OpConstant %16 0
+%78 = OpConstant %16 1
+%82 = OpTypePointer Private %2
+%3 = OpTypePointer Input %2
+%7 = OpTypePointer UniformConstant %6
+%10 = OpTypePointer UniformConstant %9
+%13 = OpTypePointer Uniform %12
+%19 = OpTypePointer Uniform %18
+%83 = OpTypePointer Private %2
+%21 = OpTypePointer Output %2
+%28 = OpTypePointer Uniform %27
+%30 = OpTypePointer Function %2
+%70 = OpTypePointer Uniform %2
+%31 = OpTypeFunction %2 %30
+%47 = OpTypeFunction %2 %30 %30
+%62 = OpTypeFunction %61
+%4 = OpVariable %3 Input
+%8 = OpVariable %7 UniformConstant
+%11 = OpVariable %10 UniformConstant
+%14 = OpVariable %13 Uniform
+%20 = OpVariable %19 Uniform
+%22 = OpVariable %21 Output
+%29 = OpVariable %28 Uniform
+%84 = OpConstant %23 0
+%85 = OpConstant %1 0.5
+%32 = OpFunction %2 None %31
+%33 = OpFunctionParameter %30
+%34 = OpLabel
+%36 = OpLoad %6 %8
+%37 = OpLoad %2 %33
+%38 = OpVectorShuffle %35 %37 %37 0 1
+%39 = OpImageSampleImplicitLod %2 %36 %38
+%41 = OpLoad %2 %33
+%42 = OpVectorShuffle %35 %41 %41 2 3
+%43 = OpConvertFToS %40 %42
+%44 = OpLoad %9 %11
+%45 = OpImageRead %2 %44 %43
+%46 = OpFAdd %2 %39 %45
+OpReturnValue %46
+OpFunctionEnd
+%48 = OpFunction %2 None %47
+%49 = OpFunctionParameter %30
+%50 = OpFunctionParameter %30
+%51 = OpLabel
+%52 = OpLoad %2 %49
+%53 = OpVectorShuffle %35 %52 %52 0 1
+%54 = OpLoad %2 %50
+%55 = OpVectorShuffle %35 %54 %54 2 3
+%56 = OpCompositeExtract %1 %53 0
+%57 = OpCompositeExtract %1 %53 1
+%58 = OpCompositeExtract %1 %55 0
+%59 = OpCompositeExtract %1 %55 1
+%60 = OpCompositeConstruct %2 %56 %57 %58 %59
+OpReturnValue %60
+OpFunctionEnd
+%63 = OpFunction %61 None %62
+%64 = OpLabel
+%65 = OpVariable %30 Function
+%68 = OpVariable %30 Function
+%73 = OpVariable %30 Function
+%66 = OpLoad %2 %4
+OpStore %65 %66
+%67 = OpFunctionCall %2 %32 %65
+%71 = OpAccessChain %70 %14 %69
+%72 = OpLoad %2 %71
+OpStore %68 %72
+%74 = OpAccessChain %70 %20 %69 %69
+%75 = OpLoad %2 %74
+OpStore %73 %75
+%76 = OpFunctionCall %2 %48 %68 %73
+%77 = OpFAdd %2 %67 %76
+%79 = OpAccessChain %70 %20 %78 %69
+%80 = OpLoad %2 %79
+%81 = OpFAdd %2 %77 %80
+OpStore %22 %81
+OpReturn
+OpFunctionEnd

+ 198 - 0
ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/different_decorations_fragment_src.spvasm

@@ -0,0 +1,198 @@
+;; Test where variable set/binding/location decorations are different between
+;; src and dst fragment shaders.
+OpCapability Shader
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %63 "main" %4 %22
+OpExecutionMode %63 OriginUpperLeft
+OpSource GLSL 450
+OpName %4 "_ue"
+OpName %8 "_uf"
+OpName %11 "_ug"
+OpName %12 "_uA"
+OpMemberName %12 0 "_ux"
+OpName %14 "_uc"
+OpName %15 "_uB"
+OpMemberName %15 0 "_ux"
+OpName %20 "_ud"
+OpName %22 "_ucol"
+OpName %26 "ANGLEDepthRangeParams"
+OpMemberName %26 0 "near"
+OpMemberName %26 1 "far"
+OpMemberName %26 2 "diff"
+OpMemberName %26 3 "reserved"
+OpName %27 "ANGLEUniformBlock"
+OpMemberName %27 0 "viewport"
+OpMemberName %27 1 "clipDistancesEnabled"
+OpMemberName %27 2 "xfbActiveUnpaused"
+OpMemberName %27 3 "xfbVerticesPerInstance"
+OpMemberName %27 4 "numSamples"
+OpMemberName %27 5 "xfbBufferOffsets"
+OpMemberName %27 6 "acbBufferOffsets"
+OpMemberName %27 7 "depthRange"
+OpName %29 "ANGLEUniforms"
+OpName %33 "_uc"
+OpName %32 "_uh"
+OpName %49 "_ux"
+OpName %50 "_uy"
+OpName %48 "_ui"
+OpName %63 "main"
+OpName %65 "param"
+OpName %68 "param"
+OpName %73 "param"
+OpDecorate %4 Location 0
+OpDecorate %8 RelaxedPrecision
+OpDecorate %8 DescriptorSet 0
+OpDecorate %8 Binding 0
+OpDecorate %11 DescriptorSet 0
+OpDecorate %11 Binding 1
+OpMemberDecorate %12 0 Offset 0
+OpMemberDecorate %12 0 RelaxedPrecision
+OpDecorate %12 Block
+OpDecorate %14 DescriptorSet 0
+OpDecorate %14 Binding 2
+OpMemberDecorate %15 0 Offset 0
+OpMemberDecorate %15 0 RelaxedPrecision
+OpDecorate %15 BufferBlock
+OpDecorate %20 DescriptorSet 0
+OpDecorate %20 Binding 3
+OpDecorate %22 RelaxedPrecision
+OpDecorate %22 Location 0
+OpMemberDecorate %26 0 Offset 0
+OpMemberDecorate %26 1 Offset 4
+OpMemberDecorate %26 2 Offset 8
+OpMemberDecorate %26 3 Offset 12
+OpMemberDecorate %27 0 Offset 0
+OpMemberDecorate %27 1 Offset 16
+OpMemberDecorate %27 2 Offset 20
+OpMemberDecorate %27 3 Offset 24
+OpMemberDecorate %27 4 Offset 28
+OpMemberDecorate %27 5 Offset 32
+OpMemberDecorate %27 6 Offset 48
+OpMemberDecorate %27 7 Offset 64
+OpMemberDecorate %27 2 RelaxedPrecision
+OpMemberDecorate %27 4 RelaxedPrecision
+OpDecorate %27 Block
+OpDecorate %29 DescriptorSet 0
+OpDecorate %29 Binding 4
+OpDecorate %32 RelaxedPrecision
+OpDecorate %33 RelaxedPrecision
+OpDecorate %36 RelaxedPrecision
+OpDecorate %37 RelaxedPrecision
+OpDecorate %38 RelaxedPrecision
+OpDecorate %39 RelaxedPrecision
+OpDecorate %41 RelaxedPrecision
+OpDecorate %42 RelaxedPrecision
+OpDecorate %43 RelaxedPrecision
+OpDecorate %48 RelaxedPrecision
+OpDecorate %49 RelaxedPrecision
+OpDecorate %50 RelaxedPrecision
+OpDecorate %52 RelaxedPrecision
+OpDecorate %53 RelaxedPrecision
+OpDecorate %54 RelaxedPrecision
+OpDecorate %55 RelaxedPrecision
+OpDecorate %56 RelaxedPrecision
+OpDecorate %57 RelaxedPrecision
+OpDecorate %58 RelaxedPrecision
+OpDecorate %59 RelaxedPrecision
+OpDecorate %60 RelaxedPrecision
+OpDecorate %67 RelaxedPrecision
+OpDecorate %68 RelaxedPrecision
+OpDecorate %72 RelaxedPrecision
+OpDecorate %73 RelaxedPrecision
+OpDecorate %75 RelaxedPrecision
+OpDecorate %76 RelaxedPrecision
+OpDecorate %77 RelaxedPrecision
+OpDecorate %80 RelaxedPrecision
+OpDecorate %81 RelaxedPrecision
+%1 = OpTypeFloat 32
+%2 = OpTypeVector %1 4
+%5 = OpTypeImage %1 2D 0 0 0 1 Unknown
+%6 = OpTypeSampledImage %5
+%9 = OpTypeImage %1 2D 0 0 0 2 Rgba8
+%12 = OpTypeStruct %2
+%15 = OpTypeStruct %2
+%16 = OpTypeInt 32 0
+%17 = OpConstant %16 2
+%18 = OpTypeArray %15 %17
+%23 = OpTypeInt 32 1
+%24 = OpTypeVector %23 4
+%25 = OpTypeVector %16 4
+%26 = OpTypeStruct %1 %1 %1 %1
+%27 = OpTypeStruct %2 %16 %16 %23 %23 %24 %25 %26
+%35 = OpTypeVector %1 2
+%40 = OpTypeVector %23 2
+%61 = OpTypeVoid
+%69 = OpConstant %16 0
+%78 = OpConstant %16 1
+%3 = OpTypePointer Input %2
+%7 = OpTypePointer UniformConstant %6
+%10 = OpTypePointer UniformConstant %9
+%13 = OpTypePointer Uniform %12
+%19 = OpTypePointer Uniform %18
+%21 = OpTypePointer Output %2
+%28 = OpTypePointer Uniform %27
+%30 = OpTypePointer Function %2
+%70 = OpTypePointer Uniform %2
+%31 = OpTypeFunction %2 %30
+%47 = OpTypeFunction %2 %30 %30
+%62 = OpTypeFunction %61
+%4 = OpVariable %3 Input
+%8 = OpVariable %7 UniformConstant
+%11 = OpVariable %10 UniformConstant
+%14 = OpVariable %13 Uniform
+%20 = OpVariable %19 Uniform
+%22 = OpVariable %21 Output
+%29 = OpVariable %28 Uniform
+%32 = OpFunction %2 None %31
+%33 = OpFunctionParameter %30
+%34 = OpLabel
+%36 = OpLoad %6 %8
+%37 = OpLoad %2 %33
+%38 = OpVectorShuffle %35 %37 %37 0 1
+%39 = OpImageSampleImplicitLod %2 %36 %38
+%41 = OpLoad %2 %33
+%42 = OpVectorShuffle %35 %41 %41 2 3
+%43 = OpConvertFToS %40 %42
+%44 = OpLoad %9 %11
+%45 = OpImageRead %2 %44 %43
+%46 = OpFAdd %2 %39 %45
+OpReturnValue %46
+OpFunctionEnd
+%48 = OpFunction %2 None %47
+%49 = OpFunctionParameter %30
+%50 = OpFunctionParameter %30
+%51 = OpLabel
+%52 = OpLoad %2 %49
+%53 = OpVectorShuffle %35 %52 %52 0 1
+%54 = OpLoad %2 %50
+%55 = OpVectorShuffle %35 %54 %54 2 3
+%56 = OpCompositeExtract %1 %53 0
+%57 = OpCompositeExtract %1 %53 1
+%58 = OpCompositeExtract %1 %55 0
+%59 = OpCompositeExtract %1 %55 1
+%60 = OpCompositeConstruct %2 %56 %57 %58 %59
+OpReturnValue %60
+OpFunctionEnd
+%63 = OpFunction %61 None %62
+%64 = OpLabel
+%65 = OpVariable %30 Function
+%68 = OpVariable %30 Function
+%73 = OpVariable %30 Function
+%66 = OpLoad %2 %4
+OpStore %65 %66
+%67 = OpFunctionCall %2 %32 %65
+%71 = OpAccessChain %70 %14 %69
+%72 = OpLoad %2 %71
+OpStore %68 %72
+%74 = OpAccessChain %70 %20 %69 %69
+%75 = OpLoad %2 %74
+OpStore %73 %75
+%76 = OpFunctionCall %2 %48 %68 %73
+%77 = OpFAdd %2 %67 %76
+%79 = OpAccessChain %70 %20 %78 %69
+%80 = OpLoad %2 %79
+%81 = OpFAdd %2 %77 %80
+OpStore %22 %81
+OpReturn
+OpFunctionEnd
+

+ 1322 - 0
ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/different_decorations_vertex_autogen.cpp

@@ -0,0 +1,1322 @@
+// GENERATED FILE - DO NOT EDIT.
+// Generated by generate_tests.py
+//
+// 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 "../diff_test_utils.h"
+
+#include "gtest/gtest.h"
+
+namespace spvtools {
+namespace diff {
+namespace {
+
+// Test where variable set/binding/location decorations are different between
+// src and dst vertex shaders.
+constexpr char kSrc[] = R"(OpCapability Shader
+OpMemoryModel Logical GLSL450
+OpEntryPoint Vertex %40 "main" %4 %5 %6 %8 %20 %25
+OpSource GLSL 450
+OpName %4 "_ub"
+OpName %5 "_uc"
+OpName %6 "_ud"
+OpName %8 "_ue"
+OpName %9 "defaultUniformsVS"
+OpMemberName %9 0 "_ua"
+OpName %11 ""
+OpName %16 "ANGLEDepthRangeParams"
+OpMemberName %16 0 "near"
+OpMemberName %16 1 "far"
+OpMemberName %16 2 "diff"
+OpMemberName %16 3 "reserved"
+OpName %17 "ANGLEUniformBlock"
+OpMemberName %17 0 "viewport"
+OpMemberName %17 1 "clipDistancesEnabled"
+OpMemberName %17 2 "xfbActiveUnpaused"
+OpMemberName %17 3 "xfbVerticesPerInstance"
+OpMemberName %17 4 "numSamples"
+OpMemberName %17 5 "xfbBufferOffsets"
+OpMemberName %17 6 "acbBufferOffsets"
+OpMemberName %17 7 "depthRange"
+OpName %19 "ANGLEUniforms"
+OpName %20 "ANGLEXfbPosition"
+OpName %23 "gl_PerVertex"
+OpMemberName %23 0 "gl_Position"
+OpMemberName %23 1 "gl_PointSize"
+OpMemberName %23 2 "gl_ClipDistance"
+OpMemberName %23 3 "gl_CullDistance"
+OpName %25 ""
+OpName %29 "_ua"
+OpName %28 "_uf"
+OpName %33 "_uf"
+OpName %32 "_ug"
+OpName %40 "main"
+OpName %42 "param"
+OpName %50 "param"
+OpName %53 "param"
+OpDecorate %4 Location 0
+OpDecorate %5 Location 1
+OpDecorate %6 Location 2
+OpDecorate %8 Location 0
+OpMemberDecorate %9 0 Offset 0
+OpDecorate %9 Block
+OpDecorate %11 DescriptorSet 0
+OpDecorate %11 Binding 0
+OpMemberDecorate %16 0 Offset 0
+OpMemberDecorate %16 1 Offset 4
+OpMemberDecorate %16 2 Offset 8
+OpMemberDecorate %16 3 Offset 12
+OpMemberDecorate %17 0 Offset 0
+OpMemberDecorate %17 1 Offset 16
+OpMemberDecorate %17 2 Offset 20
+OpMemberDecorate %17 3 Offset 24
+OpMemberDecorate %17 4 Offset 28
+OpMemberDecorate %17 5 Offset 32
+OpMemberDecorate %17 6 Offset 48
+OpMemberDecorate %17 7 Offset 64
+OpMemberDecorate %17 2 RelaxedPrecision
+OpMemberDecorate %17 4 RelaxedPrecision
+OpDecorate %17 Block
+OpDecorate %19 DescriptorSet 0
+OpDecorate %19 Binding 1
+OpDecorate %20 Location 1
+OpMemberDecorate %23 0 BuiltIn Position
+OpMemberDecorate %23 1 BuiltIn PointSize
+OpMemberDecorate %23 2 BuiltIn ClipDistance
+OpMemberDecorate %23 3 BuiltIn CullDistance
+OpDecorate %23 Block
+OpDecorate %28 RelaxedPrecision
+OpDecorate %29 RelaxedPrecision
+OpDecorate %31 RelaxedPrecision
+OpDecorate %32 RelaxedPrecision
+OpDecorate %33 RelaxedPrecision
+OpDecorate %35 RelaxedPrecision
+OpDecorate %36 RelaxedPrecision
+OpDecorate %37 RelaxedPrecision
+OpDecorate %44 RelaxedPrecision
+OpDecorate %52 RelaxedPrecision
+OpDecorate %55 RelaxedPrecision
+OpDecorate %56 RelaxedPrecision
+%1 = OpTypeFloat 32
+%2 = OpTypeVector %1 4
+%9 = OpTypeStruct %2
+%12 = OpTypeInt 32 0
+%13 = OpTypeInt 32 1
+%14 = OpTypeVector %13 4
+%15 = OpTypeVector %12 4
+%16 = OpTypeStruct %1 %1 %1 %1
+%17 = OpTypeStruct %2 %12 %12 %13 %13 %14 %15 %16
+%21 = OpConstant %12 8
+%22 = OpTypeArray %1 %21
+%23 = OpTypeStruct %2 %1 %22 %22
+%38 = OpTypeVoid
+%45 = OpConstant %12 0
+%3 = OpTypePointer Input %2
+%7 = OpTypePointer Output %2
+%10 = OpTypePointer Uniform %9
+%18 = OpTypePointer Uniform %17
+%24 = OpTypePointer Output %23
+%26 = OpTypePointer Function %2
+%46 = OpTypePointer Uniform %2
+%27 = OpTypeFunction %2 %26
+%39 = OpTypeFunction %38
+%4 = OpVariable %3 Input
+%5 = OpVariable %3 Input
+%6 = OpVariable %3 Input
+%8 = OpVariable %7 Output
+%11 = OpVariable %10 Uniform
+%19 = OpVariable %18 Uniform
+%20 = OpVariable %7 Output
+%25 = OpVariable %24 Output
+%28 = OpFunction %2 None %27
+%29 = OpFunctionParameter %26
+%30 = OpLabel
+%31 = OpLoad %2 %29
+OpReturnValue %31
+OpFunctionEnd
+%32 = OpFunction %2 None %27
+%33 = OpFunctionParameter %26
+%34 = OpLabel
+%35 = OpLoad %2 %33
+%36 = OpLoad %2 %33
+%37 = OpFAdd %2 %35 %36
+OpReturnValue %37
+OpFunctionEnd
+%40 = OpFunction %38 None %39
+%41 = OpLabel
+%42 = OpVariable %26 Function
+%50 = OpVariable %26 Function
+%53 = OpVariable %26 Function
+%43 = OpLoad %2 %4
+OpStore %42 %43
+%44 = OpFunctionCall %2 %28 %42
+%47 = OpAccessChain %46 %11 %45
+%48 = OpLoad %2 %47
+%49 = OpFAdd %2 %44 %48
+OpStore %8 %49
+%51 = OpLoad %2 %5
+OpStore %50 %51
+%52 = OpFunctionCall %2 %32 %50
+%54 = OpLoad %2 %6
+OpStore %53 %54
+%55 = OpFunctionCall %2 %28 %53
+%56 = OpFAdd %2 %52 %55
+%57 = OpAccessChain %7 %25 %45
+OpStore %57 %56
+OpReturn
+OpFunctionEnd
+)";
+constexpr char kDst[] = R"(OpCapability Shader
+OpMemoryModel Logical GLSL450
+OpEntryPoint Vertex %40 "main" %4 %5 %6 %8 %25
+OpSource GLSL 450
+OpName %4 "_ub"
+OpName %5 "_uc"
+OpName %6 "_ud"
+OpName %8 "_ue"
+OpName %9 "defaultUniformsVS"
+OpMemberName %9 0 "_ua"
+OpName %11 ""
+OpName %16 "ANGLEDepthRangeParams"
+OpMemberName %16 0 "near"
+OpMemberName %16 1 "far"
+OpMemberName %16 2 "diff"
+OpMemberName %16 3 "reserved"
+OpName %17 "ANGLEUniformBlock"
+OpMemberName %17 0 "viewport"
+OpMemberName %17 1 "clipDistancesEnabled"
+OpMemberName %17 2 "xfbActiveUnpaused"
+OpMemberName %17 3 "xfbVerticesPerInstance"
+OpMemberName %17 4 "numSamples"
+OpMemberName %17 5 "xfbBufferOffsets"
+OpMemberName %17 6 "acbBufferOffsets"
+OpMemberName %17 7 "depthRange"
+OpName %19 "ANGLEUniforms"
+OpName %23 "gl_PerVertex"
+OpMemberName %23 0 "gl_Position"
+OpName %25 ""
+OpName %29 "_ua"
+OpName %28 "_uf"
+OpName %33 "_uf"
+OpName %32 "_ug"
+OpName %40 "main"
+OpName %42 "param"
+OpName %50 "param"
+OpName %53 "param"
+OpDecorate %4 Location 1
+OpDecorate %5 Location 2
+OpDecorate %6 Location 0
+OpDecorate %8 Location 1
+OpMemberDecorate %9 0 Offset 0
+OpDecorate %9 Block
+OpDecorate %11 DescriptorSet 0
+OpDecorate %11 Binding 1
+OpMemberDecorate %16 0 Offset 0
+OpMemberDecorate %16 1 Offset 4
+OpMemberDecorate %16 2 Offset 8
+OpMemberDecorate %16 3 Offset 12
+OpMemberDecorate %17 0 Offset 0
+OpMemberDecorate %17 1 Offset 16
+OpMemberDecorate %17 2 Offset 20
+OpMemberDecorate %17 3 Offset 24
+OpMemberDecorate %17 4 Offset 28
+OpMemberDecorate %17 5 Offset 32
+OpMemberDecorate %17 6 Offset 48
+OpMemberDecorate %17 7 Offset 64
+OpMemberDecorate %17 2 RelaxedPrecision
+OpMemberDecorate %17 4 RelaxedPrecision
+OpDecorate %17 Block
+OpDecorate %19 DescriptorSet 2
+OpDecorate %19 Binding 0
+OpMemberDecorate %23 0 BuiltIn Position
+OpDecorate %23 Block
+OpDecorate %28 RelaxedPrecision
+OpDecorate %29 RelaxedPrecision
+OpDecorate %31 RelaxedPrecision
+OpDecorate %32 RelaxedPrecision
+OpDecorate %33 RelaxedPrecision
+OpDecorate %35 RelaxedPrecision
+OpDecorate %36 RelaxedPrecision
+OpDecorate %37 RelaxedPrecision
+OpDecorate %44 RelaxedPrecision
+OpDecorate %52 RelaxedPrecision
+OpDecorate %55 RelaxedPrecision
+OpDecorate %56 RelaxedPrecision
+%1 = OpTypeFloat 32
+%2 = OpTypeVector %1 4
+%9 = OpTypeStruct %2
+%12 = OpTypeInt 32 0
+%13 = OpTypeInt 32 1
+%14 = OpTypeVector %13 4
+%15 = OpTypeVector %12 4
+%16 = OpTypeStruct %1 %1 %1 %1
+%17 = OpTypeStruct %2 %12 %12 %13 %13 %14 %15 %16
+%21 = OpConstant %12 8
+%22 = OpTypeArray %1 %21
+%23 = OpTypeStruct %2
+%38 = OpTypeVoid
+%45 = OpConstant %12 0
+%58 = OpTypePointer Private %2
+%3 = OpTypePointer Input %2
+%59 = OpTypePointer Private %2
+%7 = OpTypePointer Output %2
+%10 = OpTypePointer Uniform %9
+%18 = OpTypePointer Uniform %17
+%24 = OpTypePointer Output %23
+%26 = OpTypePointer Function %2
+%46 = OpTypePointer Uniform %2
+%27 = OpTypeFunction %2 %26
+%39 = OpTypeFunction %38
+%4 = OpVariable %3 Input
+%5 = OpVariable %3 Input
+%6 = OpVariable %3 Input
+%8 = OpVariable %7 Output
+%11 = OpVariable %10 Uniform
+%19 = OpVariable %18 Uniform
+%20 = OpVariable %59 Private
+%25 = OpVariable %24 Output
+%60 = OpConstant %13 0
+%61 = OpConstant %1 0.5
+%28 = OpFunction %2 None %27
+%29 = OpFunctionParameter %26
+%30 = OpLabel
+%31 = OpLoad %2 %29
+OpReturnValue %31
+OpFunctionEnd
+%32 = OpFunction %2 None %27
+%33 = OpFunctionParameter %26
+%34 = OpLabel
+%35 = OpLoad %2 %33
+%36 = OpLoad %2 %33
+%37 = OpFAdd %2 %35 %36
+OpReturnValue %37
+OpFunctionEnd
+%40 = OpFunction %38 None %39
+%41 = OpLabel
+%42 = OpVariable %26 Function
+%50 = OpVariable %26 Function
+%53 = OpVariable %26 Function
+%43 = OpLoad %2 %4
+OpStore %42 %43
+%44 = OpFunctionCall %2 %28 %42
+%47 = OpAccessChain %46 %11 %45
+%48 = OpLoad %2 %47
+%49 = OpFAdd %2 %44 %48
+OpStore %8 %49
+%51 = OpLoad %2 %5
+OpStore %50 %51
+%52 = OpFunctionCall %2 %32 %50
+%54 = OpLoad %2 %6
+OpStore %53 %54
+%55 = OpFunctionCall %2 %28 %53
+%56 = OpFAdd %2 %52 %55
+%57 = OpAccessChain %7 %25 %45
+OpStore %57 %56
+%62 = OpAccessChain %7 %25 %60
+%63 = OpLoad %2 %62
+%64 = OpCompositeExtract %1 %63 0
+%65 = OpCompositeExtract %1 %63 1
+%66 = OpCompositeExtract %1 %63 2
+%67 = OpCompositeExtract %1 %63 3
+%69 = OpFNegate %1 %64
+%70 = OpFAdd %1 %66 %67
+%71 = OpFMul %1 %70 %61
+%68 = OpCompositeConstruct %2 %65 %69 %71 %67
+OpStore %62 %68
+OpReturn
+OpFunctionEnd
+)";
+
+TEST(DiffTest, DifferentDecorationsVertex) {
+  constexpr char kDiff[] = R"( ; SPIR-V
+ ; Version: 1.6
+ ; Generator: Khronos SPIR-V Tools Assembler; 0
+-; Bound: 58
++; Bound: 73
+ ; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+-OpEntryPoint Vertex %40 "main" %4 %5 %6 %8 %20 %25
++OpEntryPoint Vertex %40 "main" %4 %5 %6 %8 %25
+ OpSource GLSL 450
+ OpName %4 "_ub"
+ OpName %5 "_uc"
+ OpName %6 "_ud"
+ OpName %8 "_ue"
+ OpName %9 "defaultUniformsVS"
+ OpMemberName %9 0 "_ua"
+ OpName %11 ""
+ OpName %16 "ANGLEDepthRangeParams"
+ OpMemberName %16 0 "near"
+ OpMemberName %16 1 "far"
+ OpMemberName %16 2 "diff"
+ OpMemberName %16 3 "reserved"
+ OpName %17 "ANGLEUniformBlock"
+ OpMemberName %17 0 "viewport"
+ OpMemberName %17 1 "clipDistancesEnabled"
+ OpMemberName %17 2 "xfbActiveUnpaused"
+ OpMemberName %17 3 "xfbVerticesPerInstance"
+ OpMemberName %17 4 "numSamples"
+ OpMemberName %17 5 "xfbBufferOffsets"
+ OpMemberName %17 6 "acbBufferOffsets"
+ OpMemberName %17 7 "depthRange"
+ OpName %19 "ANGLEUniforms"
+-OpName %20 "ANGLEXfbPosition"
+ OpName %23 "gl_PerVertex"
+ OpMemberName %23 0 "gl_Position"
+-OpMemberName %23 1 "gl_PointSize"
+-OpMemberName %23 2 "gl_ClipDistance"
+-OpMemberName %23 3 "gl_CullDistance"
+ OpName %25 ""
+ OpName %29 "_ua"
+ OpName %28 "_uf"
+ OpName %33 "_uf"
+ OpName %32 "_ug"
+ OpName %40 "main"
+ OpName %42 "param"
+ OpName %50 "param"
+ OpName %53 "param"
+-OpDecorate %4 Location 0
++OpDecorate %4 Location 1
+-OpDecorate %5 Location 1
++OpDecorate %5 Location 2
+-OpDecorate %6 Location 2
++OpDecorate %6 Location 0
+-OpDecorate %8 Location 0
++OpDecorate %8 Location 1
+ OpMemberDecorate %9 0 Offset 0
+ OpDecorate %9 Block
+ OpDecorate %11 DescriptorSet 0
+-OpDecorate %11 Binding 0
++OpDecorate %11 Binding 1
+ OpMemberDecorate %16 0 Offset 0
+ OpMemberDecorate %16 1 Offset 4
+ OpMemberDecorate %16 2 Offset 8
+ OpMemberDecorate %16 3 Offset 12
+ OpMemberDecorate %17 0 Offset 0
+ OpMemberDecorate %17 1 Offset 16
+ OpMemberDecorate %17 2 Offset 20
+ OpMemberDecorate %17 3 Offset 24
+ OpMemberDecorate %17 4 Offset 28
+ OpMemberDecorate %17 5 Offset 32
+ OpMemberDecorate %17 6 Offset 48
+ OpMemberDecorate %17 7 Offset 64
+ OpMemberDecorate %17 2 RelaxedPrecision
+ OpMemberDecorate %17 4 RelaxedPrecision
+ OpDecorate %17 Block
+-OpDecorate %19 DescriptorSet 0
++OpDecorate %19 DescriptorSet 2
+-OpDecorate %19 Binding 1
++OpDecorate %19 Binding 0
+-OpDecorate %20 Location 1
+ OpMemberDecorate %23 0 BuiltIn Position
+-OpMemberDecorate %23 1 BuiltIn PointSize
+-OpMemberDecorate %23 2 BuiltIn ClipDistance
+-OpMemberDecorate %23 3 BuiltIn CullDistance
+ OpDecorate %23 Block
+ OpDecorate %28 RelaxedPrecision
+ OpDecorate %29 RelaxedPrecision
+ OpDecorate %31 RelaxedPrecision
+ OpDecorate %32 RelaxedPrecision
+ OpDecorate %33 RelaxedPrecision
+ OpDecorate %35 RelaxedPrecision
+ OpDecorate %36 RelaxedPrecision
+ OpDecorate %37 RelaxedPrecision
+ OpDecorate %44 RelaxedPrecision
+ OpDecorate %52 RelaxedPrecision
+ OpDecorate %55 RelaxedPrecision
+ OpDecorate %56 RelaxedPrecision
+ %1 = OpTypeFloat 32
+ %2 = OpTypeVector %1 4
+ %9 = OpTypeStruct %2
+ %12 = OpTypeInt 32 0
+ %13 = OpTypeInt 32 1
+ %14 = OpTypeVector %13 4
+ %15 = OpTypeVector %12 4
+ %16 = OpTypeStruct %1 %1 %1 %1
+ %17 = OpTypeStruct %2 %12 %12 %13 %13 %14 %15 %16
+ %21 = OpConstant %12 8
+ %22 = OpTypeArray %1 %21
+-%23 = OpTypeStruct %2 %1 %22 %22
++%23 = OpTypeStruct %2
+ %38 = OpTypeVoid
+ %45 = OpConstant %12 0
++%59 = OpTypePointer Private %2
+ %3 = OpTypePointer Input %2
++%60 = OpTypePointer Private %2
+ %7 = OpTypePointer Output %2
+ %10 = OpTypePointer Uniform %9
+ %18 = OpTypePointer Uniform %17
+ %24 = OpTypePointer Output %23
+ %26 = OpTypePointer Function %2
+ %46 = OpTypePointer Uniform %2
+ %27 = OpTypeFunction %2 %26
+ %39 = OpTypeFunction %38
+ %4 = OpVariable %3 Input
+ %5 = OpVariable %3 Input
+ %6 = OpVariable %3 Input
+ %8 = OpVariable %7 Output
+ %11 = OpVariable %10 Uniform
+ %19 = OpVariable %18 Uniform
+-%20 = OpVariable %7 Output
++%58 = OpVariable %60 Private
+ %25 = OpVariable %24 Output
++%61 = OpConstant %13 0
++%62 = OpConstant %1 0.5
+ %28 = OpFunction %2 None %27
+ %29 = OpFunctionParameter %26
+ %30 = OpLabel
+ %31 = OpLoad %2 %29
+ OpReturnValue %31
+ OpFunctionEnd
+ %32 = OpFunction %2 None %27
+ %33 = OpFunctionParameter %26
+ %34 = OpLabel
+ %35 = OpLoad %2 %33
+ %36 = OpLoad %2 %33
+ %37 = OpFAdd %2 %35 %36
+ OpReturnValue %37
+ OpFunctionEnd
+ %40 = OpFunction %38 None %39
+ %41 = OpLabel
+ %42 = OpVariable %26 Function
+ %50 = OpVariable %26 Function
+ %53 = OpVariable %26 Function
+ %43 = OpLoad %2 %4
+ OpStore %42 %43
+ %44 = OpFunctionCall %2 %28 %42
+ %47 = OpAccessChain %46 %11 %45
+ %48 = OpLoad %2 %47
+ %49 = OpFAdd %2 %44 %48
+ OpStore %8 %49
+ %51 = OpLoad %2 %5
+ OpStore %50 %51
+ %52 = OpFunctionCall %2 %32 %50
+ %54 = OpLoad %2 %6
+ OpStore %53 %54
+ %55 = OpFunctionCall %2 %28 %53
+ %56 = OpFAdd %2 %52 %55
+ %57 = OpAccessChain %7 %25 %45
+ OpStore %57 %56
++%63 = OpAccessChain %7 %25 %61
++%64 = OpLoad %2 %63
++%65 = OpCompositeExtract %1 %64 0
++%66 = OpCompositeExtract %1 %64 1
++%67 = OpCompositeExtract %1 %64 2
++%68 = OpCompositeExtract %1 %64 3
++%70 = OpFNegate %1 %65
++%71 = OpFAdd %1 %67 %68
++%72 = OpFMul %1 %71 %62
++%69 = OpCompositeConstruct %2 %66 %70 %72 %68
++OpStore %63 %69
+ OpReturn
+ OpFunctionEnd
+)";
+  Options options;
+  DoStringDiffTest(kSrc, kDst, kDiff, options);
+}
+
+TEST(DiffTest, DifferentDecorationsVertexNoDebug) {
+  constexpr char kSrcNoDebug[] = R"(OpCapability Shader
+OpMemoryModel Logical GLSL450
+OpEntryPoint Vertex %40 "main" %4 %5 %6 %8 %20 %25
+OpSource GLSL 450
+OpDecorate %4 Location 0
+OpDecorate %5 Location 1
+OpDecorate %6 Location 2
+OpDecorate %8 Location 0
+OpMemberDecorate %9 0 Offset 0
+OpDecorate %9 Block
+OpDecorate %11 DescriptorSet 0
+OpDecorate %11 Binding 0
+OpMemberDecorate %16 0 Offset 0
+OpMemberDecorate %16 1 Offset 4
+OpMemberDecorate %16 2 Offset 8
+OpMemberDecorate %16 3 Offset 12
+OpMemberDecorate %17 0 Offset 0
+OpMemberDecorate %17 1 Offset 16
+OpMemberDecorate %17 2 Offset 20
+OpMemberDecorate %17 3 Offset 24
+OpMemberDecorate %17 4 Offset 28
+OpMemberDecorate %17 5 Offset 32
+OpMemberDecorate %17 6 Offset 48
+OpMemberDecorate %17 7 Offset 64
+OpMemberDecorate %17 2 RelaxedPrecision
+OpMemberDecorate %17 4 RelaxedPrecision
+OpDecorate %17 Block
+OpDecorate %19 DescriptorSet 0
+OpDecorate %19 Binding 1
+OpDecorate %20 Location 1
+OpMemberDecorate %23 0 BuiltIn Position
+OpMemberDecorate %23 1 BuiltIn PointSize
+OpMemberDecorate %23 2 BuiltIn ClipDistance
+OpMemberDecorate %23 3 BuiltIn CullDistance
+OpDecorate %23 Block
+OpDecorate %28 RelaxedPrecision
+OpDecorate %29 RelaxedPrecision
+OpDecorate %31 RelaxedPrecision
+OpDecorate %32 RelaxedPrecision
+OpDecorate %33 RelaxedPrecision
+OpDecorate %35 RelaxedPrecision
+OpDecorate %36 RelaxedPrecision
+OpDecorate %37 RelaxedPrecision
+OpDecorate %44 RelaxedPrecision
+OpDecorate %52 RelaxedPrecision
+OpDecorate %55 RelaxedPrecision
+OpDecorate %56 RelaxedPrecision
+%1 = OpTypeFloat 32
+%2 = OpTypeVector %1 4
+%9 = OpTypeStruct %2
+%12 = OpTypeInt 32 0
+%13 = OpTypeInt 32 1
+%14 = OpTypeVector %13 4
+%15 = OpTypeVector %12 4
+%16 = OpTypeStruct %1 %1 %1 %1
+%17 = OpTypeStruct %2 %12 %12 %13 %13 %14 %15 %16
+%21 = OpConstant %12 8
+%22 = OpTypeArray %1 %21
+%23 = OpTypeStruct %2 %1 %22 %22
+%38 = OpTypeVoid
+%45 = OpConstant %12 0
+%3 = OpTypePointer Input %2
+%7 = OpTypePointer Output %2
+%10 = OpTypePointer Uniform %9
+%18 = OpTypePointer Uniform %17
+%24 = OpTypePointer Output %23
+%26 = OpTypePointer Function %2
+%46 = OpTypePointer Uniform %2
+%27 = OpTypeFunction %2 %26
+%39 = OpTypeFunction %38
+%4 = OpVariable %3 Input
+%5 = OpVariable %3 Input
+%6 = OpVariable %3 Input
+%8 = OpVariable %7 Output
+%11 = OpVariable %10 Uniform
+%19 = OpVariable %18 Uniform
+%20 = OpVariable %7 Output
+%25 = OpVariable %24 Output
+%28 = OpFunction %2 None %27
+%29 = OpFunctionParameter %26
+%30 = OpLabel
+%31 = OpLoad %2 %29
+OpReturnValue %31
+OpFunctionEnd
+%32 = OpFunction %2 None %27
+%33 = OpFunctionParameter %26
+%34 = OpLabel
+%35 = OpLoad %2 %33
+%36 = OpLoad %2 %33
+%37 = OpFAdd %2 %35 %36
+OpReturnValue %37
+OpFunctionEnd
+%40 = OpFunction %38 None %39
+%41 = OpLabel
+%42 = OpVariable %26 Function
+%50 = OpVariable %26 Function
+%53 = OpVariable %26 Function
+%43 = OpLoad %2 %4
+OpStore %42 %43
+%44 = OpFunctionCall %2 %28 %42
+%47 = OpAccessChain %46 %11 %45
+%48 = OpLoad %2 %47
+%49 = OpFAdd %2 %44 %48
+OpStore %8 %49
+%51 = OpLoad %2 %5
+OpStore %50 %51
+%52 = OpFunctionCall %2 %32 %50
+%54 = OpLoad %2 %6
+OpStore %53 %54
+%55 = OpFunctionCall %2 %28 %53
+%56 = OpFAdd %2 %52 %55
+%57 = OpAccessChain %7 %25 %45
+OpStore %57 %56
+OpReturn
+OpFunctionEnd
+
+)";
+  constexpr char kDstNoDebug[] = R"(OpCapability Shader
+OpMemoryModel Logical GLSL450
+OpEntryPoint Vertex %40 "main" %4 %5 %6 %8 %25
+OpSource GLSL 450
+OpDecorate %4 Location 1
+OpDecorate %5 Location 2
+OpDecorate %6 Location 0
+OpDecorate %8 Location 1
+OpMemberDecorate %9 0 Offset 0
+OpDecorate %9 Block
+OpDecorate %11 DescriptorSet 0
+OpDecorate %11 Binding 1
+OpMemberDecorate %16 0 Offset 0
+OpMemberDecorate %16 1 Offset 4
+OpMemberDecorate %16 2 Offset 8
+OpMemberDecorate %16 3 Offset 12
+OpMemberDecorate %17 0 Offset 0
+OpMemberDecorate %17 1 Offset 16
+OpMemberDecorate %17 2 Offset 20
+OpMemberDecorate %17 3 Offset 24
+OpMemberDecorate %17 4 Offset 28
+OpMemberDecorate %17 5 Offset 32
+OpMemberDecorate %17 6 Offset 48
+OpMemberDecorate %17 7 Offset 64
+OpMemberDecorate %17 2 RelaxedPrecision
+OpMemberDecorate %17 4 RelaxedPrecision
+OpDecorate %17 Block
+OpDecorate %19 DescriptorSet 2
+OpDecorate %19 Binding 0
+OpMemberDecorate %23 0 BuiltIn Position
+OpDecorate %23 Block
+OpDecorate %28 RelaxedPrecision
+OpDecorate %29 RelaxedPrecision
+OpDecorate %31 RelaxedPrecision
+OpDecorate %32 RelaxedPrecision
+OpDecorate %33 RelaxedPrecision
+OpDecorate %35 RelaxedPrecision
+OpDecorate %36 RelaxedPrecision
+OpDecorate %37 RelaxedPrecision
+OpDecorate %44 RelaxedPrecision
+OpDecorate %52 RelaxedPrecision
+OpDecorate %55 RelaxedPrecision
+OpDecorate %56 RelaxedPrecision
+%1 = OpTypeFloat 32
+%2 = OpTypeVector %1 4
+%9 = OpTypeStruct %2
+%12 = OpTypeInt 32 0
+%13 = OpTypeInt 32 1
+%14 = OpTypeVector %13 4
+%15 = OpTypeVector %12 4
+%16 = OpTypeStruct %1 %1 %1 %1
+%17 = OpTypeStruct %2 %12 %12 %13 %13 %14 %15 %16
+%21 = OpConstant %12 8
+%22 = OpTypeArray %1 %21
+%23 = OpTypeStruct %2
+%38 = OpTypeVoid
+%45 = OpConstant %12 0
+%58 = OpTypePointer Private %2
+%3 = OpTypePointer Input %2
+%59 = OpTypePointer Private %2
+%7 = OpTypePointer Output %2
+%10 = OpTypePointer Uniform %9
+%18 = OpTypePointer Uniform %17
+%24 = OpTypePointer Output %23
+%26 = OpTypePointer Function %2
+%46 = OpTypePointer Uniform %2
+%27 = OpTypeFunction %2 %26
+%39 = OpTypeFunction %38
+%4 = OpVariable %3 Input
+%5 = OpVariable %3 Input
+%6 = OpVariable %3 Input
+%8 = OpVariable %7 Output
+%11 = OpVariable %10 Uniform
+%19 = OpVariable %18 Uniform
+%20 = OpVariable %59 Private
+%25 = OpVariable %24 Output
+%60 = OpConstant %13 0
+%61 = OpConstant %1 0.5
+%28 = OpFunction %2 None %27
+%29 = OpFunctionParameter %26
+%30 = OpLabel
+%31 = OpLoad %2 %29
+OpReturnValue %31
+OpFunctionEnd
+%32 = OpFunction %2 None %27
+%33 = OpFunctionParameter %26
+%34 = OpLabel
+%35 = OpLoad %2 %33
+%36 = OpLoad %2 %33
+%37 = OpFAdd %2 %35 %36
+OpReturnValue %37
+OpFunctionEnd
+%40 = OpFunction %38 None %39
+%41 = OpLabel
+%42 = OpVariable %26 Function
+%50 = OpVariable %26 Function
+%53 = OpVariable %26 Function
+%43 = OpLoad %2 %4
+OpStore %42 %43
+%44 = OpFunctionCall %2 %28 %42
+%47 = OpAccessChain %46 %11 %45
+%48 = OpLoad %2 %47
+%49 = OpFAdd %2 %44 %48
+OpStore %8 %49
+%51 = OpLoad %2 %5
+OpStore %50 %51
+%52 = OpFunctionCall %2 %32 %50
+%54 = OpLoad %2 %6
+OpStore %53 %54
+%55 = OpFunctionCall %2 %28 %53
+%56 = OpFAdd %2 %52 %55
+%57 = OpAccessChain %7 %25 %45
+OpStore %57 %56
+%62 = OpAccessChain %7 %25 %60
+%63 = OpLoad %2 %62
+%64 = OpCompositeExtract %1 %63 0
+%65 = OpCompositeExtract %1 %63 1
+%66 = OpCompositeExtract %1 %63 2
+%67 = OpCompositeExtract %1 %63 3
+%69 = OpFNegate %1 %64
+%70 = OpFAdd %1 %66 %67
+%71 = OpFMul %1 %70 %61
+%68 = OpCompositeConstruct %2 %65 %69 %71 %67
+OpStore %62 %68
+OpReturn
+OpFunctionEnd
+)";
+  constexpr char kDiff[] = R"( ; SPIR-V
+ ; Version: 1.6
+ ; Generator: Khronos SPIR-V Tools Assembler; 0
+-; Bound: 58
++; Bound: 79
+ ; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+-OpEntryPoint Vertex %40 "main" %4 %5 %6 %8 %20 %25
++OpEntryPoint Vertex %40 "main" %5 %6 %4 %20 %25
+ OpSource GLSL 450
+ OpDecorate %4 Location 0
+ OpDecorate %5 Location 1
+ OpDecorate %6 Location 2
+-OpDecorate %8 Location 0
+ OpMemberDecorate %9 0 Offset 0
+ OpDecorate %9 Block
+-OpDecorate %11 DescriptorSet 0
++OpDecorate %11 DescriptorSet 2
+ OpDecorate %11 Binding 0
+ OpMemberDecorate %16 0 Offset 0
+ OpMemberDecorate %16 1 Offset 4
+ OpMemberDecorate %16 2 Offset 8
+ OpMemberDecorate %16 3 Offset 12
+ OpMemberDecorate %17 0 Offset 0
+ OpMemberDecorate %17 1 Offset 16
+ OpMemberDecorate %17 2 Offset 20
+ OpMemberDecorate %17 3 Offset 24
+ OpMemberDecorate %17 4 Offset 28
+ OpMemberDecorate %17 5 Offset 32
+ OpMemberDecorate %17 6 Offset 48
+ OpMemberDecorate %17 7 Offset 64
+ OpMemberDecorate %17 2 RelaxedPrecision
+ OpMemberDecorate %17 4 RelaxedPrecision
+ OpDecorate %17 Block
+ OpDecorate %19 DescriptorSet 0
+ OpDecorate %19 Binding 1
+ OpDecorate %20 Location 1
+ OpMemberDecorate %23 0 BuiltIn Position
+-OpMemberDecorate %23 1 BuiltIn PointSize
+-OpMemberDecorate %23 2 BuiltIn ClipDistance
+-OpMemberDecorate %23 3 BuiltIn CullDistance
+ OpDecorate %23 Block
+ OpDecorate %28 RelaxedPrecision
+-OpDecorate %29 RelaxedPrecision
++OpDecorate %59 RelaxedPrecision
+ OpDecorate %31 RelaxedPrecision
+ OpDecorate %32 RelaxedPrecision
+-OpDecorate %33 RelaxedPrecision
++OpDecorate %60 RelaxedPrecision
+ OpDecorate %35 RelaxedPrecision
+ OpDecorate %36 RelaxedPrecision
+ OpDecorate %37 RelaxedPrecision
+ OpDecorate %44 RelaxedPrecision
+ OpDecorate %52 RelaxedPrecision
+ OpDecorate %55 RelaxedPrecision
+ OpDecorate %56 RelaxedPrecision
+ %1 = OpTypeFloat 32
+ %2 = OpTypeVector %1 4
+ %9 = OpTypeStruct %2
+ %12 = OpTypeInt 32 0
+ %13 = OpTypeInt 32 1
+ %14 = OpTypeVector %13 4
+ %15 = OpTypeVector %12 4
+ %16 = OpTypeStruct %1 %1 %1 %1
+ %17 = OpTypeStruct %2 %12 %12 %13 %13 %14 %15 %16
+ %21 = OpConstant %12 8
+ %22 = OpTypeArray %1 %21
+-%23 = OpTypeStruct %2 %1 %22 %22
++%23 = OpTypeStruct %2
+ %38 = OpTypeVoid
+ %45 = OpConstant %12 0
++%65 = OpTypePointer Private %2
+ %3 = OpTypePointer Input %2
++%66 = OpTypePointer Private %2
+ %7 = OpTypePointer Output %2
+ %10 = OpTypePointer Uniform %9
+ %18 = OpTypePointer Uniform %17
+ %24 = OpTypePointer Output %23
+ %26 = OpTypePointer Function %2
+ %46 = OpTypePointer Uniform %2
+ %27 = OpTypeFunction %2 %26
+ %39 = OpTypeFunction %38
+ %4 = OpVariable %3 Input
+ %5 = OpVariable %3 Input
+ %6 = OpVariable %3 Input
+-%8 = OpVariable %7 Output
+-%11 = OpVariable %10 Uniform
++%11 = OpVariable %18 Uniform
+-%19 = OpVariable %18 Uniform
++%19 = OpVariable %10 Uniform
+ %20 = OpVariable %7 Output
++%58 = OpVariable %66 Private
+ %25 = OpVariable %24 Output
++%67 = OpConstant %13 0
++%68 = OpConstant %1 0.5
+ %28 = OpFunction %2 None %27
+-%29 = OpFunctionParameter %26
++%59 = OpFunctionParameter %26
+ %30 = OpLabel
+-%31 = OpLoad %2 %29
++%31 = OpLoad %2 %59
+ OpReturnValue %31
+ OpFunctionEnd
+ %32 = OpFunction %2 None %27
+-%33 = OpFunctionParameter %26
++%60 = OpFunctionParameter %26
+ %34 = OpLabel
+-%35 = OpLoad %2 %33
++%35 = OpLoad %2 %60
+-%36 = OpLoad %2 %33
++%36 = OpLoad %2 %60
+ %37 = OpFAdd %2 %35 %36
+ OpReturnValue %37
+ OpFunctionEnd
+ %40 = OpFunction %38 None %39
+ %41 = OpLabel
+ %42 = OpVariable %26 Function
+ %50 = OpVariable %26 Function
+ %53 = OpVariable %26 Function
+-%43 = OpLoad %2 %4
++%61 = OpLoad %2 %5
+-OpStore %42 %43
++OpStore %42 %61
+ %44 = OpFunctionCall %2 %28 %42
+-%47 = OpAccessChain %46 %11 %45
++%62 = OpAccessChain %46 %19 %45
+-%48 = OpLoad %2 %47
++%48 = OpLoad %2 %62
+ %49 = OpFAdd %2 %44 %48
+-OpStore %8 %49
++OpStore %20 %49
+-%51 = OpLoad %2 %5
++%63 = OpLoad %2 %6
+-OpStore %50 %51
++OpStore %50 %63
+ %52 = OpFunctionCall %2 %32 %50
+-%54 = OpLoad %2 %6
++%64 = OpLoad %2 %4
+-OpStore %53 %54
++OpStore %53 %64
+ %55 = OpFunctionCall %2 %28 %53
+ %56 = OpFAdd %2 %52 %55
+ %57 = OpAccessChain %7 %25 %45
+ OpStore %57 %56
++%69 = OpAccessChain %7 %25 %67
++%70 = OpLoad %2 %69
++%71 = OpCompositeExtract %1 %70 0
++%72 = OpCompositeExtract %1 %70 1
++%73 = OpCompositeExtract %1 %70 2
++%74 = OpCompositeExtract %1 %70 3
++%76 = OpFNegate %1 %71
++%77 = OpFAdd %1 %73 %74
++%78 = OpFMul %1 %77 %68
++%75 = OpCompositeConstruct %2 %72 %76 %78 %74
++OpStore %69 %75
+ OpReturn
+ OpFunctionEnd
+)";
+  Options options;
+  DoStringDiffTest(kSrcNoDebug, kDstNoDebug, kDiff, options);
+}
+
+TEST(DiffTest, DifferentDecorationsVertexIgnoreSetBinding) {
+  constexpr char kDiff[] = R"( ; SPIR-V
+ ; Version: 1.6
+ ; Generator: Khronos SPIR-V Tools Assembler; 0
+-; Bound: 58
++; Bound: 73
+ ; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+-OpEntryPoint Vertex %40 "main" %4 %5 %6 %8 %20 %25
++OpEntryPoint Vertex %40 "main" %4 %5 %6 %8 %25
+ OpSource GLSL 450
+ OpName %4 "_ub"
+ OpName %5 "_uc"
+ OpName %6 "_ud"
+ OpName %8 "_ue"
+ OpName %9 "defaultUniformsVS"
+ OpMemberName %9 0 "_ua"
+ OpName %11 ""
+ OpName %16 "ANGLEDepthRangeParams"
+ OpMemberName %16 0 "near"
+ OpMemberName %16 1 "far"
+ OpMemberName %16 2 "diff"
+ OpMemberName %16 3 "reserved"
+ OpName %17 "ANGLEUniformBlock"
+ OpMemberName %17 0 "viewport"
+ OpMemberName %17 1 "clipDistancesEnabled"
+ OpMemberName %17 2 "xfbActiveUnpaused"
+ OpMemberName %17 3 "xfbVerticesPerInstance"
+ OpMemberName %17 4 "numSamples"
+ OpMemberName %17 5 "xfbBufferOffsets"
+ OpMemberName %17 6 "acbBufferOffsets"
+ OpMemberName %17 7 "depthRange"
+ OpName %19 "ANGLEUniforms"
+-OpName %20 "ANGLEXfbPosition"
+ OpName %23 "gl_PerVertex"
+ OpMemberName %23 0 "gl_Position"
+-OpMemberName %23 1 "gl_PointSize"
+-OpMemberName %23 2 "gl_ClipDistance"
+-OpMemberName %23 3 "gl_CullDistance"
+ OpName %25 ""
+ OpName %29 "_ua"
+ OpName %28 "_uf"
+ OpName %33 "_uf"
+ OpName %32 "_ug"
+ OpName %40 "main"
+ OpName %42 "param"
+ OpName %50 "param"
+ OpName %53 "param"
+-OpDecorate %4 Location 0
++OpDecorate %4 Location 1
+-OpDecorate %5 Location 1
++OpDecorate %5 Location 2
+-OpDecorate %6 Location 2
++OpDecorate %6 Location 0
+-OpDecorate %8 Location 0
++OpDecorate %8 Location 1
+ OpMemberDecorate %9 0 Offset 0
+ OpDecorate %9 Block
+ OpDecorate %11 DescriptorSet 0
+-OpDecorate %11 Binding 0
++OpDecorate %11 Binding 1
+ OpMemberDecorate %16 0 Offset 0
+ OpMemberDecorate %16 1 Offset 4
+ OpMemberDecorate %16 2 Offset 8
+ OpMemberDecorate %16 3 Offset 12
+ OpMemberDecorate %17 0 Offset 0
+ OpMemberDecorate %17 1 Offset 16
+ OpMemberDecorate %17 2 Offset 20
+ OpMemberDecorate %17 3 Offset 24
+ OpMemberDecorate %17 4 Offset 28
+ OpMemberDecorate %17 5 Offset 32
+ OpMemberDecorate %17 6 Offset 48
+ OpMemberDecorate %17 7 Offset 64
+ OpMemberDecorate %17 2 RelaxedPrecision
+ OpMemberDecorate %17 4 RelaxedPrecision
+ OpDecorate %17 Block
+-OpDecorate %19 DescriptorSet 0
++OpDecorate %19 DescriptorSet 2
+-OpDecorate %19 Binding 1
++OpDecorate %19 Binding 0
+-OpDecorate %20 Location 1
+ OpMemberDecorate %23 0 BuiltIn Position
+-OpMemberDecorate %23 1 BuiltIn PointSize
+-OpMemberDecorate %23 2 BuiltIn ClipDistance
+-OpMemberDecorate %23 3 BuiltIn CullDistance
+ OpDecorate %23 Block
+ OpDecorate %28 RelaxedPrecision
+ OpDecorate %29 RelaxedPrecision
+ OpDecorate %31 RelaxedPrecision
+ OpDecorate %32 RelaxedPrecision
+ OpDecorate %33 RelaxedPrecision
+ OpDecorate %35 RelaxedPrecision
+ OpDecorate %36 RelaxedPrecision
+ OpDecorate %37 RelaxedPrecision
+ OpDecorate %44 RelaxedPrecision
+ OpDecorate %52 RelaxedPrecision
+ OpDecorate %55 RelaxedPrecision
+ OpDecorate %56 RelaxedPrecision
+ %1 = OpTypeFloat 32
+ %2 = OpTypeVector %1 4
+ %9 = OpTypeStruct %2
+ %12 = OpTypeInt 32 0
+ %13 = OpTypeInt 32 1
+ %14 = OpTypeVector %13 4
+ %15 = OpTypeVector %12 4
+ %16 = OpTypeStruct %1 %1 %1 %1
+ %17 = OpTypeStruct %2 %12 %12 %13 %13 %14 %15 %16
+ %21 = OpConstant %12 8
+ %22 = OpTypeArray %1 %21
+-%23 = OpTypeStruct %2 %1 %22 %22
++%23 = OpTypeStruct %2
+ %38 = OpTypeVoid
+ %45 = OpConstant %12 0
++%59 = OpTypePointer Private %2
+ %3 = OpTypePointer Input %2
++%60 = OpTypePointer Private %2
+ %7 = OpTypePointer Output %2
+ %10 = OpTypePointer Uniform %9
+ %18 = OpTypePointer Uniform %17
+ %24 = OpTypePointer Output %23
+ %26 = OpTypePointer Function %2
+ %46 = OpTypePointer Uniform %2
+ %27 = OpTypeFunction %2 %26
+ %39 = OpTypeFunction %38
+ %4 = OpVariable %3 Input
+ %5 = OpVariable %3 Input
+ %6 = OpVariable %3 Input
+ %8 = OpVariable %7 Output
+ %11 = OpVariable %10 Uniform
+ %19 = OpVariable %18 Uniform
+-%20 = OpVariable %7 Output
++%58 = OpVariable %60 Private
+ %25 = OpVariable %24 Output
++%61 = OpConstant %13 0
++%62 = OpConstant %1 0.5
+ %28 = OpFunction %2 None %27
+ %29 = OpFunctionParameter %26
+ %30 = OpLabel
+ %31 = OpLoad %2 %29
+ OpReturnValue %31
+ OpFunctionEnd
+ %32 = OpFunction %2 None %27
+ %33 = OpFunctionParameter %26
+ %34 = OpLabel
+ %35 = OpLoad %2 %33
+ %36 = OpLoad %2 %33
+ %37 = OpFAdd %2 %35 %36
+ OpReturnValue %37
+ OpFunctionEnd
+ %40 = OpFunction %38 None %39
+ %41 = OpLabel
+ %42 = OpVariable %26 Function
+ %50 = OpVariable %26 Function
+ %53 = OpVariable %26 Function
+ %43 = OpLoad %2 %4
+ OpStore %42 %43
+ %44 = OpFunctionCall %2 %28 %42
+ %47 = OpAccessChain %46 %11 %45
+ %48 = OpLoad %2 %47
+ %49 = OpFAdd %2 %44 %48
+ OpStore %8 %49
+ %51 = OpLoad %2 %5
+ OpStore %50 %51
+ %52 = OpFunctionCall %2 %32 %50
+ %54 = OpLoad %2 %6
+ OpStore %53 %54
+ %55 = OpFunctionCall %2 %28 %53
+ %56 = OpFAdd %2 %52 %55
+ %57 = OpAccessChain %7 %25 %45
+ OpStore %57 %56
++%63 = OpAccessChain %7 %25 %61
++%64 = OpLoad %2 %63
++%65 = OpCompositeExtract %1 %64 0
++%66 = OpCompositeExtract %1 %64 1
++%67 = OpCompositeExtract %1 %64 2
++%68 = OpCompositeExtract %1 %64 3
++%70 = OpFNegate %1 %65
++%71 = OpFAdd %1 %67 %68
++%72 = OpFMul %1 %71 %62
++%69 = OpCompositeConstruct %2 %66 %70 %72 %68
++OpStore %63 %69
+ OpReturn
+ OpFunctionEnd
+)";
+  Options options;
+  options.ignore_set_binding = true;
+  DoStringDiffTest(kSrc, kDst, kDiff, options);
+}
+
+TEST(DiffTest, DifferentDecorationsVertexIgnoreSetBindingLocation) {
+  constexpr char kDiff[] = R"( ; SPIR-V
+ ; Version: 1.6
+ ; Generator: Khronos SPIR-V Tools Assembler; 0
+-; Bound: 58
++; Bound: 73
+ ; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+-OpEntryPoint Vertex %40 "main" %4 %5 %6 %8 %20 %25
++OpEntryPoint Vertex %40 "main" %4 %5 %6 %8 %25
+ OpSource GLSL 450
+ OpName %4 "_ub"
+ OpName %5 "_uc"
+ OpName %6 "_ud"
+ OpName %8 "_ue"
+ OpName %9 "defaultUniformsVS"
+ OpMemberName %9 0 "_ua"
+ OpName %11 ""
+ OpName %16 "ANGLEDepthRangeParams"
+ OpMemberName %16 0 "near"
+ OpMemberName %16 1 "far"
+ OpMemberName %16 2 "diff"
+ OpMemberName %16 3 "reserved"
+ OpName %17 "ANGLEUniformBlock"
+ OpMemberName %17 0 "viewport"
+ OpMemberName %17 1 "clipDistancesEnabled"
+ OpMemberName %17 2 "xfbActiveUnpaused"
+ OpMemberName %17 3 "xfbVerticesPerInstance"
+ OpMemberName %17 4 "numSamples"
+ OpMemberName %17 5 "xfbBufferOffsets"
+ OpMemberName %17 6 "acbBufferOffsets"
+ OpMemberName %17 7 "depthRange"
+ OpName %19 "ANGLEUniforms"
+-OpName %20 "ANGLEXfbPosition"
+ OpName %23 "gl_PerVertex"
+ OpMemberName %23 0 "gl_Position"
+-OpMemberName %23 1 "gl_PointSize"
+-OpMemberName %23 2 "gl_ClipDistance"
+-OpMemberName %23 3 "gl_CullDistance"
+ OpName %25 ""
+ OpName %29 "_ua"
+ OpName %28 "_uf"
+ OpName %33 "_uf"
+ OpName %32 "_ug"
+ OpName %40 "main"
+ OpName %42 "param"
+ OpName %50 "param"
+ OpName %53 "param"
+-OpDecorate %4 Location 0
++OpDecorate %4 Location 1
+-OpDecorate %5 Location 1
++OpDecorate %5 Location 2
+-OpDecorate %6 Location 2
++OpDecorate %6 Location 0
+-OpDecorate %8 Location 0
++OpDecorate %8 Location 1
+ OpMemberDecorate %9 0 Offset 0
+ OpDecorate %9 Block
+ OpDecorate %11 DescriptorSet 0
+-OpDecorate %11 Binding 0
++OpDecorate %11 Binding 1
+ OpMemberDecorate %16 0 Offset 0
+ OpMemberDecorate %16 1 Offset 4
+ OpMemberDecorate %16 2 Offset 8
+ OpMemberDecorate %16 3 Offset 12
+ OpMemberDecorate %17 0 Offset 0
+ OpMemberDecorate %17 1 Offset 16
+ OpMemberDecorate %17 2 Offset 20
+ OpMemberDecorate %17 3 Offset 24
+ OpMemberDecorate %17 4 Offset 28
+ OpMemberDecorate %17 5 Offset 32
+ OpMemberDecorate %17 6 Offset 48
+ OpMemberDecorate %17 7 Offset 64
+ OpMemberDecorate %17 2 RelaxedPrecision
+ OpMemberDecorate %17 4 RelaxedPrecision
+ OpDecorate %17 Block
+-OpDecorate %19 DescriptorSet 0
++OpDecorate %19 DescriptorSet 2
+-OpDecorate %19 Binding 1
++OpDecorate %19 Binding 0
+-OpDecorate %20 Location 1
+ OpMemberDecorate %23 0 BuiltIn Position
+-OpMemberDecorate %23 1 BuiltIn PointSize
+-OpMemberDecorate %23 2 BuiltIn ClipDistance
+-OpMemberDecorate %23 3 BuiltIn CullDistance
+ OpDecorate %23 Block
+ OpDecorate %28 RelaxedPrecision
+ OpDecorate %29 RelaxedPrecision
+ OpDecorate %31 RelaxedPrecision
+ OpDecorate %32 RelaxedPrecision
+ OpDecorate %33 RelaxedPrecision
+ OpDecorate %35 RelaxedPrecision
+ OpDecorate %36 RelaxedPrecision
+ OpDecorate %37 RelaxedPrecision
+ OpDecorate %44 RelaxedPrecision
+ OpDecorate %52 RelaxedPrecision
+ OpDecorate %55 RelaxedPrecision
+ OpDecorate %56 RelaxedPrecision
+ %1 = OpTypeFloat 32
+ %2 = OpTypeVector %1 4
+ %9 = OpTypeStruct %2
+ %12 = OpTypeInt 32 0
+ %13 = OpTypeInt 32 1
+ %14 = OpTypeVector %13 4
+ %15 = OpTypeVector %12 4
+ %16 = OpTypeStruct %1 %1 %1 %1
+ %17 = OpTypeStruct %2 %12 %12 %13 %13 %14 %15 %16
+ %21 = OpConstant %12 8
+ %22 = OpTypeArray %1 %21
+-%23 = OpTypeStruct %2 %1 %22 %22
++%23 = OpTypeStruct %2
+ %38 = OpTypeVoid
+ %45 = OpConstant %12 0
++%59 = OpTypePointer Private %2
+ %3 = OpTypePointer Input %2
++%60 = OpTypePointer Private %2
+ %7 = OpTypePointer Output %2
+ %10 = OpTypePointer Uniform %9
+ %18 = OpTypePointer Uniform %17
+ %24 = OpTypePointer Output %23
+ %26 = OpTypePointer Function %2
+ %46 = OpTypePointer Uniform %2
+ %27 = OpTypeFunction %2 %26
+ %39 = OpTypeFunction %38
+ %4 = OpVariable %3 Input
+ %5 = OpVariable %3 Input
+ %6 = OpVariable %3 Input
+ %8 = OpVariable %7 Output
+ %11 = OpVariable %10 Uniform
+ %19 = OpVariable %18 Uniform
+-%20 = OpVariable %7 Output
++%58 = OpVariable %60 Private
+ %25 = OpVariable %24 Output
++%61 = OpConstant %13 0
++%62 = OpConstant %1 0.5
+ %28 = OpFunction %2 None %27
+ %29 = OpFunctionParameter %26
+ %30 = OpLabel
+ %31 = OpLoad %2 %29
+ OpReturnValue %31
+ OpFunctionEnd
+ %32 = OpFunction %2 None %27
+ %33 = OpFunctionParameter %26
+ %34 = OpLabel
+ %35 = OpLoad %2 %33
+ %36 = OpLoad %2 %33
+ %37 = OpFAdd %2 %35 %36
+ OpReturnValue %37
+ OpFunctionEnd
+ %40 = OpFunction %38 None %39
+ %41 = OpLabel
+ %42 = OpVariable %26 Function
+ %50 = OpVariable %26 Function
+ %53 = OpVariable %26 Function
+ %43 = OpLoad %2 %4
+ OpStore %42 %43
+ %44 = OpFunctionCall %2 %28 %42
+ %47 = OpAccessChain %46 %11 %45
+ %48 = OpLoad %2 %47
+ %49 = OpFAdd %2 %44 %48
+ OpStore %8 %49
+ %51 = OpLoad %2 %5
+ OpStore %50 %51
+ %52 = OpFunctionCall %2 %32 %50
+ %54 = OpLoad %2 %6
+ OpStore %53 %54
+ %55 = OpFunctionCall %2 %28 %53
+ %56 = OpFAdd %2 %52 %55
+ %57 = OpAccessChain %7 %25 %45
+ OpStore %57 %56
++%63 = OpAccessChain %7 %25 %61
++%64 = OpLoad %2 %63
++%65 = OpCompositeExtract %1 %64 0
++%66 = OpCompositeExtract %1 %64 1
++%67 = OpCompositeExtract %1 %64 2
++%68 = OpCompositeExtract %1 %64 3
++%70 = OpFNegate %1 %65
++%71 = OpFAdd %1 %67 %68
++%72 = OpFMul %1 %71 %62
++%69 = OpCompositeConstruct %2 %66 %70 %72 %68
++OpStore %63 %69
+ OpReturn
+ OpFunctionEnd
+)";
+  Options options;
+  options.ignore_set_binding = true;
+  options.ignore_location = true;
+  DoStringDiffTest(kSrc, kDst, kDiff, options);
+}
+
+}  // namespace
+}  // namespace diff
+}  // namespace spvtools

+ 159 - 0
ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/different_decorations_vertex_dst.spvasm

@@ -0,0 +1,159 @@
+OpCapability Shader
+OpMemoryModel Logical GLSL450
+OpEntryPoint Vertex %40 "main" %4 %5 %6 %8 %25
+OpSource GLSL 450
+OpName %4 "_ub"
+OpName %5 "_uc"
+OpName %6 "_ud"
+OpName %8 "_ue"
+OpName %9 "defaultUniformsVS"
+OpMemberName %9 0 "_ua"
+OpName %11 ""
+OpName %16 "ANGLEDepthRangeParams"
+OpMemberName %16 0 "near"
+OpMemberName %16 1 "far"
+OpMemberName %16 2 "diff"
+OpMemberName %16 3 "reserved"
+OpName %17 "ANGLEUniformBlock"
+OpMemberName %17 0 "viewport"
+OpMemberName %17 1 "clipDistancesEnabled"
+OpMemberName %17 2 "xfbActiveUnpaused"
+OpMemberName %17 3 "xfbVerticesPerInstance"
+OpMemberName %17 4 "numSamples"
+OpMemberName %17 5 "xfbBufferOffsets"
+OpMemberName %17 6 "acbBufferOffsets"
+OpMemberName %17 7 "depthRange"
+OpName %19 "ANGLEUniforms"
+OpName %23 "gl_PerVertex"
+OpMemberName %23 0 "gl_Position"
+OpName %25 ""
+OpName %29 "_ua"
+OpName %28 "_uf"
+OpName %33 "_uf"
+OpName %32 "_ug"
+OpName %40 "main"
+OpName %42 "param"
+OpName %50 "param"
+OpName %53 "param"
+OpDecorate %4 Location 1
+OpDecorate %5 Location 2
+OpDecorate %6 Location 0
+OpDecorate %8 Location 1
+OpMemberDecorate %9 0 Offset 0
+OpDecorate %9 Block
+OpDecorate %11 DescriptorSet 0
+OpDecorate %11 Binding 1
+OpMemberDecorate %16 0 Offset 0
+OpMemberDecorate %16 1 Offset 4
+OpMemberDecorate %16 2 Offset 8
+OpMemberDecorate %16 3 Offset 12
+OpMemberDecorate %17 0 Offset 0
+OpMemberDecorate %17 1 Offset 16
+OpMemberDecorate %17 2 Offset 20
+OpMemberDecorate %17 3 Offset 24
+OpMemberDecorate %17 4 Offset 28
+OpMemberDecorate %17 5 Offset 32
+OpMemberDecorate %17 6 Offset 48
+OpMemberDecorate %17 7 Offset 64
+OpMemberDecorate %17 2 RelaxedPrecision
+OpMemberDecorate %17 4 RelaxedPrecision
+OpDecorate %17 Block
+OpDecorate %19 DescriptorSet 2
+OpDecorate %19 Binding 0
+OpMemberDecorate %23 0 BuiltIn Position
+OpDecorate %23 Block
+OpDecorate %28 RelaxedPrecision
+OpDecorate %29 RelaxedPrecision
+OpDecorate %31 RelaxedPrecision
+OpDecorate %32 RelaxedPrecision
+OpDecorate %33 RelaxedPrecision
+OpDecorate %35 RelaxedPrecision
+OpDecorate %36 RelaxedPrecision
+OpDecorate %37 RelaxedPrecision
+OpDecorate %44 RelaxedPrecision
+OpDecorate %52 RelaxedPrecision
+OpDecorate %55 RelaxedPrecision
+OpDecorate %56 RelaxedPrecision
+%1 = OpTypeFloat 32
+%2 = OpTypeVector %1 4
+%9 = OpTypeStruct %2
+%12 = OpTypeInt 32 0
+%13 = OpTypeInt 32 1
+%14 = OpTypeVector %13 4
+%15 = OpTypeVector %12 4
+%16 = OpTypeStruct %1 %1 %1 %1
+%17 = OpTypeStruct %2 %12 %12 %13 %13 %14 %15 %16
+%21 = OpConstant %12 8
+%22 = OpTypeArray %1 %21
+%23 = OpTypeStruct %2
+%38 = OpTypeVoid
+%45 = OpConstant %12 0
+%58 = OpTypePointer Private %2
+%3 = OpTypePointer Input %2
+%59 = OpTypePointer Private %2
+%7 = OpTypePointer Output %2
+%10 = OpTypePointer Uniform %9
+%18 = OpTypePointer Uniform %17
+%24 = OpTypePointer Output %23
+%26 = OpTypePointer Function %2
+%46 = OpTypePointer Uniform %2
+%27 = OpTypeFunction %2 %26
+%39 = OpTypeFunction %38
+%4 = OpVariable %3 Input
+%5 = OpVariable %3 Input
+%6 = OpVariable %3 Input
+%8 = OpVariable %7 Output
+%11 = OpVariable %10 Uniform
+%19 = OpVariable %18 Uniform
+%20 = OpVariable %59 Private
+%25 = OpVariable %24 Output
+%60 = OpConstant %13 0
+%61 = OpConstant %1 0.5
+%28 = OpFunction %2 None %27
+%29 = OpFunctionParameter %26
+%30 = OpLabel
+%31 = OpLoad %2 %29
+OpReturnValue %31
+OpFunctionEnd
+%32 = OpFunction %2 None %27
+%33 = OpFunctionParameter %26
+%34 = OpLabel
+%35 = OpLoad %2 %33
+%36 = OpLoad %2 %33
+%37 = OpFAdd %2 %35 %36
+OpReturnValue %37
+OpFunctionEnd
+%40 = OpFunction %38 None %39
+%41 = OpLabel
+%42 = OpVariable %26 Function
+%50 = OpVariable %26 Function
+%53 = OpVariable %26 Function
+%43 = OpLoad %2 %4
+OpStore %42 %43
+%44 = OpFunctionCall %2 %28 %42
+%47 = OpAccessChain %46 %11 %45
+%48 = OpLoad %2 %47
+%49 = OpFAdd %2 %44 %48
+OpStore %8 %49
+%51 = OpLoad %2 %5
+OpStore %50 %51
+%52 = OpFunctionCall %2 %32 %50
+%54 = OpLoad %2 %6
+OpStore %53 %54
+%55 = OpFunctionCall %2 %28 %53
+%56 = OpFAdd %2 %52 %55
+%57 = OpAccessChain %7 %25 %45
+OpStore %57 %56
+%62 = OpAccessChain %7 %25 %60
+%63 = OpLoad %2 %62
+%64 = OpCompositeExtract %1 %63 0
+%65 = OpCompositeExtract %1 %63 1
+%66 = OpCompositeExtract %1 %63 2
+%67 = OpCompositeExtract %1 %63 3
+%69 = OpFNegate %1 %64
+%70 = OpFAdd %1 %66 %67
+%71 = OpFMul %1 %70 %61
+%68 = OpCompositeConstruct %2 %65 %69 %71 %67
+OpStore %62 %68
+OpReturn
+OpFunctionEnd

+ 155 - 0
ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/different_decorations_vertex_src.spvasm

@@ -0,0 +1,155 @@
+;; Test where variable set/binding/location decorations are different between
+;; src and dst vertex shaders.
+OpCapability Shader
+OpMemoryModel Logical GLSL450
+OpEntryPoint Vertex %40 "main" %4 %5 %6 %8 %20 %25
+OpSource GLSL 450
+OpName %4 "_ub"
+OpName %5 "_uc"
+OpName %6 "_ud"
+OpName %8 "_ue"
+OpName %9 "defaultUniformsVS"
+OpMemberName %9 0 "_ua"
+OpName %11 ""
+OpName %16 "ANGLEDepthRangeParams"
+OpMemberName %16 0 "near"
+OpMemberName %16 1 "far"
+OpMemberName %16 2 "diff"
+OpMemberName %16 3 "reserved"
+OpName %17 "ANGLEUniformBlock"
+OpMemberName %17 0 "viewport"
+OpMemberName %17 1 "clipDistancesEnabled"
+OpMemberName %17 2 "xfbActiveUnpaused"
+OpMemberName %17 3 "xfbVerticesPerInstance"
+OpMemberName %17 4 "numSamples"
+OpMemberName %17 5 "xfbBufferOffsets"
+OpMemberName %17 6 "acbBufferOffsets"
+OpMemberName %17 7 "depthRange"
+OpName %19 "ANGLEUniforms"
+OpName %20 "ANGLEXfbPosition"
+OpName %23 "gl_PerVertex"
+OpMemberName %23 0 "gl_Position"
+OpMemberName %23 1 "gl_PointSize"
+OpMemberName %23 2 "gl_ClipDistance"
+OpMemberName %23 3 "gl_CullDistance"
+OpName %25 ""
+OpName %29 "_ua"
+OpName %28 "_uf"
+OpName %33 "_uf"
+OpName %32 "_ug"
+OpName %40 "main"
+OpName %42 "param"
+OpName %50 "param"
+OpName %53 "param"
+OpDecorate %4 Location 0
+OpDecorate %5 Location 1
+OpDecorate %6 Location 2
+OpDecorate %8 Location 0
+OpMemberDecorate %9 0 Offset 0
+OpDecorate %9 Block
+OpDecorate %11 DescriptorSet 0
+OpDecorate %11 Binding 0
+OpMemberDecorate %16 0 Offset 0
+OpMemberDecorate %16 1 Offset 4
+OpMemberDecorate %16 2 Offset 8
+OpMemberDecorate %16 3 Offset 12
+OpMemberDecorate %17 0 Offset 0
+OpMemberDecorate %17 1 Offset 16
+OpMemberDecorate %17 2 Offset 20
+OpMemberDecorate %17 3 Offset 24
+OpMemberDecorate %17 4 Offset 28
+OpMemberDecorate %17 5 Offset 32
+OpMemberDecorate %17 6 Offset 48
+OpMemberDecorate %17 7 Offset 64
+OpMemberDecorate %17 2 RelaxedPrecision
+OpMemberDecorate %17 4 RelaxedPrecision
+OpDecorate %17 Block
+OpDecorate %19 DescriptorSet 0
+OpDecorate %19 Binding 1
+OpDecorate %20 Location 1
+OpMemberDecorate %23 0 BuiltIn Position
+OpMemberDecorate %23 1 BuiltIn PointSize
+OpMemberDecorate %23 2 BuiltIn ClipDistance
+OpMemberDecorate %23 3 BuiltIn CullDistance
+OpDecorate %23 Block
+OpDecorate %28 RelaxedPrecision
+OpDecorate %29 RelaxedPrecision
+OpDecorate %31 RelaxedPrecision
+OpDecorate %32 RelaxedPrecision
+OpDecorate %33 RelaxedPrecision
+OpDecorate %35 RelaxedPrecision
+OpDecorate %36 RelaxedPrecision
+OpDecorate %37 RelaxedPrecision
+OpDecorate %44 RelaxedPrecision
+OpDecorate %52 RelaxedPrecision
+OpDecorate %55 RelaxedPrecision
+OpDecorate %56 RelaxedPrecision
+%1 = OpTypeFloat 32
+%2 = OpTypeVector %1 4
+%9 = OpTypeStruct %2
+%12 = OpTypeInt 32 0
+%13 = OpTypeInt 32 1
+%14 = OpTypeVector %13 4
+%15 = OpTypeVector %12 4
+%16 = OpTypeStruct %1 %1 %1 %1
+%17 = OpTypeStruct %2 %12 %12 %13 %13 %14 %15 %16
+%21 = OpConstant %12 8
+%22 = OpTypeArray %1 %21
+%23 = OpTypeStruct %2 %1 %22 %22
+%38 = OpTypeVoid
+%45 = OpConstant %12 0
+%3 = OpTypePointer Input %2
+%7 = OpTypePointer Output %2
+%10 = OpTypePointer Uniform %9
+%18 = OpTypePointer Uniform %17
+%24 = OpTypePointer Output %23
+%26 = OpTypePointer Function %2
+%46 = OpTypePointer Uniform %2
+%27 = OpTypeFunction %2 %26
+%39 = OpTypeFunction %38
+%4 = OpVariable %3 Input
+%5 = OpVariable %3 Input
+%6 = OpVariable %3 Input
+%8 = OpVariable %7 Output
+%11 = OpVariable %10 Uniform
+%19 = OpVariable %18 Uniform
+%20 = OpVariable %7 Output
+%25 = OpVariable %24 Output
+%28 = OpFunction %2 None %27
+%29 = OpFunctionParameter %26
+%30 = OpLabel
+%31 = OpLoad %2 %29
+OpReturnValue %31
+OpFunctionEnd
+%32 = OpFunction %2 None %27
+%33 = OpFunctionParameter %26
+%34 = OpLabel
+%35 = OpLoad %2 %33
+%36 = OpLoad %2 %33
+%37 = OpFAdd %2 %35 %36
+OpReturnValue %37
+OpFunctionEnd
+%40 = OpFunction %38 None %39
+%41 = OpLabel
+%42 = OpVariable %26 Function
+%50 = OpVariable %26 Function
+%53 = OpVariable %26 Function
+%43 = OpLoad %2 %4
+OpStore %42 %43
+%44 = OpFunctionCall %2 %28 %42
+%47 = OpAccessChain %46 %11 %45
+%48 = OpLoad %2 %47
+%49 = OpFAdd %2 %44 %48
+OpStore %8 %49
+%51 = OpLoad %2 %5
+OpStore %50 %51
+%52 = OpFunctionCall %2 %32 %50
+%54 = OpLoad %2 %6
+OpStore %53 %54
+%55 = OpFunctionCall %2 %28 %53
+%56 = OpFAdd %2 %52 %55
+%57 = OpAccessChain %7 %25 %45
+OpStore %57 %56
+OpReturn
+OpFunctionEnd
+

+ 339 - 0
ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/different_function_parameter_count_autogen.cpp

@@ -0,0 +1,339 @@
+// GENERATED FILE - DO NOT EDIT.
+// Generated by generate_tests.py
+//
+// 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 "../diff_test_utils.h"
+
+#include "gtest/gtest.h"
+
+namespace spvtools {
+namespace diff {
+namespace {
+
+// Test where src and dst have a function with different parameter count.
+constexpr char kSrc[] = R"(; SPIR-V
+; Version: 1.0
+; Generator: Khronos Glslang Reference Front End; 10
+; Bound: 25
+; Schema: 0
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %4 "main" %20
+               OpExecutionMode %4 OriginUpperLeft
+               OpSource ESSL 320
+               OpName %4 "main"
+               OpName %11 "f(vf2;"
+               OpName %10 "v"
+               OpName %20 "o"
+               OpName %23 "param"
+               OpDecorate %20 RelaxedPrecision
+               OpDecorate %20 Location 0
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeFloat 32
+          %7 = OpTypeVector %6 2
+          %8 = OpTypePointer Function %7
+          %9 = OpTypeFunction %7 %8
+         %14 = OpConstant %6 0.5
+         %15 = OpConstantComposite %7 %14 %14
+         %19 = OpTypePointer Output %7
+         %20 = OpVariable %19 Output
+         %21 = OpConstant %6 0
+         %22 = OpConstantComposite %7 %21 %21
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+         %23 = OpVariable %8 Function
+               OpStore %23 %22
+         %24 = OpFunctionCall %7 %11 %23
+               OpStore %20 %24
+               OpReturn
+               OpFunctionEnd
+         %11 = OpFunction %7 None %9
+         %10 = OpFunctionParameter %8
+         %12 = OpLabel
+         %13 = OpLoad %7 %10
+         %16 = OpFAdd %7 %13 %15
+               OpReturnValue %16
+               OpFunctionEnd)";
+constexpr char kDst[] = R"(; SPIR-V
+; Version: 1.0
+; Generator: Khronos Glslang Reference Front End; 10
+; Bound: 28
+; Schema: 0
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %4 "main" %20
+               OpExecutionMode %4 OriginUpperLeft
+               OpSource ESSL 320
+               OpName %4 "main"
+               OpName %12 "f(vf2;vf2;"
+               OpName %10 "v"
+               OpName %11 "v2"
+               OpName %20 "o"
+               OpName %25 "param"
+               OpName %26 "param"
+               OpDecorate %20 RelaxedPrecision
+               OpDecorate %20 Location 0
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeFloat 32
+          %7 = OpTypeVector %6 2
+          %8 = OpTypePointer Function %7
+          %9 = OpTypeFunction %7 %8 %8
+         %19 = OpTypePointer Output %7
+         %20 = OpVariable %19 Output
+         %21 = OpConstant %6 0
+         %22 = OpConstantComposite %7 %21 %21
+         %23 = OpConstant %6 0.5
+         %24 = OpConstantComposite %7 %23 %23
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+         %25 = OpVariable %8 Function
+         %26 = OpVariable %8 Function
+               OpStore %25 %22
+               OpStore %26 %24
+         %27 = OpFunctionCall %7 %12 %25 %26
+               OpStore %20 %27
+               OpReturn
+               OpFunctionEnd
+         %12 = OpFunction %7 None %9
+         %10 = OpFunctionParameter %8
+         %11 = OpFunctionParameter %8
+         %13 = OpLabel
+         %14 = OpLoad %7 %10
+         %15 = OpLoad %7 %11
+         %16 = OpFAdd %7 %14 %15
+               OpReturnValue %16
+               OpFunctionEnd
+
+)";
+
+TEST(DiffTest, DifferentFunctionParameterCount) {
+  constexpr char kDiff[] = R"( ; SPIR-V
+ ; Version: 1.6
+ ; Generator: Khronos SPIR-V Tools Assembler; 0
+-; Bound: 25
++; Bound: 33
+ ; Schema: 0
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main" %20
+ OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 320
+ OpName %4 "main"
+-OpName %11 "f(vf2;"
++OpName %11 "f(vf2;vf2;"
+ OpName %10 "v"
++OpName %26 "v2"
+ OpName %20 "o"
+ OpName %23 "param"
++OpName %31 "param"
+ OpDecorate %20 RelaxedPrecision
+ OpDecorate %20 Location 0
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %6 = OpTypeFloat 32
+ %7 = OpTypeVector %6 2
+ %8 = OpTypePointer Function %7
+-%9 = OpTypeFunction %7 %8
++%25 = OpTypeFunction %7 %8 %8
+ %14 = OpConstant %6 0.5
+ %15 = OpConstantComposite %7 %14 %14
+ %19 = OpTypePointer Output %7
+ %20 = OpVariable %19 Output
+ %21 = OpConstant %6 0
+ %22 = OpConstantComposite %7 %21 %21
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ %23 = OpVariable %8 Function
++%31 = OpVariable %8 Function
+ OpStore %23 %22
+-%24 = OpFunctionCall %7 %11 %23
++OpStore %31 %15
++%32 = OpFunctionCall %7 %11 %23 %31
+-OpStore %20 %24
++OpStore %20 %32
+ OpReturn
+ OpFunctionEnd
+-%11 = OpFunction %7 None %9
++%11 = OpFunction %7 None %25
+ %10 = OpFunctionParameter %8
++%26 = OpFunctionParameter %8
+ %12 = OpLabel
+ %13 = OpLoad %7 %10
+-%16 = OpFAdd %7 %13 %15
++%27 = OpLoad %7 %26
++%28 = OpFAdd %7 %13 %27
+-OpReturnValue %16
++OpReturnValue %28
+ OpFunctionEnd
+)";
+  Options options;
+  DoStringDiffTest(kSrc, kDst, kDiff, options);
+}
+
+TEST(DiffTest, DifferentFunctionParameterCountNoDebug) {
+  constexpr char kSrcNoDebug[] = R"(; SPIR-V
+; Version: 1.0
+; Generator: Khronos Glslang Reference Front End; 10
+; Bound: 25
+; Schema: 0
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %4 "main" %20
+               OpExecutionMode %4 OriginUpperLeft
+               OpSource ESSL 320
+               OpDecorate %20 RelaxedPrecision
+               OpDecorate %20 Location 0
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeFloat 32
+          %7 = OpTypeVector %6 2
+          %8 = OpTypePointer Function %7
+          %9 = OpTypeFunction %7 %8
+         %14 = OpConstant %6 0.5
+         %15 = OpConstantComposite %7 %14 %14
+         %19 = OpTypePointer Output %7
+         %20 = OpVariable %19 Output
+         %21 = OpConstant %6 0
+         %22 = OpConstantComposite %7 %21 %21
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+         %23 = OpVariable %8 Function
+               OpStore %23 %22
+         %24 = OpFunctionCall %7 %11 %23
+               OpStore %20 %24
+               OpReturn
+               OpFunctionEnd
+         %11 = OpFunction %7 None %9
+         %10 = OpFunctionParameter %8
+         %12 = OpLabel
+         %13 = OpLoad %7 %10
+         %16 = OpFAdd %7 %13 %15
+               OpReturnValue %16
+               OpFunctionEnd
+)";
+  constexpr char kDstNoDebug[] = R"(; SPIR-V
+; Version: 1.0
+; Generator: Khronos Glslang Reference Front End; 10
+; Bound: 28
+; Schema: 0
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %4 "main" %20
+               OpExecutionMode %4 OriginUpperLeft
+               OpSource ESSL 320
+               OpDecorate %20 RelaxedPrecision
+               OpDecorate %20 Location 0
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeFloat 32
+          %7 = OpTypeVector %6 2
+          %8 = OpTypePointer Function %7
+          %9 = OpTypeFunction %7 %8 %8
+         %19 = OpTypePointer Output %7
+         %20 = OpVariable %19 Output
+         %21 = OpConstant %6 0
+         %22 = OpConstantComposite %7 %21 %21
+         %23 = OpConstant %6 0.5
+         %24 = OpConstantComposite %7 %23 %23
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+         %25 = OpVariable %8 Function
+         %26 = OpVariable %8 Function
+               OpStore %25 %22
+               OpStore %26 %24
+         %27 = OpFunctionCall %7 %12 %25 %26
+               OpStore %20 %27
+               OpReturn
+               OpFunctionEnd
+         %12 = OpFunction %7 None %9
+         %10 = OpFunctionParameter %8
+         %11 = OpFunctionParameter %8
+         %13 = OpLabel
+         %14 = OpLoad %7 %10
+         %15 = OpLoad %7 %11
+         %16 = OpFAdd %7 %14 %15
+               OpReturnValue %16
+               OpFunctionEnd
+
+)";
+  constexpr char kDiff[] = R"( ; SPIR-V
+ ; Version: 1.6
+ ; Generator: Khronos SPIR-V Tools Assembler; 0
+-; Bound: 25
++; Bound: 34
+ ; Schema: 0
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main" %20
+ OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 320
+ OpDecorate %20 RelaxedPrecision
+ OpDecorate %20 Location 0
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %6 = OpTypeFloat 32
+ %7 = OpTypeVector %6 2
+ %8 = OpTypePointer Function %7
+-%9 = OpTypeFunction %7 %8
++%25 = OpTypeFunction %7 %8 %8
+ %14 = OpConstant %6 0.5
+ %15 = OpConstantComposite %7 %14 %14
+ %19 = OpTypePointer Output %7
+ %20 = OpVariable %19 Output
+ %21 = OpConstant %6 0
+ %22 = OpConstantComposite %7 %21 %21
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ %23 = OpVariable %8 Function
++%32 = OpVariable %8 Function
+ OpStore %23 %22
+-%24 = OpFunctionCall %7 %11 %23
++OpStore %32 %15
++%33 = OpFunctionCall %7 %11 %23 %32
+-OpStore %20 %24
++OpStore %20 %33
+ OpReturn
+ OpFunctionEnd
+-%11 = OpFunction %7 None %9
++%11 = OpFunction %7 None %25
+-%10 = OpFunctionParameter %8
++%26 = OpFunctionParameter %8
++%27 = OpFunctionParameter %8
+ %12 = OpLabel
+-%13 = OpLoad %7 %10
++%13 = OpLoad %7 %26
+-%16 = OpFAdd %7 %13 %15
++%28 = OpLoad %7 %27
++%29 = OpFAdd %7 %13 %28
+-OpReturnValue %16
++OpReturnValue %29
+ OpFunctionEnd
+)";
+  Options options;
+  DoStringDiffTest(kSrcNoDebug, kDstNoDebug, kDiff, options);
+}
+
+}  // namespace
+}  // namespace diff
+}  // namespace spvtools

+ 52 - 0
ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/different_function_parameter_count_dst.spvasm

@@ -0,0 +1,52 @@
+; SPIR-V
+; Version: 1.0
+; Generator: Khronos Glslang Reference Front End; 10
+; Bound: 28
+; Schema: 0
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %4 "main" %20
+               OpExecutionMode %4 OriginUpperLeft
+               OpSource ESSL 320
+               OpName %4 "main"
+               OpName %12 "f(vf2;vf2;"
+               OpName %10 "v"
+               OpName %11 "v2"
+               OpName %20 "o"
+               OpName %25 "param"
+               OpName %26 "param"
+               OpDecorate %20 RelaxedPrecision
+               OpDecorate %20 Location 0
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeFloat 32
+          %7 = OpTypeVector %6 2
+          %8 = OpTypePointer Function %7
+          %9 = OpTypeFunction %7 %8 %8
+         %19 = OpTypePointer Output %7
+         %20 = OpVariable %19 Output
+         %21 = OpConstant %6 0
+         %22 = OpConstantComposite %7 %21 %21
+         %23 = OpConstant %6 0.5
+         %24 = OpConstantComposite %7 %23 %23
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+         %25 = OpVariable %8 Function
+         %26 = OpVariable %8 Function
+               OpStore %25 %22
+               OpStore %26 %24
+         %27 = OpFunctionCall %7 %12 %25 %26
+               OpStore %20 %27
+               OpReturn
+               OpFunctionEnd
+         %12 = OpFunction %7 None %9
+         %10 = OpFunctionParameter %8
+         %11 = OpFunctionParameter %8
+         %13 = OpLabel
+         %14 = OpLoad %7 %10
+         %15 = OpLoad %7 %11
+         %16 = OpFAdd %7 %14 %15
+               OpReturnValue %16
+               OpFunctionEnd
+

+ 46 - 0
ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/different_function_parameter_count_src.spvasm

@@ -0,0 +1,46 @@
+;; Test where src and dst have a function with different parameter count.
+; SPIR-V
+; Version: 1.0
+; Generator: Khronos Glslang Reference Front End; 10
+; Bound: 25
+; Schema: 0
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %4 "main" %20
+               OpExecutionMode %4 OriginUpperLeft
+               OpSource ESSL 320
+               OpName %4 "main"
+               OpName %11 "f(vf2;"
+               OpName %10 "v"
+               OpName %20 "o"
+               OpName %23 "param"
+               OpDecorate %20 RelaxedPrecision
+               OpDecorate %20 Location 0
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeFloat 32
+          %7 = OpTypeVector %6 2
+          %8 = OpTypePointer Function %7
+          %9 = OpTypeFunction %7 %8
+         %14 = OpConstant %6 0.5
+         %15 = OpConstantComposite %7 %14 %14
+         %19 = OpTypePointer Output %7
+         %20 = OpVariable %19 Output
+         %21 = OpConstant %6 0
+         %22 = OpConstantComposite %7 %21 %21
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+         %23 = OpVariable %8 Function
+               OpStore %23 %22
+         %24 = OpFunctionCall %7 %11 %23
+               OpStore %20 %24
+               OpReturn
+               OpFunctionEnd
+         %11 = OpFunction %7 None %9
+         %10 = OpFunctionParameter %8
+         %12 = OpLabel
+         %13 = OpLoad %7 %10
+         %16 = OpFAdd %7 %13 %15
+               OpReturnValue %16
+               OpFunctionEnd

+ 867 - 0
ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/extra_if_block_autogen.cpp

@@ -0,0 +1,867 @@
+// GENERATED FILE - DO NOT EDIT.
+// Generated by generate_tests.py
+//
+// 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 "../diff_test_utils.h"
+
+#include "gtest/gtest.h"
+
+namespace spvtools {
+namespace diff {
+namespace {
+
+// Test where src has an extra if block in one function, and dst has an extra
+// if block in another function.
+constexpr char kSrc[] = R"(               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %4 "main" %63 %68
+               OpExecutionMode %4 OriginUpperLeft
+               OpSource ESSL 310
+               OpName %4 "main"
+               OpName %8 "f1("
+               OpName %10 "f2("
+               OpName %13 "v"
+               OpName %16 "Buffer"
+               OpMemberName %16 0 "flag1"
+               OpMemberName %16 1 "flag2"
+               OpName %18 ""
+               OpName %45 "v"
+               OpName %63 "color"
+               OpName %68 "v"
+               OpDecorate %8 RelaxedPrecision
+               OpDecorate %10 RelaxedPrecision
+               OpDecorate %13 RelaxedPrecision
+               OpMemberDecorate %16 0 RelaxedPrecision
+               OpMemberDecorate %16 0 Offset 0
+               OpMemberDecorate %16 1 RelaxedPrecision
+               OpMemberDecorate %16 1 Offset 4
+               OpDecorate %16 Block
+               OpDecorate %18 DescriptorSet 0
+               OpDecorate %18 Binding 0
+               OpDecorate %23 RelaxedPrecision
+               OpDecorate %30 RelaxedPrecision
+               OpDecorate %31 RelaxedPrecision
+               OpDecorate %34 RelaxedPrecision
+               OpDecorate %35 RelaxedPrecision
+               OpDecorate %36 RelaxedPrecision
+               OpDecorate %37 RelaxedPrecision
+               OpDecorate %38 RelaxedPrecision
+               OpDecorate %39 RelaxedPrecision
+               OpDecorate %40 RelaxedPrecision
+               OpDecorate %41 RelaxedPrecision
+               OpDecorate %42 RelaxedPrecision
+               OpDecorate %45 RelaxedPrecision
+               OpDecorate %47 RelaxedPrecision
+               OpDecorate %48 RelaxedPrecision
+               OpDecorate %50 RelaxedPrecision
+               OpDecorate %51 RelaxedPrecision
+               OpDecorate %54 RelaxedPrecision
+               OpDecorate %55 RelaxedPrecision
+               OpDecorate %56 RelaxedPrecision
+               OpDecorate %57 RelaxedPrecision
+               OpDecorate %58 RelaxedPrecision
+               OpDecorate %63 RelaxedPrecision
+               OpDecorate %63 Location 0
+               OpDecorate %64 RelaxedPrecision
+               OpDecorate %65 RelaxedPrecision
+               OpDecorate %66 RelaxedPrecision
+               OpDecorate %68 RelaxedPrecision
+               OpDecorate %68 Location 0
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeFloat 32
+          %7 = OpTypeFunction %6
+         %12 = OpTypePointer Function %6
+         %14 = OpConstant %6 0
+         %15 = OpTypeInt 32 0
+         %16 = OpTypeStruct %15 %15
+         %17 = OpTypePointer Uniform %16
+         %18 = OpVariable %17 Uniform
+         %19 = OpTypeInt 32 1
+         %20 = OpConstant %19 0
+         %21 = OpTypePointer Uniform %15
+         %24 = OpConstant %15 0
+         %25 = OpTypeBool
+         %29 = OpConstant %6 1
+         %32 = OpConstant %19 1
+         %49 = OpConstant %6 10
+         %52 = OpConstant %6 0.5
+         %53 = OpConstant %6 0.699999988
+         %61 = OpTypeVector %6 4
+         %62 = OpTypePointer Output %61
+         %63 = OpVariable %62 Output
+         %67 = OpTypePointer Input %6
+         %68 = OpVariable %67 Input
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+         %64 = OpFunctionCall %6 %8
+         %65 = OpFunctionCall %6 %10
+         %66 = OpCompositeConstruct %61 %64 %65 %14 %29
+               OpStore %63 %66
+               OpReturn
+               OpFunctionEnd
+          %8 = OpFunction %6 None %7
+          %9 = OpLabel
+         %13 = OpVariable %12 Function
+               OpStore %13 %14
+         %22 = OpAccessChain %21 %18 %20
+         %23 = OpLoad %15 %22
+         %26 = OpINotEqual %25 %23 %24
+               OpSelectionMerge %28 None
+               OpBranchConditional %26 %27 %28
+         %27 = OpLabel
+         %30 = OpLoad %6 %13
+         %31 = OpFAdd %6 %30 %29
+               OpStore %13 %31
+               OpBranch %28
+         %28 = OpLabel
+         %33 = OpAccessChain %21 %18 %32
+         %34 = OpLoad %15 %33
+         %35 = OpConvertUToF %6 %34
+         %36 = OpExtInst %6 %1 Log2 %35
+         %37 = OpLoad %6 %13
+         %38 = OpFAdd %6 %37 %36
+               OpStore %13 %38
+         %39 = OpLoad %6 %13
+         %40 = OpLoad %6 %13
+         %41 = OpExtInst %6 %1 Sqrt %40
+         %42 = OpFSub %6 %39 %41
+               OpReturnValue %42
+               OpFunctionEnd
+         %10 = OpFunction %6 None %7
+         %11 = OpLabel
+         %45 = OpVariable %12 Function
+         %46 = OpAccessChain %21 %18 %20
+         %47 = OpLoad %15 %46
+         %48 = OpConvertUToF %6 %47
+         %50 = OpFDiv %6 %48 %49
+               OpStore %45 %50
+         %51 = OpLoad %6 %45
+         %54 = OpExtInst %6 %1 FClamp %51 %52 %53
+         %55 = OpLoad %6 %45
+         %56 = OpFMul %6 %55 %54
+               OpStore %45 %56
+         %57 = OpLoad %6 %45
+         %58 = OpExtInst %6 %1 Exp %57
+               OpReturnValue %58
+               OpFunctionEnd
+)";
+constexpr char kDst[] = R"(               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %4 "main" %63 %69
+               OpExecutionMode %4 OriginUpperLeft
+               OpSource ESSL 310
+               OpName %4 "main"
+               OpName %8 "f1("
+               OpName %10 "f2("
+               OpName %13 "v"
+               OpName %16 "Buffer"
+               OpMemberName %16 0 "flag1"
+               OpMemberName %16 1 "flag2"
+               OpName %18 ""
+               OpName %34 "v"
+               OpName %63 "color"
+               OpName %69 "v"
+               OpDecorate %8 RelaxedPrecision
+               OpDecorate %10 RelaxedPrecision
+               OpDecorate %13 RelaxedPrecision
+               OpMemberDecorate %16 0 RelaxedPrecision
+               OpMemberDecorate %16 0 Offset 0
+               OpMemberDecorate %16 1 RelaxedPrecision
+               OpMemberDecorate %16 1 Offset 4
+               OpDecorate %16 Block
+               OpDecorate %18 DescriptorSet 0
+               OpDecorate %18 Binding 0
+               OpDecorate %23 RelaxedPrecision
+               OpDecorate %24 RelaxedPrecision
+               OpDecorate %25 RelaxedPrecision
+               OpDecorate %26 RelaxedPrecision
+               OpDecorate %27 RelaxedPrecision
+               OpDecorate %28 RelaxedPrecision
+               OpDecorate %29 RelaxedPrecision
+               OpDecorate %30 RelaxedPrecision
+               OpDecorate %31 RelaxedPrecision
+               OpDecorate %34 RelaxedPrecision
+               OpDecorate %37 RelaxedPrecision
+               OpDecorate %38 RelaxedPrecision
+               OpDecorate %40 RelaxedPrecision
+               OpDecorate %41 RelaxedPrecision
+               OpDecorate %44 RelaxedPrecision
+               OpDecorate %45 RelaxedPrecision
+               OpDecorate %46 RelaxedPrecision
+               OpDecorate %48 RelaxedPrecision
+               OpDecorate %55 RelaxedPrecision
+               OpDecorate %56 RelaxedPrecision
+               OpDecorate %57 RelaxedPrecision
+               OpDecorate %58 RelaxedPrecision
+               OpDecorate %63 RelaxedPrecision
+               OpDecorate %63 Location 0
+               OpDecorate %64 RelaxedPrecision
+               OpDecorate %65 RelaxedPrecision
+               OpDecorate %67 RelaxedPrecision
+               OpDecorate %69 RelaxedPrecision
+               OpDecorate %69 Location 0
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeFloat 32
+          %7 = OpTypeFunction %6
+         %12 = OpTypePointer Function %6
+         %14 = OpConstant %6 0
+         %15 = OpTypeInt 32 0
+         %16 = OpTypeStruct %15 %15
+         %17 = OpTypePointer Uniform %16
+         %18 = OpVariable %17 Uniform
+         %19 = OpTypeInt 32 1
+         %20 = OpConstant %19 1
+         %21 = OpTypePointer Uniform %15
+         %35 = OpConstant %19 0
+         %39 = OpConstant %6 10
+         %42 = OpConstant %6 0.5
+         %43 = OpConstant %6 0.699999988
+         %49 = OpConstant %15 0
+         %50 = OpTypeBool
+         %54 = OpConstant %6 0.100000001
+         %61 = OpTypeVector %6 4
+         %62 = OpTypePointer Output %61
+         %63 = OpVariable %62 Output
+         %66 = OpConstant %6 1
+         %68 = OpTypePointer Input %6
+         %69 = OpVariable %68 Input
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+         %64 = OpFunctionCall %6 %8
+         %65 = OpFunctionCall %6 %10
+         %67 = OpCompositeConstruct %61 %64 %65 %14 %66
+               OpStore %63 %67
+               OpReturn
+               OpFunctionEnd
+          %8 = OpFunction %6 None %7
+          %9 = OpLabel
+         %13 = OpVariable %12 Function
+               OpStore %13 %14
+         %22 = OpAccessChain %21 %18 %20
+         %23 = OpLoad %15 %22
+         %24 = OpConvertUToF %6 %23
+         %25 = OpExtInst %6 %1 Log2 %24
+         %26 = OpLoad %6 %13
+         %27 = OpFAdd %6 %26 %25
+               OpStore %13 %27
+         %28 = OpLoad %6 %13
+         %29 = OpLoad %6 %13
+         %30 = OpExtInst %6 %1 Sqrt %29
+         %31 = OpFSub %6 %28 %30
+               OpReturnValue %31
+               OpFunctionEnd
+         %10 = OpFunction %6 None %7
+         %11 = OpLabel
+         %34 = OpVariable %12 Function
+         %36 = OpAccessChain %21 %18 %35
+         %37 = OpLoad %15 %36
+         %38 = OpConvertUToF %6 %37
+         %40 = OpFDiv %6 %38 %39
+               OpStore %34 %40
+         %41 = OpLoad %6 %34
+         %44 = OpExtInst %6 %1 FClamp %41 %42 %43
+         %45 = OpLoad %6 %34
+         %46 = OpFMul %6 %45 %44
+               OpStore %34 %46
+         %47 = OpAccessChain %21 %18 %20
+         %48 = OpLoad %15 %47
+         %51 = OpINotEqual %50 %48 %49
+               OpSelectionMerge %53 None
+               OpBranchConditional %51 %52 %53
+         %52 = OpLabel
+         %55 = OpLoad %6 %34
+         %56 = OpFSub %6 %55 %54
+               OpStore %34 %56
+               OpBranch %53
+         %53 = OpLabel
+         %57 = OpLoad %6 %34
+         %58 = OpExtInst %6 %1 Exp %57
+               OpReturnValue %58
+               OpFunctionEnd
+
+)";
+
+TEST(DiffTest, ExtraIfBlock) {
+  constexpr char kDiff[] = R"( ; SPIR-V
+ ; Version: 1.6
+ ; Generator: Khronos SPIR-V Tools Assembler; 0
+-; Bound: 69
++; Bound: 81
+ ; Schema: 0
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main" %63 %68
+ OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 310
+ OpName %4 "main"
+ OpName %8 "f1("
+ OpName %10 "f2("
+ OpName %13 "v"
+ OpName %16 "Buffer"
+ OpMemberName %16 0 "flag1"
+ OpMemberName %16 1 "flag2"
+ OpName %18 ""
+ OpName %45 "v"
+ OpName %63 "color"
+ OpName %68 "v"
+ OpDecorate %8 RelaxedPrecision
+ OpDecorate %10 RelaxedPrecision
+ OpDecorate %13 RelaxedPrecision
+ OpMemberDecorate %16 0 RelaxedPrecision
+ OpMemberDecorate %16 0 Offset 0
+ OpMemberDecorate %16 1 RelaxedPrecision
+ OpMemberDecorate %16 1 Offset 4
+ OpDecorate %16 Block
+ OpDecorate %18 DescriptorSet 0
+ OpDecorate %18 Binding 0
+-OpDecorate %23 RelaxedPrecision
+-OpDecorate %30 RelaxedPrecision
+-OpDecorate %31 RelaxedPrecision
+ OpDecorate %34 RelaxedPrecision
+ OpDecorate %35 RelaxedPrecision
+ OpDecorate %36 RelaxedPrecision
+ OpDecorate %37 RelaxedPrecision
+ OpDecorate %38 RelaxedPrecision
+ OpDecorate %39 RelaxedPrecision
+ OpDecorate %40 RelaxedPrecision
+ OpDecorate %41 RelaxedPrecision
+ OpDecorate %42 RelaxedPrecision
+ OpDecorate %45 RelaxedPrecision
+ OpDecorate %47 RelaxedPrecision
+ OpDecorate %48 RelaxedPrecision
+ OpDecorate %50 RelaxedPrecision
+ OpDecorate %51 RelaxedPrecision
+ OpDecorate %54 RelaxedPrecision
+ OpDecorate %55 RelaxedPrecision
+ OpDecorate %56 RelaxedPrecision
++OpDecorate %72 RelaxedPrecision
+ OpDecorate %57 RelaxedPrecision
++OpDecorate %77 RelaxedPrecision
++OpDecorate %78 RelaxedPrecision
+ OpDecorate %58 RelaxedPrecision
+ OpDecorate %63 RelaxedPrecision
+ OpDecorate %63 Location 0
+ OpDecorate %64 RelaxedPrecision
+ OpDecorate %65 RelaxedPrecision
+ OpDecorate %66 RelaxedPrecision
+ OpDecorate %68 RelaxedPrecision
+ OpDecorate %68 Location 0
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %6 = OpTypeFloat 32
+ %7 = OpTypeFunction %6
+ %12 = OpTypePointer Function %6
+ %14 = OpConstant %6 0
+ %15 = OpTypeInt 32 0
+ %16 = OpTypeStruct %15 %15
+ %17 = OpTypePointer Uniform %16
+ %18 = OpVariable %17 Uniform
+ %19 = OpTypeInt 32 1
+ %20 = OpConstant %19 0
+ %21 = OpTypePointer Uniform %15
+ %24 = OpConstant %15 0
+ %25 = OpTypeBool
+ %29 = OpConstant %6 1
+ %32 = OpConstant %19 1
+ %49 = OpConstant %6 10
+ %52 = OpConstant %6 0.5
++%76 = OpConstant %6 0.100000001
+ %53 = OpConstant %6 0.699999988
+ %61 = OpTypeVector %6 4
+ %62 = OpTypePointer Output %61
+ %63 = OpVariable %62 Output
+ %67 = OpTypePointer Input %6
+ %68 = OpVariable %67 Input
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ %64 = OpFunctionCall %6 %8
+ %65 = OpFunctionCall %6 %10
+ %66 = OpCompositeConstruct %61 %64 %65 %14 %29
+ OpStore %63 %66
+ OpReturn
+ OpFunctionEnd
+ %8 = OpFunction %6 None %7
+ %9 = OpLabel
+ %13 = OpVariable %12 Function
+ OpStore %13 %14
+-%22 = OpAccessChain %21 %18 %20
+-%23 = OpLoad %15 %22
+-%26 = OpINotEqual %25 %23 %24
+-OpSelectionMerge %28 None
+-OpBranchConditional %26 %27 %28
+-%27 = OpLabel
+-%30 = OpLoad %6 %13
+-%31 = OpFAdd %6 %30 %29
+-OpStore %13 %31
+-OpBranch %28
+-%28 = OpLabel
+ %33 = OpAccessChain %21 %18 %32
+ %34 = OpLoad %15 %33
+ %35 = OpConvertUToF %6 %34
+ %36 = OpExtInst %6 %1 Log2 %35
+ %37 = OpLoad %6 %13
+ %38 = OpFAdd %6 %37 %36
+ OpStore %13 %38
+ %39 = OpLoad %6 %13
+ %40 = OpLoad %6 %13
+ %41 = OpExtInst %6 %1 Sqrt %40
+ %42 = OpFSub %6 %39 %41
+ OpReturnValue %42
+ OpFunctionEnd
+ %10 = OpFunction %6 None %7
+ %11 = OpLabel
+ %45 = OpVariable %12 Function
+ %46 = OpAccessChain %21 %18 %20
+ %47 = OpLoad %15 %46
+ %48 = OpConvertUToF %6 %47
+ %50 = OpFDiv %6 %48 %49
+ OpStore %45 %50
+ %51 = OpLoad %6 %45
+ %54 = OpExtInst %6 %1 FClamp %51 %52 %53
+ %55 = OpLoad %6 %45
+ %56 = OpFMul %6 %55 %54
+ OpStore %45 %56
++%71 = OpAccessChain %21 %18 %32
++%72 = OpLoad %15 %71
++%73 = OpINotEqual %25 %72 %24
++OpSelectionMerge %75 None
++OpBranchConditional %73 %74 %75
++%74 = OpLabel
+ %57 = OpLoad %6 %45
++%77 = OpFSub %6 %57 %76
++OpStore %45 %77
++OpBranch %75
++%75 = OpLabel
++%78 = OpLoad %6 %45
+-%58 = OpExtInst %6 %1 Exp %57
++%58 = OpExtInst %6 %1 Exp %78
+ OpReturnValue %58
+ OpFunctionEnd
+)";
+  Options options;
+  DoStringDiffTest(kSrc, kDst, kDiff, options);
+}
+
+TEST(DiffTest, ExtraIfBlockNoDebug) {
+  constexpr char kSrcNoDebug[] = R"(               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %4 "main" %63 %68
+               OpExecutionMode %4 OriginUpperLeft
+               OpSource ESSL 310
+               OpDecorate %8 RelaxedPrecision
+               OpDecorate %10 RelaxedPrecision
+               OpDecorate %13 RelaxedPrecision
+               OpMemberDecorate %16 0 RelaxedPrecision
+               OpMemberDecorate %16 0 Offset 0
+               OpMemberDecorate %16 1 RelaxedPrecision
+               OpMemberDecorate %16 1 Offset 4
+               OpDecorate %16 Block
+               OpDecorate %18 DescriptorSet 0
+               OpDecorate %18 Binding 0
+               OpDecorate %23 RelaxedPrecision
+               OpDecorate %30 RelaxedPrecision
+               OpDecorate %31 RelaxedPrecision
+               OpDecorate %34 RelaxedPrecision
+               OpDecorate %35 RelaxedPrecision
+               OpDecorate %36 RelaxedPrecision
+               OpDecorate %37 RelaxedPrecision
+               OpDecorate %38 RelaxedPrecision
+               OpDecorate %39 RelaxedPrecision
+               OpDecorate %40 RelaxedPrecision
+               OpDecorate %41 RelaxedPrecision
+               OpDecorate %42 RelaxedPrecision
+               OpDecorate %45 RelaxedPrecision
+               OpDecorate %47 RelaxedPrecision
+               OpDecorate %48 RelaxedPrecision
+               OpDecorate %50 RelaxedPrecision
+               OpDecorate %51 RelaxedPrecision
+               OpDecorate %54 RelaxedPrecision
+               OpDecorate %55 RelaxedPrecision
+               OpDecorate %56 RelaxedPrecision
+               OpDecorate %57 RelaxedPrecision
+               OpDecorate %58 RelaxedPrecision
+               OpDecorate %63 RelaxedPrecision
+               OpDecorate %63 Location 0
+               OpDecorate %64 RelaxedPrecision
+               OpDecorate %65 RelaxedPrecision
+               OpDecorate %66 RelaxedPrecision
+               OpDecorate %68 RelaxedPrecision
+               OpDecorate %68 Location 0
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeFloat 32
+          %7 = OpTypeFunction %6
+         %12 = OpTypePointer Function %6
+         %14 = OpConstant %6 0
+         %15 = OpTypeInt 32 0
+         %16 = OpTypeStruct %15 %15
+         %17 = OpTypePointer Uniform %16
+         %18 = OpVariable %17 Uniform
+         %19 = OpTypeInt 32 1
+         %20 = OpConstant %19 0
+         %21 = OpTypePointer Uniform %15
+         %24 = OpConstant %15 0
+         %25 = OpTypeBool
+         %29 = OpConstant %6 1
+         %32 = OpConstant %19 1
+         %49 = OpConstant %6 10
+         %52 = OpConstant %6 0.5
+         %53 = OpConstant %6 0.699999988
+         %61 = OpTypeVector %6 4
+         %62 = OpTypePointer Output %61
+         %63 = OpVariable %62 Output
+         %67 = OpTypePointer Input %6
+         %68 = OpVariable %67 Input
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+         %64 = OpFunctionCall %6 %8
+         %65 = OpFunctionCall %6 %10
+         %66 = OpCompositeConstruct %61 %64 %65 %14 %29
+               OpStore %63 %66
+               OpReturn
+               OpFunctionEnd
+          %8 = OpFunction %6 None %7
+          %9 = OpLabel
+         %13 = OpVariable %12 Function
+               OpStore %13 %14
+         %22 = OpAccessChain %21 %18 %20
+         %23 = OpLoad %15 %22
+         %26 = OpINotEqual %25 %23 %24
+               OpSelectionMerge %28 None
+               OpBranchConditional %26 %27 %28
+         %27 = OpLabel
+         %30 = OpLoad %6 %13
+         %31 = OpFAdd %6 %30 %29
+               OpStore %13 %31
+               OpBranch %28
+         %28 = OpLabel
+         %33 = OpAccessChain %21 %18 %32
+         %34 = OpLoad %15 %33
+         %35 = OpConvertUToF %6 %34
+         %36 = OpExtInst %6 %1 Log2 %35
+         %37 = OpLoad %6 %13
+         %38 = OpFAdd %6 %37 %36
+               OpStore %13 %38
+         %39 = OpLoad %6 %13
+         %40 = OpLoad %6 %13
+         %41 = OpExtInst %6 %1 Sqrt %40
+         %42 = OpFSub %6 %39 %41
+               OpReturnValue %42
+               OpFunctionEnd
+         %10 = OpFunction %6 None %7
+         %11 = OpLabel
+         %45 = OpVariable %12 Function
+         %46 = OpAccessChain %21 %18 %20
+         %47 = OpLoad %15 %46
+         %48 = OpConvertUToF %6 %47
+         %50 = OpFDiv %6 %48 %49
+               OpStore %45 %50
+         %51 = OpLoad %6 %45
+         %54 = OpExtInst %6 %1 FClamp %51 %52 %53
+         %55 = OpLoad %6 %45
+         %56 = OpFMul %6 %55 %54
+               OpStore %45 %56
+         %57 = OpLoad %6 %45
+         %58 = OpExtInst %6 %1 Exp %57
+               OpReturnValue %58
+               OpFunctionEnd
+
+)";
+  constexpr char kDstNoDebug[] = R"(               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %4 "main" %63 %69
+               OpExecutionMode %4 OriginUpperLeft
+               OpSource ESSL 310
+               OpDecorate %8 RelaxedPrecision
+               OpDecorate %10 RelaxedPrecision
+               OpDecorate %13 RelaxedPrecision
+               OpMemberDecorate %16 0 RelaxedPrecision
+               OpMemberDecorate %16 0 Offset 0
+               OpMemberDecorate %16 1 RelaxedPrecision
+               OpMemberDecorate %16 1 Offset 4
+               OpDecorate %16 Block
+               OpDecorate %18 DescriptorSet 0
+               OpDecorate %18 Binding 0
+               OpDecorate %23 RelaxedPrecision
+               OpDecorate %24 RelaxedPrecision
+               OpDecorate %25 RelaxedPrecision
+               OpDecorate %26 RelaxedPrecision
+               OpDecorate %27 RelaxedPrecision
+               OpDecorate %28 RelaxedPrecision
+               OpDecorate %29 RelaxedPrecision
+               OpDecorate %30 RelaxedPrecision
+               OpDecorate %31 RelaxedPrecision
+               OpDecorate %34 RelaxedPrecision
+               OpDecorate %37 RelaxedPrecision
+               OpDecorate %38 RelaxedPrecision
+               OpDecorate %40 RelaxedPrecision
+               OpDecorate %41 RelaxedPrecision
+               OpDecorate %44 RelaxedPrecision
+               OpDecorate %45 RelaxedPrecision
+               OpDecorate %46 RelaxedPrecision
+               OpDecorate %48 RelaxedPrecision
+               OpDecorate %55 RelaxedPrecision
+               OpDecorate %56 RelaxedPrecision
+               OpDecorate %57 RelaxedPrecision
+               OpDecorate %58 RelaxedPrecision
+               OpDecorate %63 RelaxedPrecision
+               OpDecorate %63 Location 0
+               OpDecorate %64 RelaxedPrecision
+               OpDecorate %65 RelaxedPrecision
+               OpDecorate %67 RelaxedPrecision
+               OpDecorate %69 RelaxedPrecision
+               OpDecorate %69 Location 0
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeFloat 32
+          %7 = OpTypeFunction %6
+         %12 = OpTypePointer Function %6
+         %14 = OpConstant %6 0
+         %15 = OpTypeInt 32 0
+         %16 = OpTypeStruct %15 %15
+         %17 = OpTypePointer Uniform %16
+         %18 = OpVariable %17 Uniform
+         %19 = OpTypeInt 32 1
+         %20 = OpConstant %19 1
+         %21 = OpTypePointer Uniform %15
+         %35 = OpConstant %19 0
+         %39 = OpConstant %6 10
+         %42 = OpConstant %6 0.5
+         %43 = OpConstant %6 0.699999988
+         %49 = OpConstant %15 0
+         %50 = OpTypeBool
+         %54 = OpConstant %6 0.100000001
+         %61 = OpTypeVector %6 4
+         %62 = OpTypePointer Output %61
+         %63 = OpVariable %62 Output
+         %66 = OpConstant %6 1
+         %68 = OpTypePointer Input %6
+         %69 = OpVariable %68 Input
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+         %64 = OpFunctionCall %6 %8
+         %65 = OpFunctionCall %6 %10
+         %67 = OpCompositeConstruct %61 %64 %65 %14 %66
+               OpStore %63 %67
+               OpReturn
+               OpFunctionEnd
+          %8 = OpFunction %6 None %7
+          %9 = OpLabel
+         %13 = OpVariable %12 Function
+               OpStore %13 %14
+         %22 = OpAccessChain %21 %18 %20
+         %23 = OpLoad %15 %22
+         %24 = OpConvertUToF %6 %23
+         %25 = OpExtInst %6 %1 Log2 %24
+         %26 = OpLoad %6 %13
+         %27 = OpFAdd %6 %26 %25
+               OpStore %13 %27
+         %28 = OpLoad %6 %13
+         %29 = OpLoad %6 %13
+         %30 = OpExtInst %6 %1 Sqrt %29
+         %31 = OpFSub %6 %28 %30
+               OpReturnValue %31
+               OpFunctionEnd
+         %10 = OpFunction %6 None %7
+         %11 = OpLabel
+         %34 = OpVariable %12 Function
+         %36 = OpAccessChain %21 %18 %35
+         %37 = OpLoad %15 %36
+         %38 = OpConvertUToF %6 %37
+         %40 = OpFDiv %6 %38 %39
+               OpStore %34 %40
+         %41 = OpLoad %6 %34
+         %44 = OpExtInst %6 %1 FClamp %41 %42 %43
+         %45 = OpLoad %6 %34
+         %46 = OpFMul %6 %45 %44
+               OpStore %34 %46
+         %47 = OpAccessChain %21 %18 %20
+         %48 = OpLoad %15 %47
+         %51 = OpINotEqual %50 %48 %49
+               OpSelectionMerge %53 None
+               OpBranchConditional %51 %52 %53
+         %52 = OpLabel
+         %55 = OpLoad %6 %34
+         %56 = OpFSub %6 %55 %54
+               OpStore %34 %56
+               OpBranch %53
+         %53 = OpLabel
+         %57 = OpLoad %6 %34
+         %58 = OpExtInst %6 %1 Exp %57
+               OpReturnValue %58
+               OpFunctionEnd
+
+)";
+  constexpr char kDiff[] = R"( ; SPIR-V
+ ; Version: 1.6
+ ; Generator: Khronos SPIR-V Tools Assembler; 0
+-; Bound: 69
++; Bound: 81
+ ; Schema: 0
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main" %63 %68
+ OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 310
+ OpDecorate %8 RelaxedPrecision
+ OpDecorate %10 RelaxedPrecision
+ OpDecorate %13 RelaxedPrecision
+ OpMemberDecorate %16 0 RelaxedPrecision
+ OpMemberDecorate %16 0 Offset 0
+ OpMemberDecorate %16 1 RelaxedPrecision
+ OpMemberDecorate %16 1 Offset 4
+ OpDecorate %16 Block
+ OpDecorate %18 DescriptorSet 0
+ OpDecorate %18 Binding 0
+-OpDecorate %23 RelaxedPrecision
+-OpDecorate %30 RelaxedPrecision
+-OpDecorate %31 RelaxedPrecision
+ OpDecorate %34 RelaxedPrecision
+ OpDecorate %35 RelaxedPrecision
+ OpDecorate %36 RelaxedPrecision
+ OpDecorate %37 RelaxedPrecision
+ OpDecorate %38 RelaxedPrecision
+ OpDecorate %39 RelaxedPrecision
+ OpDecorate %40 RelaxedPrecision
+ OpDecorate %41 RelaxedPrecision
+ OpDecorate %42 RelaxedPrecision
+ OpDecorate %45 RelaxedPrecision
+ OpDecorate %47 RelaxedPrecision
+ OpDecorate %48 RelaxedPrecision
+ OpDecorate %50 RelaxedPrecision
+ OpDecorate %51 RelaxedPrecision
+ OpDecorate %54 RelaxedPrecision
+ OpDecorate %55 RelaxedPrecision
+ OpDecorate %56 RelaxedPrecision
++OpDecorate %72 RelaxedPrecision
+ OpDecorate %57 RelaxedPrecision
++OpDecorate %77 RelaxedPrecision
++OpDecorate %78 RelaxedPrecision
+ OpDecorate %58 RelaxedPrecision
+ OpDecorate %63 RelaxedPrecision
+ OpDecorate %63 Location 0
+ OpDecorate %64 RelaxedPrecision
+ OpDecorate %65 RelaxedPrecision
+ OpDecorate %66 RelaxedPrecision
+ OpDecorate %68 RelaxedPrecision
+ OpDecorate %68 Location 0
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %6 = OpTypeFloat 32
+ %7 = OpTypeFunction %6
+ %12 = OpTypePointer Function %6
+ %14 = OpConstant %6 0
+ %15 = OpTypeInt 32 0
+ %16 = OpTypeStruct %15 %15
+ %17 = OpTypePointer Uniform %16
+ %18 = OpVariable %17 Uniform
+ %19 = OpTypeInt 32 1
+ %20 = OpConstant %19 0
+ %21 = OpTypePointer Uniform %15
+ %24 = OpConstant %15 0
+ %25 = OpTypeBool
+ %29 = OpConstant %6 1
+ %32 = OpConstant %19 1
+ %49 = OpConstant %6 10
+ %52 = OpConstant %6 0.5
++%76 = OpConstant %6 0.100000001
+ %53 = OpConstant %6 0.699999988
+ %61 = OpTypeVector %6 4
+ %62 = OpTypePointer Output %61
+ %63 = OpVariable %62 Output
+ %67 = OpTypePointer Input %6
+ %68 = OpVariable %67 Input
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ %64 = OpFunctionCall %6 %8
+ %65 = OpFunctionCall %6 %10
+ %66 = OpCompositeConstruct %61 %64 %65 %14 %29
+ OpStore %63 %66
+ OpReturn
+ OpFunctionEnd
+ %8 = OpFunction %6 None %7
+ %9 = OpLabel
+ %13 = OpVariable %12 Function
+ OpStore %13 %14
+-%22 = OpAccessChain %21 %18 %20
+-%23 = OpLoad %15 %22
+-%26 = OpINotEqual %25 %23 %24
+-OpSelectionMerge %28 None
+-OpBranchConditional %26 %27 %28
+-%27 = OpLabel
+-%30 = OpLoad %6 %13
+-%31 = OpFAdd %6 %30 %29
+-OpStore %13 %31
+-OpBranch %28
+-%28 = OpLabel
+ %33 = OpAccessChain %21 %18 %32
+ %34 = OpLoad %15 %33
+ %35 = OpConvertUToF %6 %34
+ %36 = OpExtInst %6 %1 Log2 %35
+ %37 = OpLoad %6 %13
+ %38 = OpFAdd %6 %37 %36
+ OpStore %13 %38
+ %39 = OpLoad %6 %13
+ %40 = OpLoad %6 %13
+ %41 = OpExtInst %6 %1 Sqrt %40
+ %42 = OpFSub %6 %39 %41
+ OpReturnValue %42
+ OpFunctionEnd
+ %10 = OpFunction %6 None %7
+ %11 = OpLabel
+ %45 = OpVariable %12 Function
+ %46 = OpAccessChain %21 %18 %20
+ %47 = OpLoad %15 %46
+ %48 = OpConvertUToF %6 %47
+ %50 = OpFDiv %6 %48 %49
+ OpStore %45 %50
+ %51 = OpLoad %6 %45
+ %54 = OpExtInst %6 %1 FClamp %51 %52 %53
+ %55 = OpLoad %6 %45
+ %56 = OpFMul %6 %55 %54
+ OpStore %45 %56
++%71 = OpAccessChain %21 %18 %32
++%72 = OpLoad %15 %71
++%73 = OpINotEqual %25 %72 %24
++OpSelectionMerge %75 None
++OpBranchConditional %73 %74 %75
++%74 = OpLabel
+ %57 = OpLoad %6 %45
++%77 = OpFSub %6 %57 %76
++OpStore %45 %77
++OpBranch %75
++%75 = OpLabel
++%78 = OpLoad %6 %45
+-%58 = OpExtInst %6 %1 Exp %57
++%58 = OpExtInst %6 %1 Exp %78
+ OpReturnValue %58
+ OpFunctionEnd
+)";
+  Options options;
+  DoStringDiffTest(kSrcNoDebug, kDstNoDebug, kDiff, options);
+}
+
+}  // namespace
+}  // namespace diff
+}  // namespace spvtools

+ 136 - 0
ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/extra_if_block_dst.spvasm

@@ -0,0 +1,136 @@
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %4 "main" %63 %69
+               OpExecutionMode %4 OriginUpperLeft
+               OpSource ESSL 310
+               OpName %4 "main"
+               OpName %8 "f1("
+               OpName %10 "f2("
+               OpName %13 "v"
+               OpName %16 "Buffer"
+               OpMemberName %16 0 "flag1"
+               OpMemberName %16 1 "flag2"
+               OpName %18 ""
+               OpName %34 "v"
+               OpName %63 "color"
+               OpName %69 "v"
+               OpDecorate %8 RelaxedPrecision
+               OpDecorate %10 RelaxedPrecision
+               OpDecorate %13 RelaxedPrecision
+               OpMemberDecorate %16 0 RelaxedPrecision
+               OpMemberDecorate %16 0 Offset 0
+               OpMemberDecorate %16 1 RelaxedPrecision
+               OpMemberDecorate %16 1 Offset 4
+               OpDecorate %16 Block
+               OpDecorate %18 DescriptorSet 0
+               OpDecorate %18 Binding 0
+               OpDecorate %23 RelaxedPrecision
+               OpDecorate %24 RelaxedPrecision
+               OpDecorate %25 RelaxedPrecision
+               OpDecorate %26 RelaxedPrecision
+               OpDecorate %27 RelaxedPrecision
+               OpDecorate %28 RelaxedPrecision
+               OpDecorate %29 RelaxedPrecision
+               OpDecorate %30 RelaxedPrecision
+               OpDecorate %31 RelaxedPrecision
+               OpDecorate %34 RelaxedPrecision
+               OpDecorate %37 RelaxedPrecision
+               OpDecorate %38 RelaxedPrecision
+               OpDecorate %40 RelaxedPrecision
+               OpDecorate %41 RelaxedPrecision
+               OpDecorate %44 RelaxedPrecision
+               OpDecorate %45 RelaxedPrecision
+               OpDecorate %46 RelaxedPrecision
+               OpDecorate %48 RelaxedPrecision
+               OpDecorate %55 RelaxedPrecision
+               OpDecorate %56 RelaxedPrecision
+               OpDecorate %57 RelaxedPrecision
+               OpDecorate %58 RelaxedPrecision
+               OpDecorate %63 RelaxedPrecision
+               OpDecorate %63 Location 0
+               OpDecorate %64 RelaxedPrecision
+               OpDecorate %65 RelaxedPrecision
+               OpDecorate %67 RelaxedPrecision
+               OpDecorate %69 RelaxedPrecision
+               OpDecorate %69 Location 0
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeFloat 32
+          %7 = OpTypeFunction %6
+         %12 = OpTypePointer Function %6
+         %14 = OpConstant %6 0
+         %15 = OpTypeInt 32 0
+         %16 = OpTypeStruct %15 %15
+         %17 = OpTypePointer Uniform %16
+         %18 = OpVariable %17 Uniform
+         %19 = OpTypeInt 32 1
+         %20 = OpConstant %19 1
+         %21 = OpTypePointer Uniform %15
+         %35 = OpConstant %19 0
+         %39 = OpConstant %6 10
+         %42 = OpConstant %6 0.5
+         %43 = OpConstant %6 0.699999988
+         %49 = OpConstant %15 0
+         %50 = OpTypeBool
+         %54 = OpConstant %6 0.100000001
+         %61 = OpTypeVector %6 4
+         %62 = OpTypePointer Output %61
+         %63 = OpVariable %62 Output
+         %66 = OpConstant %6 1
+         %68 = OpTypePointer Input %6
+         %69 = OpVariable %68 Input
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+         %64 = OpFunctionCall %6 %8
+         %65 = OpFunctionCall %6 %10
+         %67 = OpCompositeConstruct %61 %64 %65 %14 %66
+               OpStore %63 %67
+               OpReturn
+               OpFunctionEnd
+          %8 = OpFunction %6 None %7
+          %9 = OpLabel
+         %13 = OpVariable %12 Function
+               OpStore %13 %14
+         %22 = OpAccessChain %21 %18 %20
+         %23 = OpLoad %15 %22
+         %24 = OpConvertUToF %6 %23
+         %25 = OpExtInst %6 %1 Log2 %24
+         %26 = OpLoad %6 %13
+         %27 = OpFAdd %6 %26 %25
+               OpStore %13 %27
+         %28 = OpLoad %6 %13
+         %29 = OpLoad %6 %13
+         %30 = OpExtInst %6 %1 Sqrt %29
+         %31 = OpFSub %6 %28 %30
+               OpReturnValue %31
+               OpFunctionEnd
+         %10 = OpFunction %6 None %7
+         %11 = OpLabel
+         %34 = OpVariable %12 Function
+         %36 = OpAccessChain %21 %18 %35
+         %37 = OpLoad %15 %36
+         %38 = OpConvertUToF %6 %37
+         %40 = OpFDiv %6 %38 %39
+               OpStore %34 %40
+         %41 = OpLoad %6 %34
+         %44 = OpExtInst %6 %1 FClamp %41 %42 %43
+         %45 = OpLoad %6 %34
+         %46 = OpFMul %6 %45 %44
+               OpStore %34 %46
+         %47 = OpAccessChain %21 %18 %20
+         %48 = OpLoad %15 %47
+         %51 = OpINotEqual %50 %48 %49
+               OpSelectionMerge %53 None
+               OpBranchConditional %51 %52 %53
+         %52 = OpLabel
+         %55 = OpLoad %6 %34
+         %56 = OpFSub %6 %55 %54
+               OpStore %34 %56
+               OpBranch %53
+         %53 = OpLabel
+         %57 = OpLoad %6 %34
+         %58 = OpExtInst %6 %1 Exp %57
+               OpReturnValue %58
+               OpFunctionEnd
+

+ 137 - 0
ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/extra_if_block_src.spvasm

@@ -0,0 +1,137 @@
+;; Test where src has an extra if block in one function, and dst has an extra
+;; if block in another function.
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %4 "main" %63 %68
+               OpExecutionMode %4 OriginUpperLeft
+               OpSource ESSL 310
+               OpName %4 "main"
+               OpName %8 "f1("
+               OpName %10 "f2("
+               OpName %13 "v"
+               OpName %16 "Buffer"
+               OpMemberName %16 0 "flag1"
+               OpMemberName %16 1 "flag2"
+               OpName %18 ""
+               OpName %45 "v"
+               OpName %63 "color"
+               OpName %68 "v"
+               OpDecorate %8 RelaxedPrecision
+               OpDecorate %10 RelaxedPrecision
+               OpDecorate %13 RelaxedPrecision
+               OpMemberDecorate %16 0 RelaxedPrecision
+               OpMemberDecorate %16 0 Offset 0
+               OpMemberDecorate %16 1 RelaxedPrecision
+               OpMemberDecorate %16 1 Offset 4
+               OpDecorate %16 Block
+               OpDecorate %18 DescriptorSet 0
+               OpDecorate %18 Binding 0
+               OpDecorate %23 RelaxedPrecision
+               OpDecorate %30 RelaxedPrecision
+               OpDecorate %31 RelaxedPrecision
+               OpDecorate %34 RelaxedPrecision
+               OpDecorate %35 RelaxedPrecision
+               OpDecorate %36 RelaxedPrecision
+               OpDecorate %37 RelaxedPrecision
+               OpDecorate %38 RelaxedPrecision
+               OpDecorate %39 RelaxedPrecision
+               OpDecorate %40 RelaxedPrecision
+               OpDecorate %41 RelaxedPrecision
+               OpDecorate %42 RelaxedPrecision
+               OpDecorate %45 RelaxedPrecision
+               OpDecorate %47 RelaxedPrecision
+               OpDecorate %48 RelaxedPrecision
+               OpDecorate %50 RelaxedPrecision
+               OpDecorate %51 RelaxedPrecision
+               OpDecorate %54 RelaxedPrecision
+               OpDecorate %55 RelaxedPrecision
+               OpDecorate %56 RelaxedPrecision
+               OpDecorate %57 RelaxedPrecision
+               OpDecorate %58 RelaxedPrecision
+               OpDecorate %63 RelaxedPrecision
+               OpDecorate %63 Location 0
+               OpDecorate %64 RelaxedPrecision
+               OpDecorate %65 RelaxedPrecision
+               OpDecorate %66 RelaxedPrecision
+               OpDecorate %68 RelaxedPrecision
+               OpDecorate %68 Location 0
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeFloat 32
+          %7 = OpTypeFunction %6
+         %12 = OpTypePointer Function %6
+         %14 = OpConstant %6 0
+         %15 = OpTypeInt 32 0
+         %16 = OpTypeStruct %15 %15
+         %17 = OpTypePointer Uniform %16
+         %18 = OpVariable %17 Uniform
+         %19 = OpTypeInt 32 1
+         %20 = OpConstant %19 0
+         %21 = OpTypePointer Uniform %15
+         %24 = OpConstant %15 0
+         %25 = OpTypeBool
+         %29 = OpConstant %6 1
+         %32 = OpConstant %19 1
+         %49 = OpConstant %6 10
+         %52 = OpConstant %6 0.5
+         %53 = OpConstant %6 0.699999988
+         %61 = OpTypeVector %6 4
+         %62 = OpTypePointer Output %61
+         %63 = OpVariable %62 Output
+         %67 = OpTypePointer Input %6
+         %68 = OpVariable %67 Input
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+         %64 = OpFunctionCall %6 %8
+         %65 = OpFunctionCall %6 %10
+         %66 = OpCompositeConstruct %61 %64 %65 %14 %29
+               OpStore %63 %66
+               OpReturn
+               OpFunctionEnd
+          %8 = OpFunction %6 None %7
+          %9 = OpLabel
+         %13 = OpVariable %12 Function
+               OpStore %13 %14
+         %22 = OpAccessChain %21 %18 %20
+         %23 = OpLoad %15 %22
+         %26 = OpINotEqual %25 %23 %24
+               OpSelectionMerge %28 None
+               OpBranchConditional %26 %27 %28
+         %27 = OpLabel
+         %30 = OpLoad %6 %13
+         %31 = OpFAdd %6 %30 %29
+               OpStore %13 %31
+               OpBranch %28
+         %28 = OpLabel
+         %33 = OpAccessChain %21 %18 %32
+         %34 = OpLoad %15 %33
+         %35 = OpConvertUToF %6 %34
+         %36 = OpExtInst %6 %1 Log2 %35
+         %37 = OpLoad %6 %13
+         %38 = OpFAdd %6 %37 %36
+               OpStore %13 %38
+         %39 = OpLoad %6 %13
+         %40 = OpLoad %6 %13
+         %41 = OpExtInst %6 %1 Sqrt %40
+         %42 = OpFSub %6 %39 %41
+               OpReturnValue %42
+               OpFunctionEnd
+         %10 = OpFunction %6 None %7
+         %11 = OpLabel
+         %45 = OpVariable %12 Function
+         %46 = OpAccessChain %21 %18 %20
+         %47 = OpLoad %15 %46
+         %48 = OpConvertUToF %6 %47
+         %50 = OpFDiv %6 %48 %49
+               OpStore %45 %50
+         %51 = OpLoad %6 %45
+         %54 = OpExtInst %6 %1 FClamp %51 %52 %53
+         %55 = OpLoad %6 %45
+         %56 = OpFMul %6 %55 %54
+               OpStore %45 %56
+         %57 = OpLoad %6 %45
+         %58 = OpExtInst %6 %1 Exp %57
+               OpReturnValue %58
+               OpFunctionEnd
+

+ 304 - 0
ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/generate_tests.py

@@ -0,0 +1,304 @@
+#! /usr/bin/python3
+#
+# 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.
+
+import glob
+import os
+import subprocess
+import sys
+
+# A handful of relevant tests are hand-picked to generate extra unit tests with
+# specific options of spirv-diff.
+IGNORE_SET_BINDING_TESTS = ['different_decorations_vertex']
+IGNORE_LOCATION_TESTS = ['different_decorations_fragment']
+IGNORE_DECORATIONS_TESTS = ['different_decorations_vertex', 'different_decorations_fragment']
+DUMP_IDS_TESTS = ['basic', 'int_vs_uint_constants', 'multiple_same_entry_points', 'small_functions_small_diffs']
+
+LICENSE = u"""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.
+"""
+
+TEMPLATE_TEST_FILE = u"""// GENERATED FILE - DO NOT EDIT.
+// Generated by {script_name}
+//
+{license}
+
+#include "../diff_test_utils.h"
+
+#include "gtest/gtest.h"
+
+namespace spvtools {{
+namespace diff {{
+namespace {{
+
+{test_comment}
+constexpr char kSrc[] = R"({src_spirv})";
+constexpr char kDst[] = R"({dst_spirv})";
+
+TEST(DiffTest, {test_name}) {{
+  constexpr char kDiff[] = R"({diff_spirv})";
+  Options options;
+  DoStringDiffTest(kSrc, kDst, kDiff, options);
+}}
+
+TEST(DiffTest, {test_name}NoDebug) {{
+  constexpr char kSrcNoDebug[] = R"({src_spirv_no_debug})";
+  constexpr char kDstNoDebug[] = R"({dst_spirv_no_debug})";
+  constexpr char kDiff[] = R"({diff_spirv_no_debug})";
+  Options options;
+  DoStringDiffTest(kSrcNoDebug, kDstNoDebug, kDiff, options);
+}}
+{extra_tests}
+}}  // namespace
+}}  // namespace diff
+}}  // namespace spvtools
+"""
+
+TEMPLATE_TEST_FUNC = u"""
+TEST(DiffTest, {test_name}{test_tag}) {{
+  constexpr char kDiff[] = R"({diff_spirv})";
+  Options options;
+  {test_options}
+  DoStringDiffTest(kSrc, kDst, kDiff, options);
+}}
+"""
+
+TEMPLATE_TEST_FILES_CMAKE = u"""# GENERATED FILE - DO NOT EDIT.
+# Generated by {script_name}
+#
+{license}
+
+list(APPEND DIFF_TEST_FILES
+{test_files}
+)
+"""
+
+VARIANT_NONE = 0
+VARIANT_IGNORE_SET_BINDING = 1
+VARIANT_IGNORE_LOCATION = 2
+VARIANT_IGNORE_DECORATIONS = 3
+VARIANT_DUMP_IDS = 4
+
+def print_usage():
+    print("Usage: {} <path-to-spirv-diff>".format(sys.argv[0]))
+
+def remove_debug_info(in_path):
+    tmp_dir = '.no_dbg'
+
+    if not os.path.exists(tmp_dir):
+        os.makedirs(tmp_dir)
+
+    (in_basename, in_ext) = os.path.splitext(in_path)
+    out_name = in_basename + '_no_dbg' + in_ext
+    out_path = os.path.join(tmp_dir, out_name)
+
+    with open(in_path, 'r') as fin:
+        with open(out_path, 'w') as fout:
+            for line in fin:
+                ops = line.strip().split()
+                op = ops[0] if len(ops) > 0 else ''
+                if (op != ';;' and op != 'OpName' and op != 'OpMemberName' and op != 'OpString' and
+                    op != 'OpLine' and op != 'OpNoLine' and op != 'OpModuleProcessed'):
+                    fout.write(line)
+
+    return out_path
+
+def make_src_file(test_name):
+    return '{}_src.spvasm'.format(test_name)
+
+def make_dst_file(test_name):
+    return '{}_dst.spvasm'.format(test_name)
+
+def make_cpp_file(test_name):
+    return '{}_autogen.cpp'.format(test_name)
+
+def make_camel_case(test_name):
+    return test_name.replace('_', ' ').title().replace(' ', '')
+
+def make_comment(text, comment_prefix):
+    return '\n'.join([comment_prefix + (' ' if line.strip() else '') + line for line in text.splitlines()])
+
+def read_file(file_name):
+    with open(file_name, 'r') as f:
+        content = f.read()
+
+    # Use unix line endings.
+    content = content.replace('\r\n', '\n')
+
+    return content
+
+def parse_test_comment(src_spirv_file_name, src_spirv):
+    src_spirv_lines = src_spirv.splitlines()
+    comment_line_count = 0
+    while comment_line_count < len(src_spirv_lines):
+        if not src_spirv_lines[comment_line_count].strip().startswith(';;'):
+            break
+        comment_line_count += 1
+
+    if comment_line_count == 0:
+        print("Expected comment on test file '{}'.  See README.md next to this file.".format(src_spirv_file_name))
+        sys.exit(1)
+
+    comment_block = src_spirv_lines[:comment_line_count]
+    spirv_block = src_spirv_lines[comment_line_count:]
+
+    comment_block = ['// ' + line.replace(';;', '').strip() for line in comment_block]
+
+    return '\n'.join(spirv_block), '\n'.join(comment_block)
+
+def run_diff_tool(diff_tool, src_file, dst_file, variant):
+    args = [diff_tool]
+
+    if variant == VARIANT_IGNORE_SET_BINDING or variant == VARIANT_IGNORE_DECORATIONS:
+        args.append('--ignore-set-binding')
+
+    if variant == VARIANT_IGNORE_LOCATION or variant == VARIANT_IGNORE_DECORATIONS:
+        args.append('--ignore-location')
+
+    if variant == VARIANT_DUMP_IDS:
+        args.append('--with-id-map')
+
+    args.append('--no-color')
+    args.append('--no-indent')
+
+    args.append(src_file)
+    args.append(dst_file)
+
+    success = True
+    print(' '.join(args))
+    process = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
+    out, err = process.communicate()
+
+    if process.returncode != 0:
+        print(err)
+        sys.exit(process.returncode)
+
+    # Use unix line endings.
+    out = out.replace('\r\n', '\n')
+
+    return out
+
+def generate_extra_test(diff_tool, src_file, dst_file, variant, test_name_camel_case, test_tag, test_options):
+    diff = run_diff_tool(diff_tool, src_file, dst_file, variant)
+    return TEMPLATE_TEST_FUNC.format(
+        test_name = test_name_camel_case,
+        test_tag = test_tag,
+        test_options = test_options,
+        diff_spirv = diff)
+
+def generate_test(diff_tool, test_name):
+    src_file = make_src_file(test_name)
+    dst_file = make_dst_file(test_name)
+    src_file_no_debug = remove_debug_info(src_file)
+    dst_file_no_debug = remove_debug_info(dst_file)
+
+    src_spirv = read_file(src_file)
+    dst_spirv = read_file(dst_file)
+    src_spirv_no_debug = read_file(src_file_no_debug)
+    dst_spirv_no_debug = read_file(dst_file_no_debug)
+
+    test_name_camel_case = make_camel_case(test_name)
+
+    diff_spirv = run_diff_tool(diff_tool, src_file, dst_file, VARIANT_NONE)
+    diff_spirv_no_debug = run_diff_tool(diff_tool, src_file_no_debug, dst_file_no_debug, VARIANT_NONE)
+
+    extra_tests = []
+
+    if test_name in IGNORE_SET_BINDING_TESTS:
+        extra_tests.append(generate_extra_test(diff_tool, src_file, dst_file, VARIANT_IGNORE_SET_BINDING,
+            test_name_camel_case, 'IgnoreSetBinding', 'options.ignore_set_binding = true;'))
+
+    if test_name in IGNORE_LOCATION_TESTS:
+        extra_tests.append(generate_extra_test(diff_tool, src_file, dst_file, VARIANT_IGNORE_LOCATION,
+            test_name_camel_case, 'IgnoreLocation', 'options.ignore_location = true;'))
+
+    if test_name in IGNORE_DECORATIONS_TESTS:
+        extra_tests.append(generate_extra_test(diff_tool, src_file, dst_file, VARIANT_IGNORE_DECORATIONS,
+            test_name_camel_case, 'IgnoreSetBindingLocation',
+            '\n  '.join(['options.ignore_set_binding = true;', 'options.ignore_location = true;'])))
+
+    if test_name in DUMP_IDS_TESTS:
+        extra_tests.append(generate_extra_test(diff_tool, src_file, dst_file, VARIANT_DUMP_IDS,
+            test_name_camel_case, 'DumpIds', 'options.dump_id_map = true;'))
+
+    src_spirv, test_comment = parse_test_comment(src_file, src_spirv)
+
+    test_file = TEMPLATE_TEST_FILE.format(
+            script_name = os.path.basename(__file__),
+            license = make_comment(LICENSE, '//'),
+            test_comment = test_comment,
+            test_name = test_name_camel_case,
+            src_spirv = src_spirv,
+            dst_spirv = dst_spirv,
+            diff_spirv = diff_spirv,
+            src_spirv_no_debug = src_spirv_no_debug,
+            dst_spirv_no_debug = dst_spirv_no_debug,
+            diff_spirv_no_debug = diff_spirv_no_debug,
+            extra_tests = ''.join(extra_tests))
+
+    test_file_name = make_cpp_file(test_name)
+    with open(test_file_name, 'wb') as fout:
+        fout.write(str.encode(test_file))
+
+    return test_file_name
+
+def generate_tests(diff_tool, test_names):
+    return [generate_test(diff_tool, test_name) for test_name in test_names]
+
+def generate_cmake(test_files):
+    cmake = TEMPLATE_TEST_FILES_CMAKE.format(
+            script_name = os.path.basename(__file__),
+            license = make_comment(LICENSE, '#'),
+            test_files = '\n'.join(['"diff_files/{}"'.format(f) for f in test_files]))
+
+    with open('diff_test_files_autogen.cmake', 'wb') as fout:
+        fout.write(str.encode(cmake))
+
+def main():
+
+    if len(sys.argv) != 2:
+        print_usage()
+        return 1
+
+    diff_tool = sys.argv[1]
+    if not os.path.exists(diff_tool):
+        print("No such file: {}".format(diff_tool))
+        print_usage()
+        return 1
+
+    diff_tool = os.path.realpath(diff_tool)
+    os.chdir(os.path.dirname(__file__))
+
+    test_names = sorted([f[:-11] for f in glob.glob("*_src.spvasm")])
+
+    test_files = generate_tests(diff_tool, test_names)
+
+    generate_cmake(test_files)
+
+    return 0
+
+if __name__ == '__main__':
+    sys.exit(main())

+ 733 - 0
ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/index_signedness_autogen.cpp

@@ -0,0 +1,733 @@
+// GENERATED FILE - DO NOT EDIT.
+// Generated by generate_tests.py
+//
+// 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 "../diff_test_utils.h"
+
+#include "gtest/gtest.h"
+
+namespace spvtools {
+namespace diff {
+namespace {
+
+// Test where signedness of indices are different between src and dst.
+constexpr char kSrc[] = R"(               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %4 "main"
+               OpExecutionMode %4 LocalSize 1 1 1
+               OpSource ESSL 310
+               OpName %4 "main"
+               OpName %13 "BufferOut"
+               OpMemberName %13 0 "o1"
+               OpMemberName %13 1 "o2"
+               OpMemberName %13 2 "o3"
+               OpName %15 ""
+               OpName %22 "BufferIn"
+               OpMemberName %22 0 "i1"
+               OpMemberName %22 1 "i2"
+               OpName %24 ""
+               OpDecorate %8 ArrayStride 4
+               OpDecorate %9 ArrayStride 4
+               OpDecorate %11 ArrayStride 4
+               OpDecorate %12 ArrayStride 8
+               OpMemberDecorate %13 0 Offset 0
+               OpMemberDecorate %13 1 Offset 12
+               OpMemberDecorate %13 2 Offset 24
+               OpDecorate %13 BufferBlock
+               OpDecorate %15 DescriptorSet 0
+               OpDecorate %15 Binding 1
+               OpDecorate %18 ArrayStride 16
+               OpDecorate %19 ArrayStride 48
+               OpDecorate %21 ArrayStride 16
+               OpMemberDecorate %22 0 Offset 0
+               OpMemberDecorate %22 1 Offset 96
+               OpDecorate %22 Block
+               OpDecorate %24 DescriptorSet 0
+               OpDecorate %24 Binding 0
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeInt 32 0
+          %7 = OpConstant %6 3
+          %8 = OpTypeArray %6 %7
+          %9 = OpTypeArray %6 %7
+         %10 = OpConstant %6 2
+         %11 = OpTypeArray %6 %10
+         %12 = OpTypeArray %11 %10
+         %13 = OpTypeStruct %8 %9 %12
+         %14 = OpTypePointer Uniform %13
+         %15 = OpVariable %14 Uniform
+         %16 = OpTypeInt 32 1
+         %17 = OpConstant %16 0
+         %18 = OpTypeArray %6 %7
+         %19 = OpTypeArray %18 %10
+         %20 = OpConstant %6 4
+         %21 = OpTypeArray %6 %20
+         %22 = OpTypeStruct %19 %21
+         %23 = OpTypePointer Uniform %22
+         %24 = OpVariable %23 Uniform
+         %25 = OpTypePointer Uniform %6
+         %28 = OpConstant %6 1
+         %31 = OpConstant %16 1
+         %34 = OpConstant %6 0
+         %37 = OpConstant %16 2
+         %61 = OpConstant %16 3
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+         %26 = OpAccessChain %25 %24 %17 %17 %17
+         %27 = OpLoad %6 %26
+         %29 = OpIAdd %6 %27 %28
+         %30 = OpAccessChain %25 %15 %17 %17
+               OpStore %30 %29
+         %32 = OpAccessChain %25 %24 %17 %31 %17
+         %33 = OpLoad %6 %32
+         %35 = OpIAdd %6 %33 %34
+         %36 = OpAccessChain %25 %15 %17 %31
+               OpStore %36 %35
+         %38 = OpAccessChain %25 %24 %17 %31 %31
+         %39 = OpLoad %6 %38
+         %40 = OpIAdd %6 %39 %10
+         %41 = OpAccessChain %25 %15 %17 %37
+               OpStore %41 %40
+         %42 = OpAccessChain %25 %24 %17 %17 %37
+         %43 = OpLoad %6 %42
+         %44 = OpAccessChain %25 %15 %31 %17
+               OpStore %44 %43
+         %45 = OpAccessChain %25 %24 %17 %17 %31
+         %46 = OpLoad %6 %45
+         %47 = OpIMul %6 %46 %7
+         %48 = OpAccessChain %25 %15 %31 %31
+               OpStore %48 %47
+         %49 = OpAccessChain %25 %24 %17 %31 %37
+         %50 = OpLoad %6 %49
+         %51 = OpAccessChain %25 %15 %31 %37
+               OpStore %51 %50
+         %52 = OpAccessChain %25 %24 %31 %17
+         %53 = OpLoad %6 %52
+         %54 = OpAccessChain %25 %15 %37 %17 %17
+               OpStore %54 %53
+         %55 = OpAccessChain %25 %24 %31 %31
+         %56 = OpLoad %6 %55
+         %57 = OpAccessChain %25 %15 %37 %17 %31
+               OpStore %57 %56
+         %58 = OpAccessChain %25 %24 %31 %37
+         %59 = OpLoad %6 %58
+         %60 = OpAccessChain %25 %15 %37 %31 %17
+               OpStore %60 %59
+         %62 = OpAccessChain %25 %24 %31 %61
+         %63 = OpLoad %6 %62
+         %64 = OpAccessChain %25 %15 %37 %31 %31
+               OpStore %64 %63
+               OpReturn
+               OpFunctionEnd
+)";
+constexpr char kDst[] = R"(               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %4 "main"
+               OpExecutionMode %4 LocalSize 1 1 1
+               OpSource ESSL 310
+               OpName %4 "main"
+               OpName %13 "BufferOut"
+               OpMemberName %13 0 "o1"
+               OpMemberName %13 1 "o2"
+               OpMemberName %13 2 "o3"
+               OpName %15 ""
+               OpName %22 "BufferIn"
+               OpMemberName %22 0 "i1"
+               OpMemberName %22 1 "i2"
+               OpName %24 ""
+               OpDecorate %8 ArrayStride 4
+               OpDecorate %9 ArrayStride 4
+               OpDecorate %11 ArrayStride 4
+               OpDecorate %12 ArrayStride 8
+               OpMemberDecorate %13 0 Offset 0
+               OpMemberDecorate %13 1 Offset 12
+               OpMemberDecorate %13 2 Offset 24
+               OpDecorate %13 BufferBlock
+               OpDecorate %15 DescriptorSet 0
+               OpDecorate %15 Binding 1
+               OpDecorate %18 ArrayStride 16
+               OpDecorate %19 ArrayStride 48
+               OpDecorate %21 ArrayStride 16
+               OpMemberDecorate %22 0 Offset 0
+               OpMemberDecorate %22 1 Offset 96
+               OpDecorate %22 Block
+               OpDecorate %24 DescriptorSet 0
+               OpDecorate %24 Binding 0
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeInt 32 0
+         %16 = OpTypeInt 32 1
+          %7 = OpConstant %16 3
+          %8 = OpTypeArray %6 %7
+          %9 = OpTypeArray %6 %7
+         %10 = OpConstant %16 2
+         %11 = OpTypeArray %6 %10
+         %12 = OpTypeArray %11 %10
+         %13 = OpTypeStruct %8 %9 %12
+         %14 = OpTypePointer Uniform %13
+         %15 = OpVariable %14 Uniform
+         %18 = OpTypeArray %6 %7
+         %19 = OpTypeArray %18 %10
+         %20 = OpConstant %16 4
+         %21 = OpTypeArray %6 %20
+         %22 = OpTypeStruct %19 %21
+         %23 = OpTypePointer Uniform %22
+         %24 = OpVariable %23 Uniform
+         %25 = OpTypePointer Uniform %6
+         %17 = OpConstant %16 0
+         %28 = OpConstant %16 1
+         %31 = OpConstant %6 1
+         %34 = OpConstant %6 0
+         %37 = OpConstant %6 2
+         %61 = OpConstant %6 3
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+         %26 = OpAccessChain %25 %24 %17 %17 %17
+         %27 = OpLoad %6 %26
+         %29 = OpIAdd %6 %27 %28
+         %30 = OpAccessChain %25 %15 %17 %17
+               OpStore %30 %29
+         %32 = OpAccessChain %25 %24 %17 %31 %17
+         %33 = OpLoad %6 %32
+         %35 = OpIAdd %6 %33 %34
+         %36 = OpAccessChain %25 %15 %17 %31
+               OpStore %36 %35
+         %38 = OpAccessChain %25 %24 %17 %31 %31
+         %39 = OpLoad %6 %38
+         %40 = OpIAdd %6 %39 %37
+         %41 = OpAccessChain %25 %15 %17 %10
+               OpStore %41 %40
+         %42 = OpAccessChain %25 %24 %17 %17 %10
+         %43 = OpLoad %6 %42
+         %44 = OpAccessChain %25 %15 %31 %17
+               OpStore %44 %43
+         %45 = OpAccessChain %25 %24 %17 %17 %31
+         %46 = OpLoad %6 %45
+         %47 = OpIMul %6 %46 %7
+         %48 = OpAccessChain %25 %15 %31 %31
+               OpStore %48 %47
+         %49 = OpAccessChain %25 %24 %17 %31 %10
+         %50 = OpLoad %6 %49
+         %51 = OpAccessChain %25 %15 %31 %10
+               OpStore %51 %50
+         %52 = OpAccessChain %25 %24 %31 %17
+         %53 = OpLoad %6 %52
+         %54 = OpAccessChain %25 %15 %37 %17 %17
+               OpStore %54 %53
+         %55 = OpAccessChain %25 %24 %31 %31
+         %56 = OpLoad %6 %55
+         %57 = OpAccessChain %25 %15 %37 %17 %31
+               OpStore %57 %56
+         %58 = OpAccessChain %25 %24 %31 %37
+         %59 = OpLoad %6 %58
+         %60 = OpAccessChain %25 %15 %37 %31 %17
+               OpStore %60 %59
+         %62 = OpAccessChain %25 %24 %31 %61
+         %63 = OpLoad %6 %62
+         %64 = OpAccessChain %25 %15 %37 %31 %31
+               OpStore %64 %63
+               OpReturn
+               OpFunctionEnd
+
+)";
+
+TEST(DiffTest, IndexSignedness) {
+  constexpr char kDiff[] = R"( ; SPIR-V
+ ; Version: 1.6
+ ; Generator: Khronos SPIR-V Tools Assembler; 0
+ ; Bound: 65
+ ; Schema: 0
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %4 "main"
+ OpExecutionMode %4 LocalSize 1 1 1
+ OpSource ESSL 310
+ OpName %4 "main"
+ OpName %13 "BufferOut"
+ OpMemberName %13 0 "o1"
+ OpMemberName %13 1 "o2"
+ OpMemberName %13 2 "o3"
+ OpName %15 ""
+ OpName %22 "BufferIn"
+ OpMemberName %22 0 "i1"
+ OpMemberName %22 1 "i2"
+ OpName %24 ""
+ OpDecorate %8 ArrayStride 4
+ OpDecorate %9 ArrayStride 4
+ OpDecorate %11 ArrayStride 4
+ OpDecorate %12 ArrayStride 8
+ OpMemberDecorate %13 0 Offset 0
+ OpMemberDecorate %13 1 Offset 12
+ OpMemberDecorate %13 2 Offset 24
+ OpDecorate %13 BufferBlock
+ OpDecorate %15 DescriptorSet 0
+ OpDecorate %15 Binding 1
+ OpDecorate %18 ArrayStride 16
+ OpDecorate %19 ArrayStride 48
+ OpDecorate %21 ArrayStride 16
+ OpMemberDecorate %22 0 Offset 0
+ OpMemberDecorate %22 1 Offset 96
+ OpDecorate %22 Block
+ OpDecorate %24 DescriptorSet 0
+ OpDecorate %24 Binding 0
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %6 = OpTypeInt 32 0
+ %7 = OpConstant %6 3
+-%8 = OpTypeArray %6 %7
++%8 = OpTypeArray %6 %61
+-%9 = OpTypeArray %6 %7
++%9 = OpTypeArray %6 %61
+ %10 = OpConstant %6 2
+-%11 = OpTypeArray %6 %10
++%11 = OpTypeArray %6 %37
+-%12 = OpTypeArray %11 %10
++%12 = OpTypeArray %11 %37
+ %13 = OpTypeStruct %8 %9 %12
+ %14 = OpTypePointer Uniform %13
+ %15 = OpVariable %14 Uniform
+ %16 = OpTypeInt 32 1
+ %17 = OpConstant %16 0
+-%18 = OpTypeArray %6 %7
++%18 = OpTypeArray %6 %61
+-%19 = OpTypeArray %18 %10
++%19 = OpTypeArray %18 %37
+-%20 = OpConstant %6 4
++%20 = OpConstant %16 4
+ %21 = OpTypeArray %6 %20
+ %22 = OpTypeStruct %19 %21
+ %23 = OpTypePointer Uniform %22
+ %24 = OpVariable %23 Uniform
+ %25 = OpTypePointer Uniform %6
+ %28 = OpConstant %6 1
+ %31 = OpConstant %16 1
+ %34 = OpConstant %6 0
+ %37 = OpConstant %16 2
+ %61 = OpConstant %16 3
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ %26 = OpAccessChain %25 %24 %17 %17 %17
+ %27 = OpLoad %6 %26
+-%29 = OpIAdd %6 %27 %28
++%29 = OpIAdd %6 %27 %31
+ %30 = OpAccessChain %25 %15 %17 %17
+ OpStore %30 %29
+-%32 = OpAccessChain %25 %24 %17 %31 %17
++%32 = OpAccessChain %25 %24 %17 %28 %17
+ %33 = OpLoad %6 %32
+ %35 = OpIAdd %6 %33 %34
+-%36 = OpAccessChain %25 %15 %17 %31
++%36 = OpAccessChain %25 %15 %17 %28
+ OpStore %36 %35
+-%38 = OpAccessChain %25 %24 %17 %31 %31
++%38 = OpAccessChain %25 %24 %17 %28 %28
+ %39 = OpLoad %6 %38
+ %40 = OpIAdd %6 %39 %10
+ %41 = OpAccessChain %25 %15 %17 %37
+ OpStore %41 %40
+ %42 = OpAccessChain %25 %24 %17 %17 %37
+ %43 = OpLoad %6 %42
+-%44 = OpAccessChain %25 %15 %31 %17
++%44 = OpAccessChain %25 %15 %28 %17
+ OpStore %44 %43
+-%45 = OpAccessChain %25 %24 %17 %17 %31
++%45 = OpAccessChain %25 %24 %17 %17 %28
+ %46 = OpLoad %6 %45
+-%47 = OpIMul %6 %46 %7
++%47 = OpIMul %6 %46 %61
+-%48 = OpAccessChain %25 %15 %31 %31
++%48 = OpAccessChain %25 %15 %28 %28
+ OpStore %48 %47
+-%49 = OpAccessChain %25 %24 %17 %31 %37
++%49 = OpAccessChain %25 %24 %17 %28 %37
+ %50 = OpLoad %6 %49
+-%51 = OpAccessChain %25 %15 %31 %37
++%51 = OpAccessChain %25 %15 %28 %37
+ OpStore %51 %50
+-%52 = OpAccessChain %25 %24 %31 %17
++%52 = OpAccessChain %25 %24 %28 %17
+ %53 = OpLoad %6 %52
+-%54 = OpAccessChain %25 %15 %37 %17 %17
++%54 = OpAccessChain %25 %15 %10 %17 %17
+ OpStore %54 %53
+-%55 = OpAccessChain %25 %24 %31 %31
++%55 = OpAccessChain %25 %24 %28 %28
+ %56 = OpLoad %6 %55
+-%57 = OpAccessChain %25 %15 %37 %17 %31
++%57 = OpAccessChain %25 %15 %10 %17 %28
+ OpStore %57 %56
+-%58 = OpAccessChain %25 %24 %31 %37
++%58 = OpAccessChain %25 %24 %28 %10
+ %59 = OpLoad %6 %58
+-%60 = OpAccessChain %25 %15 %37 %31 %17
++%60 = OpAccessChain %25 %15 %10 %28 %17
+ OpStore %60 %59
+-%62 = OpAccessChain %25 %24 %31 %61
++%62 = OpAccessChain %25 %24 %28 %7
+ %63 = OpLoad %6 %62
+-%64 = OpAccessChain %25 %15 %37 %31 %31
++%64 = OpAccessChain %25 %15 %10 %28 %28
+ OpStore %64 %63
+ OpReturn
+ OpFunctionEnd
+)";
+  Options options;
+  DoStringDiffTest(kSrc, kDst, kDiff, options);
+}
+
+TEST(DiffTest, IndexSignednessNoDebug) {
+  constexpr char kSrcNoDebug[] = R"(               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %4 "main"
+               OpExecutionMode %4 LocalSize 1 1 1
+               OpSource ESSL 310
+               OpDecorate %8 ArrayStride 4
+               OpDecorate %9 ArrayStride 4
+               OpDecorate %11 ArrayStride 4
+               OpDecorate %12 ArrayStride 8
+               OpMemberDecorate %13 0 Offset 0
+               OpMemberDecorate %13 1 Offset 12
+               OpMemberDecorate %13 2 Offset 24
+               OpDecorate %13 BufferBlock
+               OpDecorate %15 DescriptorSet 0
+               OpDecorate %15 Binding 1
+               OpDecorate %18 ArrayStride 16
+               OpDecorate %19 ArrayStride 48
+               OpDecorate %21 ArrayStride 16
+               OpMemberDecorate %22 0 Offset 0
+               OpMemberDecorate %22 1 Offset 96
+               OpDecorate %22 Block
+               OpDecorate %24 DescriptorSet 0
+               OpDecorate %24 Binding 0
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeInt 32 0
+          %7 = OpConstant %6 3
+          %8 = OpTypeArray %6 %7
+          %9 = OpTypeArray %6 %7
+         %10 = OpConstant %6 2
+         %11 = OpTypeArray %6 %10
+         %12 = OpTypeArray %11 %10
+         %13 = OpTypeStruct %8 %9 %12
+         %14 = OpTypePointer Uniform %13
+         %15 = OpVariable %14 Uniform
+         %16 = OpTypeInt 32 1
+         %17 = OpConstant %16 0
+         %18 = OpTypeArray %6 %7
+         %19 = OpTypeArray %18 %10
+         %20 = OpConstant %6 4
+         %21 = OpTypeArray %6 %20
+         %22 = OpTypeStruct %19 %21
+         %23 = OpTypePointer Uniform %22
+         %24 = OpVariable %23 Uniform
+         %25 = OpTypePointer Uniform %6
+         %28 = OpConstant %6 1
+         %31 = OpConstant %16 1
+         %34 = OpConstant %6 0
+         %37 = OpConstant %16 2
+         %61 = OpConstant %16 3
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+         %26 = OpAccessChain %25 %24 %17 %17 %17
+         %27 = OpLoad %6 %26
+         %29 = OpIAdd %6 %27 %28
+         %30 = OpAccessChain %25 %15 %17 %17
+               OpStore %30 %29
+         %32 = OpAccessChain %25 %24 %17 %31 %17
+         %33 = OpLoad %6 %32
+         %35 = OpIAdd %6 %33 %34
+         %36 = OpAccessChain %25 %15 %17 %31
+               OpStore %36 %35
+         %38 = OpAccessChain %25 %24 %17 %31 %31
+         %39 = OpLoad %6 %38
+         %40 = OpIAdd %6 %39 %10
+         %41 = OpAccessChain %25 %15 %17 %37
+               OpStore %41 %40
+         %42 = OpAccessChain %25 %24 %17 %17 %37
+         %43 = OpLoad %6 %42
+         %44 = OpAccessChain %25 %15 %31 %17
+               OpStore %44 %43
+         %45 = OpAccessChain %25 %24 %17 %17 %31
+         %46 = OpLoad %6 %45
+         %47 = OpIMul %6 %46 %7
+         %48 = OpAccessChain %25 %15 %31 %31
+               OpStore %48 %47
+         %49 = OpAccessChain %25 %24 %17 %31 %37
+         %50 = OpLoad %6 %49
+         %51 = OpAccessChain %25 %15 %31 %37
+               OpStore %51 %50
+         %52 = OpAccessChain %25 %24 %31 %17
+         %53 = OpLoad %6 %52
+         %54 = OpAccessChain %25 %15 %37 %17 %17
+               OpStore %54 %53
+         %55 = OpAccessChain %25 %24 %31 %31
+         %56 = OpLoad %6 %55
+         %57 = OpAccessChain %25 %15 %37 %17 %31
+               OpStore %57 %56
+         %58 = OpAccessChain %25 %24 %31 %37
+         %59 = OpLoad %6 %58
+         %60 = OpAccessChain %25 %15 %37 %31 %17
+               OpStore %60 %59
+         %62 = OpAccessChain %25 %24 %31 %61
+         %63 = OpLoad %6 %62
+         %64 = OpAccessChain %25 %15 %37 %31 %31
+               OpStore %64 %63
+               OpReturn
+               OpFunctionEnd
+
+)";
+  constexpr char kDstNoDebug[] = R"(               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %4 "main"
+               OpExecutionMode %4 LocalSize 1 1 1
+               OpSource ESSL 310
+               OpDecorate %8 ArrayStride 4
+               OpDecorate %9 ArrayStride 4
+               OpDecorate %11 ArrayStride 4
+               OpDecorate %12 ArrayStride 8
+               OpMemberDecorate %13 0 Offset 0
+               OpMemberDecorate %13 1 Offset 12
+               OpMemberDecorate %13 2 Offset 24
+               OpDecorate %13 BufferBlock
+               OpDecorate %15 DescriptorSet 0
+               OpDecorate %15 Binding 1
+               OpDecorate %18 ArrayStride 16
+               OpDecorate %19 ArrayStride 48
+               OpDecorate %21 ArrayStride 16
+               OpMemberDecorate %22 0 Offset 0
+               OpMemberDecorate %22 1 Offset 96
+               OpDecorate %22 Block
+               OpDecorate %24 DescriptorSet 0
+               OpDecorate %24 Binding 0
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeInt 32 0
+         %16 = OpTypeInt 32 1
+          %7 = OpConstant %16 3
+          %8 = OpTypeArray %6 %7
+          %9 = OpTypeArray %6 %7
+         %10 = OpConstant %16 2
+         %11 = OpTypeArray %6 %10
+         %12 = OpTypeArray %11 %10
+         %13 = OpTypeStruct %8 %9 %12
+         %14 = OpTypePointer Uniform %13
+         %15 = OpVariable %14 Uniform
+         %18 = OpTypeArray %6 %7
+         %19 = OpTypeArray %18 %10
+         %20 = OpConstant %16 4
+         %21 = OpTypeArray %6 %20
+         %22 = OpTypeStruct %19 %21
+         %23 = OpTypePointer Uniform %22
+         %24 = OpVariable %23 Uniform
+         %25 = OpTypePointer Uniform %6
+         %17 = OpConstant %16 0
+         %28 = OpConstant %16 1
+         %31 = OpConstant %6 1
+         %34 = OpConstant %6 0
+         %37 = OpConstant %6 2
+         %61 = OpConstant %6 3
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+         %26 = OpAccessChain %25 %24 %17 %17 %17
+         %27 = OpLoad %6 %26
+         %29 = OpIAdd %6 %27 %28
+         %30 = OpAccessChain %25 %15 %17 %17
+               OpStore %30 %29
+         %32 = OpAccessChain %25 %24 %17 %31 %17
+         %33 = OpLoad %6 %32
+         %35 = OpIAdd %6 %33 %34
+         %36 = OpAccessChain %25 %15 %17 %31
+               OpStore %36 %35
+         %38 = OpAccessChain %25 %24 %17 %31 %31
+         %39 = OpLoad %6 %38
+         %40 = OpIAdd %6 %39 %37
+         %41 = OpAccessChain %25 %15 %17 %10
+               OpStore %41 %40
+         %42 = OpAccessChain %25 %24 %17 %17 %10
+         %43 = OpLoad %6 %42
+         %44 = OpAccessChain %25 %15 %31 %17
+               OpStore %44 %43
+         %45 = OpAccessChain %25 %24 %17 %17 %31
+         %46 = OpLoad %6 %45
+         %47 = OpIMul %6 %46 %7
+         %48 = OpAccessChain %25 %15 %31 %31
+               OpStore %48 %47
+         %49 = OpAccessChain %25 %24 %17 %31 %10
+         %50 = OpLoad %6 %49
+         %51 = OpAccessChain %25 %15 %31 %10
+               OpStore %51 %50
+         %52 = OpAccessChain %25 %24 %31 %17
+         %53 = OpLoad %6 %52
+         %54 = OpAccessChain %25 %15 %37 %17 %17
+               OpStore %54 %53
+         %55 = OpAccessChain %25 %24 %31 %31
+         %56 = OpLoad %6 %55
+         %57 = OpAccessChain %25 %15 %37 %17 %31
+               OpStore %57 %56
+         %58 = OpAccessChain %25 %24 %31 %37
+         %59 = OpLoad %6 %58
+         %60 = OpAccessChain %25 %15 %37 %31 %17
+               OpStore %60 %59
+         %62 = OpAccessChain %25 %24 %31 %61
+         %63 = OpLoad %6 %62
+         %64 = OpAccessChain %25 %15 %37 %31 %31
+               OpStore %64 %63
+               OpReturn
+               OpFunctionEnd
+
+)";
+  constexpr char kDiff[] = R"( ; SPIR-V
+ ; Version: 1.6
+ ; Generator: Khronos SPIR-V Tools Assembler; 0
+ ; Bound: 65
+ ; Schema: 0
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %4 "main"
+ OpExecutionMode %4 LocalSize 1 1 1
+ OpSource ESSL 310
+ OpDecorate %8 ArrayStride 4
+ OpDecorate %9 ArrayStride 4
+ OpDecorate %11 ArrayStride 4
+ OpDecorate %12 ArrayStride 8
+ OpMemberDecorate %13 0 Offset 0
+ OpMemberDecorate %13 1 Offset 12
+ OpMemberDecorate %13 2 Offset 24
+ OpDecorate %13 BufferBlock
+ OpDecorate %15 DescriptorSet 0
+ OpDecorate %15 Binding 1
+ OpDecorate %18 ArrayStride 16
+ OpDecorate %19 ArrayStride 48
+ OpDecorate %21 ArrayStride 16
+ OpMemberDecorate %22 0 Offset 0
+ OpMemberDecorate %22 1 Offset 96
+ OpDecorate %22 Block
+ OpDecorate %24 DescriptorSet 0
+ OpDecorate %24 Binding 0
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %6 = OpTypeInt 32 0
+ %7 = OpConstant %6 3
+-%8 = OpTypeArray %6 %7
++%8 = OpTypeArray %6 %61
+-%9 = OpTypeArray %6 %7
++%9 = OpTypeArray %6 %61
+ %10 = OpConstant %6 2
+-%11 = OpTypeArray %6 %10
++%11 = OpTypeArray %6 %37
+-%12 = OpTypeArray %11 %10
++%12 = OpTypeArray %11 %37
+ %13 = OpTypeStruct %8 %9 %12
+ %14 = OpTypePointer Uniform %13
+ %15 = OpVariable %14 Uniform
+ %16 = OpTypeInt 32 1
+ %17 = OpConstant %16 0
+-%18 = OpTypeArray %6 %7
++%18 = OpTypeArray %6 %61
+-%19 = OpTypeArray %18 %10
++%19 = OpTypeArray %18 %37
+-%20 = OpConstant %6 4
++%20 = OpConstant %16 4
+ %21 = OpTypeArray %6 %20
+ %22 = OpTypeStruct %19 %21
+ %23 = OpTypePointer Uniform %22
+ %24 = OpVariable %23 Uniform
+ %25 = OpTypePointer Uniform %6
+ %28 = OpConstant %6 1
+ %31 = OpConstant %16 1
+ %34 = OpConstant %6 0
+ %37 = OpConstant %16 2
+ %61 = OpConstant %16 3
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ %26 = OpAccessChain %25 %24 %17 %17 %17
+ %27 = OpLoad %6 %26
+-%29 = OpIAdd %6 %27 %28
++%29 = OpIAdd %6 %27 %31
+ %30 = OpAccessChain %25 %15 %17 %17
+ OpStore %30 %29
+-%32 = OpAccessChain %25 %24 %17 %31 %17
++%32 = OpAccessChain %25 %24 %17 %28 %17
+ %33 = OpLoad %6 %32
+ %35 = OpIAdd %6 %33 %34
+-%36 = OpAccessChain %25 %15 %17 %31
++%36 = OpAccessChain %25 %15 %17 %28
+ OpStore %36 %35
+-%38 = OpAccessChain %25 %24 %17 %31 %31
++%38 = OpAccessChain %25 %24 %17 %28 %28
+ %39 = OpLoad %6 %38
+ %40 = OpIAdd %6 %39 %10
+ %41 = OpAccessChain %25 %15 %17 %37
+ OpStore %41 %40
+ %42 = OpAccessChain %25 %24 %17 %17 %37
+ %43 = OpLoad %6 %42
+-%44 = OpAccessChain %25 %15 %31 %17
++%44 = OpAccessChain %25 %15 %28 %17
+ OpStore %44 %43
+-%45 = OpAccessChain %25 %24 %17 %17 %31
++%45 = OpAccessChain %25 %24 %17 %17 %28
+ %46 = OpLoad %6 %45
+-%47 = OpIMul %6 %46 %7
++%47 = OpIMul %6 %46 %61
+-%48 = OpAccessChain %25 %15 %31 %31
++%48 = OpAccessChain %25 %15 %28 %28
+ OpStore %48 %47
+-%49 = OpAccessChain %25 %24 %17 %31 %37
++%49 = OpAccessChain %25 %24 %17 %28 %37
+ %50 = OpLoad %6 %49
+-%51 = OpAccessChain %25 %15 %31 %37
++%51 = OpAccessChain %25 %15 %28 %37
+ OpStore %51 %50
+-%52 = OpAccessChain %25 %24 %31 %17
++%52 = OpAccessChain %25 %24 %28 %17
+ %53 = OpLoad %6 %52
+-%54 = OpAccessChain %25 %15 %37 %17 %17
++%54 = OpAccessChain %25 %15 %10 %17 %17
+ OpStore %54 %53
+-%55 = OpAccessChain %25 %24 %31 %31
++%55 = OpAccessChain %25 %24 %28 %28
+ %56 = OpLoad %6 %55
+-%57 = OpAccessChain %25 %15 %37 %17 %31
++%57 = OpAccessChain %25 %15 %10 %17 %28
+ OpStore %57 %56
+-%58 = OpAccessChain %25 %24 %31 %37
++%58 = OpAccessChain %25 %24 %28 %10
+ %59 = OpLoad %6 %58
+-%60 = OpAccessChain %25 %15 %37 %31 %17
++%60 = OpAccessChain %25 %15 %10 %28 %17
+ OpStore %60 %59
+-%62 = OpAccessChain %25 %24 %31 %61
++%62 = OpAccessChain %25 %24 %28 %7
+ %63 = OpLoad %6 %62
+-%64 = OpAccessChain %25 %15 %37 %31 %31
++%64 = OpAccessChain %25 %15 %10 %28 %28
+ OpStore %64 %63
+ OpReturn
+ OpFunctionEnd
+)";
+  Options options;
+  DoStringDiffTest(kSrcNoDebug, kDstNoDebug, kDiff, options);
+}
+
+}  // namespace
+}  // namespace diff
+}  // namespace spvtools

+ 110 - 0
ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/index_signedness_dst.spvasm

@@ -0,0 +1,110 @@
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %4 "main"
+               OpExecutionMode %4 LocalSize 1 1 1
+               OpSource ESSL 310
+               OpName %4 "main"
+               OpName %13 "BufferOut"
+               OpMemberName %13 0 "o1"
+               OpMemberName %13 1 "o2"
+               OpMemberName %13 2 "o3"
+               OpName %15 ""
+               OpName %22 "BufferIn"
+               OpMemberName %22 0 "i1"
+               OpMemberName %22 1 "i2"
+               OpName %24 ""
+               OpDecorate %8 ArrayStride 4
+               OpDecorate %9 ArrayStride 4
+               OpDecorate %11 ArrayStride 4
+               OpDecorate %12 ArrayStride 8
+               OpMemberDecorate %13 0 Offset 0
+               OpMemberDecorate %13 1 Offset 12
+               OpMemberDecorate %13 2 Offset 24
+               OpDecorate %13 BufferBlock
+               OpDecorate %15 DescriptorSet 0
+               OpDecorate %15 Binding 1
+               OpDecorate %18 ArrayStride 16
+               OpDecorate %19 ArrayStride 48
+               OpDecorate %21 ArrayStride 16
+               OpMemberDecorate %22 0 Offset 0
+               OpMemberDecorate %22 1 Offset 96
+               OpDecorate %22 Block
+               OpDecorate %24 DescriptorSet 0
+               OpDecorate %24 Binding 0
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeInt 32 0
+         %16 = OpTypeInt 32 1
+          %7 = OpConstant %16 3
+          %8 = OpTypeArray %6 %7
+          %9 = OpTypeArray %6 %7
+         %10 = OpConstant %16 2
+         %11 = OpTypeArray %6 %10
+         %12 = OpTypeArray %11 %10
+         %13 = OpTypeStruct %8 %9 %12
+         %14 = OpTypePointer Uniform %13
+         %15 = OpVariable %14 Uniform
+         %18 = OpTypeArray %6 %7
+         %19 = OpTypeArray %18 %10
+         %20 = OpConstant %16 4
+         %21 = OpTypeArray %6 %20
+         %22 = OpTypeStruct %19 %21
+         %23 = OpTypePointer Uniform %22
+         %24 = OpVariable %23 Uniform
+         %25 = OpTypePointer Uniform %6
+         %17 = OpConstant %16 0
+         %28 = OpConstant %16 1
+         %31 = OpConstant %6 1
+         %34 = OpConstant %6 0
+         %37 = OpConstant %6 2
+         %61 = OpConstant %6 3
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+         %26 = OpAccessChain %25 %24 %17 %17 %17
+         %27 = OpLoad %6 %26
+         %29 = OpIAdd %6 %27 %28
+         %30 = OpAccessChain %25 %15 %17 %17
+               OpStore %30 %29
+         %32 = OpAccessChain %25 %24 %17 %31 %17
+         %33 = OpLoad %6 %32
+         %35 = OpIAdd %6 %33 %34
+         %36 = OpAccessChain %25 %15 %17 %31
+               OpStore %36 %35
+         %38 = OpAccessChain %25 %24 %17 %31 %31
+         %39 = OpLoad %6 %38
+         %40 = OpIAdd %6 %39 %37
+         %41 = OpAccessChain %25 %15 %17 %10
+               OpStore %41 %40
+         %42 = OpAccessChain %25 %24 %17 %17 %10
+         %43 = OpLoad %6 %42
+         %44 = OpAccessChain %25 %15 %31 %17
+               OpStore %44 %43
+         %45 = OpAccessChain %25 %24 %17 %17 %31
+         %46 = OpLoad %6 %45
+         %47 = OpIMul %6 %46 %7
+         %48 = OpAccessChain %25 %15 %31 %31
+               OpStore %48 %47
+         %49 = OpAccessChain %25 %24 %17 %31 %10
+         %50 = OpLoad %6 %49
+         %51 = OpAccessChain %25 %15 %31 %10
+               OpStore %51 %50
+         %52 = OpAccessChain %25 %24 %31 %17
+         %53 = OpLoad %6 %52
+         %54 = OpAccessChain %25 %15 %37 %17 %17
+               OpStore %54 %53
+         %55 = OpAccessChain %25 %24 %31 %31
+         %56 = OpLoad %6 %55
+         %57 = OpAccessChain %25 %15 %37 %17 %31
+               OpStore %57 %56
+         %58 = OpAccessChain %25 %24 %31 %37
+         %59 = OpLoad %6 %58
+         %60 = OpAccessChain %25 %15 %37 %31 %17
+               OpStore %60 %59
+         %62 = OpAccessChain %25 %24 %31 %61
+         %63 = OpLoad %6 %62
+         %64 = OpAccessChain %25 %15 %37 %31 %31
+               OpStore %64 %63
+               OpReturn
+               OpFunctionEnd
+

+ 111 - 0
ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/index_signedness_src.spvasm

@@ -0,0 +1,111 @@
+;; Test where signedness of indices are different between src and dst.
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %4 "main"
+               OpExecutionMode %4 LocalSize 1 1 1
+               OpSource ESSL 310
+               OpName %4 "main"
+               OpName %13 "BufferOut"
+               OpMemberName %13 0 "o1"
+               OpMemberName %13 1 "o2"
+               OpMemberName %13 2 "o3"
+               OpName %15 ""
+               OpName %22 "BufferIn"
+               OpMemberName %22 0 "i1"
+               OpMemberName %22 1 "i2"
+               OpName %24 ""
+               OpDecorate %8 ArrayStride 4
+               OpDecorate %9 ArrayStride 4
+               OpDecorate %11 ArrayStride 4
+               OpDecorate %12 ArrayStride 8
+               OpMemberDecorate %13 0 Offset 0
+               OpMemberDecorate %13 1 Offset 12
+               OpMemberDecorate %13 2 Offset 24
+               OpDecorate %13 BufferBlock
+               OpDecorate %15 DescriptorSet 0
+               OpDecorate %15 Binding 1
+               OpDecorate %18 ArrayStride 16
+               OpDecorate %19 ArrayStride 48
+               OpDecorate %21 ArrayStride 16
+               OpMemberDecorate %22 0 Offset 0
+               OpMemberDecorate %22 1 Offset 96
+               OpDecorate %22 Block
+               OpDecorate %24 DescriptorSet 0
+               OpDecorate %24 Binding 0
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeInt 32 0
+          %7 = OpConstant %6 3
+          %8 = OpTypeArray %6 %7
+          %9 = OpTypeArray %6 %7
+         %10 = OpConstant %6 2
+         %11 = OpTypeArray %6 %10
+         %12 = OpTypeArray %11 %10
+         %13 = OpTypeStruct %8 %9 %12
+         %14 = OpTypePointer Uniform %13
+         %15 = OpVariable %14 Uniform
+         %16 = OpTypeInt 32 1
+         %17 = OpConstant %16 0
+         %18 = OpTypeArray %6 %7
+         %19 = OpTypeArray %18 %10
+         %20 = OpConstant %6 4
+         %21 = OpTypeArray %6 %20
+         %22 = OpTypeStruct %19 %21
+         %23 = OpTypePointer Uniform %22
+         %24 = OpVariable %23 Uniform
+         %25 = OpTypePointer Uniform %6
+         %28 = OpConstant %6 1
+         %31 = OpConstant %16 1
+         %34 = OpConstant %6 0
+         %37 = OpConstant %16 2
+         %61 = OpConstant %16 3
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+         %26 = OpAccessChain %25 %24 %17 %17 %17
+         %27 = OpLoad %6 %26
+         %29 = OpIAdd %6 %27 %28
+         %30 = OpAccessChain %25 %15 %17 %17
+               OpStore %30 %29
+         %32 = OpAccessChain %25 %24 %17 %31 %17
+         %33 = OpLoad %6 %32
+         %35 = OpIAdd %6 %33 %34
+         %36 = OpAccessChain %25 %15 %17 %31
+               OpStore %36 %35
+         %38 = OpAccessChain %25 %24 %17 %31 %31
+         %39 = OpLoad %6 %38
+         %40 = OpIAdd %6 %39 %10
+         %41 = OpAccessChain %25 %15 %17 %37
+               OpStore %41 %40
+         %42 = OpAccessChain %25 %24 %17 %17 %37
+         %43 = OpLoad %6 %42
+         %44 = OpAccessChain %25 %15 %31 %17
+               OpStore %44 %43
+         %45 = OpAccessChain %25 %24 %17 %17 %31
+         %46 = OpLoad %6 %45
+         %47 = OpIMul %6 %46 %7
+         %48 = OpAccessChain %25 %15 %31 %31
+               OpStore %48 %47
+         %49 = OpAccessChain %25 %24 %17 %31 %37
+         %50 = OpLoad %6 %49
+         %51 = OpAccessChain %25 %15 %31 %37
+               OpStore %51 %50
+         %52 = OpAccessChain %25 %24 %31 %17
+         %53 = OpLoad %6 %52
+         %54 = OpAccessChain %25 %15 %37 %17 %17
+               OpStore %54 %53
+         %55 = OpAccessChain %25 %24 %31 %31
+         %56 = OpLoad %6 %55
+         %57 = OpAccessChain %25 %15 %37 %17 %31
+               OpStore %57 %56
+         %58 = OpAccessChain %25 %24 %31 %37
+         %59 = OpLoad %6 %58
+         %60 = OpAccessChain %25 %15 %37 %31 %17
+               OpStore %60 %59
+         %62 = OpAccessChain %25 %24 %31 %61
+         %63 = OpLoad %6 %62
+         %64 = OpAccessChain %25 %15 %37 %31 %31
+               OpStore %64 %63
+               OpReturn
+               OpFunctionEnd
+

+ 396 - 0
ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/int_vs_uint_constants_autogen.cpp

@@ -0,0 +1,396 @@
+// GENERATED FILE - DO NOT EDIT.
+// Generated by generate_tests.py
+//
+// 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 "../diff_test_utils.h"
+
+#include "gtest/gtest.h"
+
+namespace spvtools {
+namespace diff {
+namespace {
+
+// Tests that identical integer constants are matched, regardless of int or
+// uint.  This helps compare output from different generators that default to
+// int or uint for constants such as those passed to OpAccessChain.
+constexpr char kSrc[] = R"(; SPIR-V
+; Version: 1.0
+; Generator: Google ANGLE Shader Compiler; 0
+; Bound: 27
+; Schema: 0
+OpCapability Shader
+OpMemoryModel Logical GLSL450
+OpEntryPoint Vertex %22 "main" %4 %19
+OpSource GLSL 450
+OpName %4 "_ua_position"
+OpName %17 "gl_PerVertex"
+OpMemberName %17 0 "gl_Position"
+OpMemberName %17 1 "gl_PointSize"
+OpMemberName %17 2 "gl_ClipDistance"
+OpMemberName %17 3 "gl_CullDistance"
+OpName %19 ""
+OpName %22 "main"
+OpDecorate %4 Location 0
+OpMemberDecorate %17 1 RelaxedPrecision
+OpMemberDecorate %17 0 BuiltIn Position
+OpMemberDecorate %17 1 BuiltIn PointSize
+OpMemberDecorate %17 2 BuiltIn ClipDistance
+OpMemberDecorate %17 3 BuiltIn CullDistance
+OpDecorate %17 Block
+%1 = OpTypeFloat 32
+%2 = OpTypeVector %1 4
+%5 = OpTypeInt 32 0
+%8 = OpTypeVector %5 4
+%15 = OpConstant %5 8
+%16 = OpTypeArray %1 %15
+%17 = OpTypeStruct %2 %1 %16 %16
+%20 = OpTypeVoid
+%25 = OpConstant %5 0
+%3 = OpTypePointer Input %2
+%13 = OpTypePointer Output %2
+%18 = OpTypePointer Output %17
+%21 = OpTypeFunction %20
+%4 = OpVariable %3 Input
+%19 = OpVariable %18 Output
+%22 = OpFunction %20 None %21
+%23 = OpLabel
+%24 = OpLoad %2 %4
+%26 = OpAccessChain %13 %19 %25
+OpStore %26 %24
+OpReturn
+OpFunctionEnd)";
+constexpr char kDst[] = R"(; SPIR-V
+; Version: 1.0
+; Generator: Khronos Glslang Reference Front End; 10
+; Bound: 28
+; Schema: 0
+OpCapability Shader
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint Vertex %4 "main" %13 %17
+OpSource GLSL 450
+OpName %4 "main"
+OpName %11 "gl_PerVertex"
+OpMemberName %11 0 "gl_Position"
+OpMemberName %11 1 "gl_PointSize"
+OpMemberName %11 2 "gl_ClipDistance"
+OpMemberName %11 3 "gl_CullDistance"
+OpName %13 ""
+OpName %17 "_ua_position"
+OpMemberDecorate %11 0 BuiltIn Position
+OpMemberDecorate %11 1 BuiltIn PointSize
+OpMemberDecorate %11 2 BuiltIn ClipDistance
+OpMemberDecorate %11 3 BuiltIn CullDistance
+OpDecorate %11 Block
+OpDecorate %17 Location 0
+%2 = OpTypeVoid
+%3 = OpTypeFunction %2
+%6 = OpTypeFloat 32
+%7 = OpTypeVector %6 4
+%8 = OpTypeInt 32 0
+%9 = OpConstant %8 1
+%10 = OpTypeArray %6 %9
+%11 = OpTypeStruct %7 %6 %10 %10
+%12 = OpTypePointer Output %11
+%13 = OpVariable %12 Output
+%14 = OpTypeInt 32 1
+%15 = OpConstant %14 0
+%16 = OpTypePointer Input %7
+%17 = OpVariable %16 Input
+%19 = OpTypePointer Output %7
+%4 = OpFunction %2 None %3
+%5 = OpLabel
+%18 = OpLoad %7 %17
+%20 = OpAccessChain %19 %13 %15
+OpStore %20 %18
+OpReturn
+OpFunctionEnd
+)";
+
+TEST(DiffTest, IntVsUintConstants) {
+  constexpr char kDiff[] = R"( ; SPIR-V
+ ; Version: 1.6
+ ; Generator: Khronos SPIR-V Tools Assembler; 0
+-; Bound: 27
++; Bound: 31
+ ; Schema: 0
+ OpCapability Shader
++%27 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+-OpEntryPoint Vertex %22 "main" %4 %19
++OpEntryPoint Vertex %22 "main" %19 %4
+ OpSource GLSL 450
+ OpName %4 "_ua_position"
+ OpName %17 "gl_PerVertex"
+ OpMemberName %17 0 "gl_Position"
+ OpMemberName %17 1 "gl_PointSize"
+ OpMemberName %17 2 "gl_ClipDistance"
+ OpMemberName %17 3 "gl_CullDistance"
+ OpName %19 ""
+ OpName %22 "main"
+ OpDecorate %4 Location 0
+-OpMemberDecorate %17 1 RelaxedPrecision
+ OpMemberDecorate %17 0 BuiltIn Position
+ OpMemberDecorate %17 1 BuiltIn PointSize
+ OpMemberDecorate %17 2 BuiltIn ClipDistance
+ OpMemberDecorate %17 3 BuiltIn CullDistance
+ OpDecorate %17 Block
+ %1 = OpTypeFloat 32
+ %2 = OpTypeVector %1 4
+ %5 = OpTypeInt 32 0
+-%8 = OpTypeVector %5 4
+-%15 = OpConstant %5 8
+-%16 = OpTypeArray %1 %15
+-%17 = OpTypeStruct %2 %1 %16 %16
++%17 = OpTypeStruct %2 %1 %29 %29
+ %20 = OpTypeVoid
++%28 = OpConstant %5 1
++%29 = OpTypeArray %1 %28
+-%25 = OpConstant %5 0
++%25 = OpConstant %30 0
+ %3 = OpTypePointer Input %2
+ %13 = OpTypePointer Output %2
++%30 = OpTypeInt 32 1
+ %18 = OpTypePointer Output %17
+ %21 = OpTypeFunction %20
+ %4 = OpVariable %3 Input
+ %19 = OpVariable %18 Output
+ %22 = OpFunction %20 None %21
+ %23 = OpLabel
+ %24 = OpLoad %2 %4
+ %26 = OpAccessChain %13 %19 %25
+ OpStore %26 %24
+ OpReturn
+ OpFunctionEnd
+)";
+  Options options;
+  DoStringDiffTest(kSrc, kDst, kDiff, options);
+}
+
+TEST(DiffTest, IntVsUintConstantsNoDebug) {
+  constexpr char kSrcNoDebug[] = R"(; SPIR-V
+; Version: 1.0
+; Generator: Google ANGLE Shader Compiler; 0
+; Bound: 27
+; Schema: 0
+OpCapability Shader
+OpMemoryModel Logical GLSL450
+OpEntryPoint Vertex %22 "main" %4 %19
+OpSource GLSL 450
+OpDecorate %4 Location 0
+OpMemberDecorate %17 1 RelaxedPrecision
+OpMemberDecorate %17 0 BuiltIn Position
+OpMemberDecorate %17 1 BuiltIn PointSize
+OpMemberDecorate %17 2 BuiltIn ClipDistance
+OpMemberDecorate %17 3 BuiltIn CullDistance
+OpDecorate %17 Block
+%1 = OpTypeFloat 32
+%2 = OpTypeVector %1 4
+%5 = OpTypeInt 32 0
+%8 = OpTypeVector %5 4
+%15 = OpConstant %5 8
+%16 = OpTypeArray %1 %15
+%17 = OpTypeStruct %2 %1 %16 %16
+%20 = OpTypeVoid
+%25 = OpConstant %5 0
+%3 = OpTypePointer Input %2
+%13 = OpTypePointer Output %2
+%18 = OpTypePointer Output %17
+%21 = OpTypeFunction %20
+%4 = OpVariable %3 Input
+%19 = OpVariable %18 Output
+%22 = OpFunction %20 None %21
+%23 = OpLabel
+%24 = OpLoad %2 %4
+%26 = OpAccessChain %13 %19 %25
+OpStore %26 %24
+OpReturn
+OpFunctionEnd
+)";
+  constexpr char kDstNoDebug[] = R"(; SPIR-V
+; Version: 1.0
+; Generator: Khronos Glslang Reference Front End; 10
+; Bound: 28
+; Schema: 0
+OpCapability Shader
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint Vertex %4 "main" %13 %17
+OpSource GLSL 450
+OpMemberDecorate %11 0 BuiltIn Position
+OpMemberDecorate %11 1 BuiltIn PointSize
+OpMemberDecorate %11 2 BuiltIn ClipDistance
+OpMemberDecorate %11 3 BuiltIn CullDistance
+OpDecorate %11 Block
+OpDecorate %17 Location 0
+%2 = OpTypeVoid
+%3 = OpTypeFunction %2
+%6 = OpTypeFloat 32
+%7 = OpTypeVector %6 4
+%8 = OpTypeInt 32 0
+%9 = OpConstant %8 1
+%10 = OpTypeArray %6 %9
+%11 = OpTypeStruct %7 %6 %10 %10
+%12 = OpTypePointer Output %11
+%13 = OpVariable %12 Output
+%14 = OpTypeInt 32 1
+%15 = OpConstant %14 0
+%16 = OpTypePointer Input %7
+%17 = OpVariable %16 Input
+%19 = OpTypePointer Output %7
+%4 = OpFunction %2 None %3
+%5 = OpLabel
+%18 = OpLoad %7 %17
+%20 = OpAccessChain %19 %13 %15
+OpStore %20 %18
+OpReturn
+OpFunctionEnd
+)";
+  constexpr char kDiff[] = R"( ; SPIR-V
+ ; Version: 1.6
+ ; Generator: Khronos SPIR-V Tools Assembler; 0
+-; Bound: 27
++; Bound: 31
+ ; Schema: 0
+ OpCapability Shader
++%27 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+-OpEntryPoint Vertex %22 "main" %4 %19
++OpEntryPoint Vertex %22 "main" %19 %4
+ OpSource GLSL 450
+ OpDecorate %4 Location 0
+-OpMemberDecorate %17 1 RelaxedPrecision
+ OpMemberDecorate %17 0 BuiltIn Position
+ OpMemberDecorate %17 1 BuiltIn PointSize
+ OpMemberDecorate %17 2 BuiltIn ClipDistance
+ OpMemberDecorate %17 3 BuiltIn CullDistance
+ OpDecorate %17 Block
+ %1 = OpTypeFloat 32
+ %2 = OpTypeVector %1 4
+ %5 = OpTypeInt 32 0
+-%8 = OpTypeVector %5 4
+-%15 = OpConstant %5 8
+-%16 = OpTypeArray %1 %15
+-%17 = OpTypeStruct %2 %1 %16 %16
++%17 = OpTypeStruct %2 %1 %29 %29
+ %20 = OpTypeVoid
++%28 = OpConstant %5 1
++%29 = OpTypeArray %1 %28
+-%25 = OpConstant %5 0
++%25 = OpConstant %30 0
+ %3 = OpTypePointer Input %2
+ %13 = OpTypePointer Output %2
++%30 = OpTypeInt 32 1
+ %18 = OpTypePointer Output %17
+ %21 = OpTypeFunction %20
+ %4 = OpVariable %3 Input
+ %19 = OpVariable %18 Output
+ %22 = OpFunction %20 None %21
+ %23 = OpLabel
+ %24 = OpLoad %2 %4
+ %26 = OpAccessChain %13 %19 %25
+ OpStore %26 %24
+ OpReturn
+ OpFunctionEnd
+)";
+  Options options;
+  DoStringDiffTest(kSrcNoDebug, kDstNoDebug, kDiff, options);
+}
+
+TEST(DiffTest, IntVsUintConstantsDumpIds) {
+  constexpr char kDiff[] = R"( ; SPIR-V
+ ; Version: 1.6
+ ; Generator: Khronos SPIR-V Tools Assembler; 0
+-; Bound: 27
++; Bound: 31
+ ; Schema: 0
+ OpCapability Shader
++%27 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+-OpEntryPoint Vertex %22 "main" %4 %19
++OpEntryPoint Vertex %22 "main" %19 %4
+ OpSource GLSL 450
+ OpName %4 "_ua_position"
+ OpName %17 "gl_PerVertex"
+ OpMemberName %17 0 "gl_Position"
+ OpMemberName %17 1 "gl_PointSize"
+ OpMemberName %17 2 "gl_ClipDistance"
+ OpMemberName %17 3 "gl_CullDistance"
+ OpName %19 ""
+ OpName %22 "main"
+ OpDecorate %4 Location 0
+-OpMemberDecorate %17 1 RelaxedPrecision
+ OpMemberDecorate %17 0 BuiltIn Position
+ OpMemberDecorate %17 1 BuiltIn PointSize
+ OpMemberDecorate %17 2 BuiltIn ClipDistance
+ OpMemberDecorate %17 3 BuiltIn CullDistance
+ OpDecorate %17 Block
+ %1 = OpTypeFloat 32
+ %2 = OpTypeVector %1 4
+ %5 = OpTypeInt 32 0
+-%8 = OpTypeVector %5 4
+-%15 = OpConstant %5 8
+-%16 = OpTypeArray %1 %15
+-%17 = OpTypeStruct %2 %1 %16 %16
++%17 = OpTypeStruct %2 %1 %29 %29
+ %20 = OpTypeVoid
++%28 = OpConstant %5 1
++%29 = OpTypeArray %1 %28
+-%25 = OpConstant %5 0
++%25 = OpConstant %30 0
+ %3 = OpTypePointer Input %2
+ %13 = OpTypePointer Output %2
++%30 = OpTypeInt 32 1
+ %18 = OpTypePointer Output %17
+ %21 = OpTypeFunction %20
+ %4 = OpVariable %3 Input
+ %19 = OpVariable %18 Output
+ %22 = OpFunction %20 None %21
+ %23 = OpLabel
+ %24 = OpLoad %2 %4
+ %26 = OpAccessChain %13 %19 %25
+ OpStore %26 %24
+ OpReturn
+ OpFunctionEnd
+ Src ->  Dst
+   1 ->    6 [TypeFloat]
+   2 ->    7 [TypeVector]
+   3 ->   16 [TypePointer]
+   4 ->   17 [Variable]
+   5 ->    8 [TypeInt]
+   8 ->   23 [TypeVector]
+  13 ->   19 [TypePointer]
+  15 ->   29 [Constant]
+  16 ->   30 [TypeArray]
+  17 ->   11 [TypeStruct]
+  18 ->   12 [TypePointer]
+  19 ->   13 [Variable]
+  20 ->    2 [TypeVoid]
+  21 ->    3 [TypeFunction]
+  22 ->    4 [Function]
+  23 ->    5 [Label]
+  24 ->   18 [Load]
+  25 ->   15 [Constant]
+  26 ->   20 [AccessChain]
+)";
+  Options options;
+  options.dump_id_map = true;
+  DoStringDiffTest(kSrc, kDst, kDiff, options);
+}
+
+}  // namespace
+}  // namespace diff
+}  // namespace spvtools

+ 46 - 0
ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/int_vs_uint_constants_dst.spvasm

@@ -0,0 +1,46 @@
+; SPIR-V
+; Version: 1.0
+; Generator: Khronos Glslang Reference Front End; 10
+; Bound: 28
+; Schema: 0
+OpCapability Shader
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint Vertex %4 "main" %13 %17
+OpSource GLSL 450
+OpName %4 "main"
+OpName %11 "gl_PerVertex"
+OpMemberName %11 0 "gl_Position"
+OpMemberName %11 1 "gl_PointSize"
+OpMemberName %11 2 "gl_ClipDistance"
+OpMemberName %11 3 "gl_CullDistance"
+OpName %13 ""
+OpName %17 "_ua_position"
+OpMemberDecorate %11 0 BuiltIn Position
+OpMemberDecorate %11 1 BuiltIn PointSize
+OpMemberDecorate %11 2 BuiltIn ClipDistance
+OpMemberDecorate %11 3 BuiltIn CullDistance
+OpDecorate %11 Block
+OpDecorate %17 Location 0
+%2 = OpTypeVoid
+%3 = OpTypeFunction %2
+%6 = OpTypeFloat 32
+%7 = OpTypeVector %6 4
+%8 = OpTypeInt 32 0
+%9 = OpConstant %8 1
+%10 = OpTypeArray %6 %9
+%11 = OpTypeStruct %7 %6 %10 %10
+%12 = OpTypePointer Output %11
+%13 = OpVariable %12 Output
+%14 = OpTypeInt 32 1
+%15 = OpConstant %14 0
+%16 = OpTypePointer Input %7
+%17 = OpVariable %16 Input
+%19 = OpTypePointer Output %7
+%4 = OpFunction %2 None %3
+%5 = OpLabel
+%18 = OpLoad %7 %17
+%20 = OpAccessChain %19 %13 %15
+OpStore %20 %18
+OpReturn
+OpFunctionEnd

+ 49 - 0
ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/int_vs_uint_constants_src.spvasm

@@ -0,0 +1,49 @@
+;; Tests that identical integer constants are matched, regardless of int or
+;; uint.  This helps compare output from different generators that default to
+;; int or uint for constants such as those passed to OpAccessChain.
+; SPIR-V
+; Version: 1.0
+; Generator: Google ANGLE Shader Compiler; 0
+; Bound: 27
+; Schema: 0
+OpCapability Shader
+OpMemoryModel Logical GLSL450
+OpEntryPoint Vertex %22 "main" %4 %19
+OpSource GLSL 450
+OpName %4 "_ua_position"
+OpName %17 "gl_PerVertex"
+OpMemberName %17 0 "gl_Position"
+OpMemberName %17 1 "gl_PointSize"
+OpMemberName %17 2 "gl_ClipDistance"
+OpMemberName %17 3 "gl_CullDistance"
+OpName %19 ""
+OpName %22 "main"
+OpDecorate %4 Location 0
+OpMemberDecorate %17 1 RelaxedPrecision
+OpMemberDecorate %17 0 BuiltIn Position
+OpMemberDecorate %17 1 BuiltIn PointSize
+OpMemberDecorate %17 2 BuiltIn ClipDistance
+OpMemberDecorate %17 3 BuiltIn CullDistance
+OpDecorate %17 Block
+%1 = OpTypeFloat 32
+%2 = OpTypeVector %1 4
+%5 = OpTypeInt 32 0
+%8 = OpTypeVector %5 4
+%15 = OpConstant %5 8
+%16 = OpTypeArray %1 %15
+%17 = OpTypeStruct %2 %1 %16 %16
+%20 = OpTypeVoid
+%25 = OpConstant %5 0
+%3 = OpTypePointer Input %2
+%13 = OpTypePointer Output %2
+%18 = OpTypePointer Output %17
+%21 = OpTypeFunction %20
+%4 = OpVariable %3 Input
+%19 = OpVariable %18 Output
+%22 = OpFunction %20 None %21
+%23 = OpLabel
+%24 = OpLoad %2 %4
+%26 = OpAccessChain %13 %19 %25
+OpStore %26 %24
+OpReturn
+OpFunctionEnd

+ 1534 - 0
ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/large_functions_large_diffs_autogen.cpp

@@ -0,0 +1,1534 @@
+// GENERATED FILE - DO NOT EDIT.
+// Generated by generate_tests.py
+//
+// 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 "../diff_test_utils.h"
+
+#include "gtest/gtest.h"
+
+namespace spvtools {
+namespace diff {
+namespace {
+
+// Test where src and dst have a few large functions with large differences.
+constexpr char kSrc[] = R"(               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %4 "main" %15
+               OpExecutionMode %4 LocalSize 1 1 1
+               OpSource ESSL 310
+               OpName %4 "main"
+               OpName %6 "f1("
+               OpName %8 "f2("
+               OpName %12 "x"
+               OpName %15 "gl_LocalInvocationID"
+               OpName %20 "y"
+               OpName %27 "image"
+               OpName %44 "sum"
+               OpName %46 "i"
+               OpName %56 "j"
+               OpName %80 "BufferOut"
+               OpMemberName %80 0 "o_uv4"
+               OpMemberName %80 1 "o_v3"
+               OpMemberName %80 2 "o_i"
+               OpName %82 ""
+               OpName %88 "BufferIn"
+               OpMemberName %88 0 "i_u"
+               OpMemberName %88 1 "i_v4"
+               OpMemberName %88 2 "i_f"
+               OpName %90 ""
+               OpName %101 "i"
+               OpName %128 "image2"
+               OpDecorate %15 BuiltIn LocalInvocationId
+               OpDecorate %27 DescriptorSet 0
+               OpDecorate %27 Binding 2
+               OpMemberDecorate %80 0 Offset 0
+               OpMemberDecorate %80 1 Offset 16
+               OpMemberDecorate %80 2 Offset 28
+               OpDecorate %80 BufferBlock
+               OpDecorate %82 DescriptorSet 0
+               OpDecorate %82 Binding 1
+               OpMemberDecorate %88 0 Offset 0
+               OpMemberDecorate %88 1 RowMajor
+               OpMemberDecorate %88 1 Offset 16
+               OpMemberDecorate %88 1 MatrixStride 16
+               OpMemberDecorate %88 2 Offset 80
+               OpDecorate %88 Block
+               OpDecorate %90 DescriptorSet 0
+               OpDecorate %90 Binding 0
+               OpDecorate %128 DescriptorSet 0
+               OpDecorate %128 Binding 3
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+         %10 = OpTypeInt 32 0
+         %11 = OpTypePointer Function %10
+         %13 = OpTypeVector %10 3
+         %14 = OpTypePointer Input %13
+         %15 = OpVariable %14 Input
+         %16 = OpConstant %10 0
+         %17 = OpTypePointer Input %10
+         %21 = OpConstant %10 1
+         %24 = OpTypeInt 32 1
+         %25 = OpTypeImage %24 2D 0 0 0 2 R32i
+         %26 = OpTypePointer UniformConstant %25
+         %27 = OpVariable %26 UniformConstant
+         %29 = OpTypeVector %10 2
+         %32 = OpTypeVector %24 2
+         %38 = OpTypeVector %24 4
+         %40 = OpConstant %10 2
+         %41 = OpConstant %10 3400
+         %42 = OpConstant %10 264
+         %43 = OpTypePointer Function %24
+         %45 = OpConstant %24 0
+         %53 = OpConstant %24 2
+         %54 = OpTypeBool
+         %73 = OpConstant %24 1
+         %77 = OpTypeVector %10 4
+         %78 = OpTypeFloat 32
+         %79 = OpTypeVector %78 3
+         %80 = OpTypeStruct %77 %79 %24
+         %81 = OpTypePointer Uniform %80
+         %82 = OpVariable %81 Uniform
+         %84 = OpTypePointer Uniform %24
+         %86 = OpTypeVector %78 4
+         %87 = OpTypeMatrix %86 4
+         %88 = OpTypeStruct %10 %87 %78
+         %89 = OpTypePointer Uniform %88
+         %90 = OpVariable %89 Uniform
+         %91 = OpTypePointer Uniform %87
+         %94 = OpTypePointer Uniform %77
+        %108 = OpConstant %24 3
+        %110 = OpTypePointer Uniform %79
+        %113 = OpTypePointer Uniform %78
+        %128 = OpVariable %26 UniformConstant
+        %130 = OpConstantComposite %32 %45 %45
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+        %136 = OpFunctionCall %2 %6
+        %137 = OpFunctionCall %2 %8
+               OpReturn
+               OpFunctionEnd
+          %6 = OpFunction %2 None %3
+          %7 = OpLabel
+         %12 = OpVariable %11 Function
+         %20 = OpVariable %11 Function
+         %44 = OpVariable %43 Function
+         %46 = OpVariable %43 Function
+         %56 = OpVariable %43 Function
+         %18 = OpAccessChain %17 %15 %16
+         %19 = OpLoad %10 %18
+               OpStore %12 %19
+         %22 = OpAccessChain %17 %15 %21
+         %23 = OpLoad %10 %22
+               OpStore %20 %23
+         %28 = OpLoad %25 %27
+         %30 = OpLoad %13 %15
+         %31 = OpVectorShuffle %29 %30 %30 0 1
+         %33 = OpBitcast %32 %31
+         %34 = OpLoad %10 %12
+         %35 = OpLoad %10 %20
+         %36 = OpIAdd %10 %34 %35
+         %37 = OpBitcast %24 %36
+         %39 = OpCompositeConstruct %38 %37 %37 %37 %37
+               OpImageWrite %28 %33 %39
+               OpMemoryBarrier %40 %41
+               OpControlBarrier %40 %40 %42
+               OpStore %44 %45
+               OpStore %46 %45
+               OpBranch %47
+         %47 = OpLabel
+               OpLoopMerge %49 %50 None
+               OpBranch %51
+         %51 = OpLabel
+         %52 = OpLoad %24 %46
+         %55 = OpSLessThan %54 %52 %53
+               OpBranchConditional %55 %48 %49
+         %48 = OpLabel
+               OpStore %56 %45
+               OpBranch %57
+         %57 = OpLabel
+               OpLoopMerge %59 %60 None
+               OpBranch %61
+         %61 = OpLabel
+         %62 = OpLoad %24 %56
+         %63 = OpSLessThan %54 %62 %53
+               OpBranchConditional %63 %58 %59
+         %58 = OpLabel
+         %64 = OpLoad %25 %27
+         %65 = OpLoad %24 %46
+         %66 = OpLoad %24 %56
+         %67 = OpCompositeConstruct %32 %65 %66
+         %68 = OpImageRead %38 %64 %67
+         %69 = OpCompositeExtract %24 %68 0
+         %70 = OpLoad %24 %44
+         %71 = OpIMul %24 %70 %69
+               OpStore %44 %71
+               OpBranch %60
+         %60 = OpLabel
+         %72 = OpLoad %24 %56
+         %74 = OpIAdd %24 %72 %73
+               OpStore %56 %74
+               OpBranch %57
+         %59 = OpLabel
+               OpBranch %50
+         %50 = OpLabel
+         %75 = OpLoad %24 %46
+         %76 = OpIAdd %24 %75 %73
+               OpStore %46 %76
+               OpBranch %47
+         %49 = OpLabel
+               OpMemoryBarrier %40 %41
+               OpControlBarrier %40 %40 %42
+         %83 = OpLoad %24 %44
+         %85 = OpAccessChain %84 %82 %53
+               OpStore %85 %83
+               OpReturn
+               OpFunctionEnd
+          %8 = OpFunction %2 None %3
+          %9 = OpLabel
+        %101 = OpVariable %43 Function
+         %92 = OpAccessChain %91 %90 %73
+         %93 = OpLoad %87 %92
+         %95 = OpAccessChain %94 %82 %45
+         %96 = OpLoad %77 %95
+         %97 = OpConvertUToF %86 %96
+         %98 = OpMatrixTimesVector %86 %93 %97
+         %99 = OpConvertFToU %77 %98
+        %100 = OpAccessChain %94 %82 %45
+               OpStore %100 %99
+               OpStore %101 %45
+               OpBranch %102
+        %102 = OpLabel
+               OpLoopMerge %104 %105 None
+               OpBranch %106
+        %106 = OpLabel
+        %107 = OpLoad %24 %101
+        %109 = OpSLessThan %54 %107 %108
+               OpBranchConditional %109 %103 %104
+        %103 = OpLabel
+        %111 = OpAccessChain %110 %82 %73
+        %112 = OpLoad %79 %111
+        %114 = OpAccessChain %113 %90 %53
+        %115 = OpLoad %78 %114
+        %116 = OpVectorTimesScalar %79 %112 %115
+        %117 = OpConvertFToU %13 %116
+        %118 = OpCompositeExtract %10 %117 0
+        %119 = OpCompositeExtract %10 %117 1
+        %120 = OpCompositeExtract %10 %117 2
+        %121 = OpCompositeConstruct %77 %118 %119 %120 %16
+        %122 = OpAccessChain %94 %82 %45
+        %123 = OpLoad %77 %122
+        %124 = OpIAdd %77 %123 %121
+        %125 = OpAccessChain %94 %82 %45
+               OpStore %125 %124
+               OpBranch %105
+        %105 = OpLabel
+        %126 = OpLoad %24 %101
+        %127 = OpIAdd %24 %126 %73
+               OpStore %101 %127
+               OpBranch %102
+        %104 = OpLabel
+               OpMemoryBarrier %40 %41
+               OpControlBarrier %40 %40 %42
+        %129 = OpLoad %25 %128
+        %131 = OpImageRead %38 %129 %130
+        %132 = OpCompositeExtract %24 %131 0
+        %133 = OpConvertSToF %78 %132
+        %134 = OpCompositeConstruct %79 %133 %133 %133
+        %135 = OpAccessChain %110 %82 %73
+               OpStore %135 %134
+               OpReturn
+               OpFunctionEnd
+)";
+constexpr char kDst[] = R"(               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %4 "main" %15 %110
+               OpExecutionMode %4 LocalSize 1 1 1
+               OpSource ESSL 310
+               OpName %4 "main"
+               OpName %6 "f1("
+               OpName %8 "f2("
+               OpName %12 "x"
+               OpName %15 "gl_GlobalInvocationID"
+               OpName %20 "z"
+               OpName %26 "i"
+               OpName %40 "BufferOut"
+               OpMemberName %40 0 "o_uv4"
+               OpMemberName %40 1 "o_v3"
+               OpMemberName %40 2 "o_i"
+               OpName %42 ""
+               OpName %63 "image2"
+               OpName %79 "image"
+               OpName %89 "i"
+               OpName %110 "gl_LocalInvocationID"
+               OpName %127 "BufferIn"
+               OpMemberName %127 0 "i_u"
+               OpMemberName %127 1 "i_v4"
+               OpMemberName %127 2 "i_f"
+               OpName %129 ""
+               OpDecorate %15 BuiltIn GlobalInvocationId
+               OpMemberDecorate %40 0 Offset 0
+               OpMemberDecorate %40 1 Offset 16
+               OpMemberDecorate %40 2 Offset 28
+               OpDecorate %40 BufferBlock
+               OpDecorate %42 DescriptorSet 0
+               OpDecorate %42 Binding 1
+               OpDecorate %63 DescriptorSet 0
+               OpDecorate %63 Binding 3
+               OpDecorate %79 DescriptorSet 0
+               OpDecorate %79 Binding 2
+               OpDecorate %110 BuiltIn LocalInvocationId
+               OpMemberDecorate %127 0 Offset 0
+               OpMemberDecorate %127 1 RowMajor
+               OpMemberDecorate %127 1 Offset 16
+               OpMemberDecorate %127 1 MatrixStride 16
+               OpMemberDecorate %127 2 Offset 80
+               OpDecorate %127 Block
+               OpDecorate %129 DescriptorSet 0
+               OpDecorate %129 Binding 0
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+         %10 = OpTypeInt 32 0
+         %11 = OpTypePointer Function %10
+         %13 = OpTypeVector %10 3
+         %14 = OpTypePointer Input %13
+         %15 = OpVariable %14 Input
+         %16 = OpConstant %10 0
+         %17 = OpTypePointer Input %10
+         %21 = OpConstant %10 1
+         %24 = OpTypeInt 32 1
+         %25 = OpTypePointer Function %24
+         %27 = OpConstant %24 0
+         %34 = OpConstant %24 2
+         %35 = OpTypeBool
+         %37 = OpTypeVector %10 4
+         %38 = OpTypeFloat 32
+         %39 = OpTypeVector %38 3
+         %40 = OpTypeStruct %37 %39 %24
+         %41 = OpTypePointer Uniform %40
+         %42 = OpVariable %41 Uniform
+         %46 = OpTypeVector %10 2
+         %48 = OpTypePointer Uniform %37
+         %53 = OpTypePointer Uniform %10
+         %59 = OpConstant %24 1
+         %61 = OpTypeImage %24 2D 0 0 0 2 R32i
+         %62 = OpTypePointer UniformConstant %61
+         %63 = OpVariable %62 UniformConstant
+         %69 = OpTypeVector %24 2
+         %71 = OpTypeVector %24 4
+         %74 = OpTypePointer Uniform %24
+         %76 = OpConstant %10 2
+         %77 = OpConstant %10 3400
+         %78 = OpConstant %10 264
+         %79 = OpVariable %62 UniformConstant
+         %96 = OpConstant %24 3
+        %103 = OpConstantComposite %69 %27 %27
+        %107 = OpTypePointer Uniform %38
+        %110 = OpVariable %14 Input
+        %113 = OpTypeVector %38 2
+        %125 = OpTypeVector %38 4
+        %126 = OpTypeMatrix %125 4
+        %127 = OpTypeStruct %10 %126 %38
+        %128 = OpTypePointer Uniform %127
+        %129 = OpVariable %128 Uniform
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+        %123 = OpFunctionCall %2 %8
+        %124 = OpFunctionCall %2 %6
+               OpReturn
+               OpFunctionEnd
+          %6 = OpFunction %2 None %3
+          %7 = OpLabel
+         %12 = OpVariable %11 Function
+         %20 = OpVariable %11 Function
+         %26 = OpVariable %25 Function
+         %18 = OpAccessChain %17 %15 %16
+         %19 = OpLoad %10 %18
+               OpStore %12 %19
+         %22 = OpAccessChain %17 %15 %21
+         %23 = OpLoad %10 %22
+               OpStore %20 %23
+               OpStore %26 %27
+               OpBranch %28
+         %28 = OpLabel
+               OpLoopMerge %30 %31 None
+               OpBranch %32
+         %32 = OpLabel
+         %33 = OpLoad %24 %26
+         %36 = OpSLessThan %35 %33 %34
+               OpBranchConditional %36 %29 %30
+         %29 = OpLabel
+         %43 = OpLoad %10 %12
+         %44 = OpLoad %10 %20
+         %45 = OpIAdd %10 %43 %44
+         %47 = OpCompositeConstruct %46 %45 %45
+         %49 = OpAccessChain %48 %42 %27
+         %50 = OpLoad %37 %49
+         %51 = OpVectorShuffle %46 %50 %50 0 1
+         %52 = OpIAdd %46 %51 %47
+         %54 = OpAccessChain %53 %42 %27 %16
+         %55 = OpCompositeExtract %10 %52 0
+               OpStore %54 %55
+         %56 = OpAccessChain %53 %42 %27 %21
+         %57 = OpCompositeExtract %10 %52 1
+               OpStore %56 %57
+               OpBranch %31
+         %31 = OpLabel
+         %58 = OpLoad %24 %26
+         %60 = OpIAdd %24 %58 %59
+               OpStore %26 %60
+               OpBranch %28
+         %30 = OpLabel
+         %64 = OpLoad %61 %63
+         %65 = OpLoad %10 %12
+         %66 = OpBitcast %24 %65
+         %67 = OpLoad %10 %20
+         %68 = OpBitcast %24 %67
+         %70 = OpCompositeConstruct %69 %66 %68
+         %72 = OpImageRead %71 %64 %70
+         %73 = OpCompositeExtract %24 %72 1
+         %75 = OpAccessChain %74 %42 %34
+               OpStore %75 %73
+               OpMemoryBarrier %76 %77
+               OpControlBarrier %76 %76 %78
+         %80 = OpLoad %61 %79
+         %81 = OpLoad %10 %20
+         %82 = OpBitcast %24 %81
+         %83 = OpLoad %10 %12
+         %84 = OpBitcast %24 %83
+         %85 = OpCompositeConstruct %69 %82 %84
+         %86 = OpAccessChain %74 %42 %34
+         %87 = OpLoad %24 %86
+         %88 = OpCompositeConstruct %71 %87 %27 %27 %27
+               OpImageWrite %80 %85 %88
+               OpReturn
+               OpFunctionEnd
+          %8 = OpFunction %2 None %3
+          %9 = OpLabel
+         %89 = OpVariable %25 Function
+               OpStore %89 %27
+               OpBranch %90
+         %90 = OpLabel
+               OpLoopMerge %92 %93 None
+               OpBranch %94
+         %94 = OpLabel
+         %95 = OpLoad %24 %89
+         %97 = OpSLessThan %35 %95 %96
+               OpBranchConditional %97 %91 %92
+         %91 = OpLabel
+         %98 = OpLoad %24 %89
+         %99 = OpIEqual %35 %98 %27
+               OpSelectionMerge %101 None
+               OpBranchConditional %99 %100 %109
+        %100 = OpLabel
+        %102 = OpLoad %61 %63
+        %104 = OpImageRead %71 %102 %103
+        %105 = OpCompositeExtract %24 %104 0
+        %106 = OpConvertSToF %38 %105
+        %108 = OpAccessChain %107 %42 %59 %16
+               OpStore %108 %106
+               OpBranch %101
+        %109 = OpLabel
+        %111 = OpLoad %13 %110
+        %112 = OpConvertUToF %39 %111
+        %114 = OpCompositeExtract %38 %112 0
+        %115 = OpCompositeExtract %38 %112 1
+        %116 = OpCompositeConstruct %113 %114 %115
+        %117 = OpAccessChain %107 %42 %59 %21
+        %118 = OpCompositeExtract %38 %116 0
+               OpStore %117 %118
+        %119 = OpAccessChain %107 %42 %59 %76
+        %120 = OpCompositeExtract %38 %116 1
+               OpStore %119 %120
+               OpBranch %101
+        %101 = OpLabel
+               OpBranch %93
+         %93 = OpLabel
+        %121 = OpLoad %24 %89
+        %122 = OpIAdd %24 %121 %59
+               OpStore %89 %122
+               OpBranch %90
+         %92 = OpLabel
+               OpReturn
+               OpFunctionEnd
+
+)";
+
+TEST(DiffTest, LargeFunctionsLargeDiffs) {
+  constexpr char kDiff[] = R"( ; SPIR-V
+ ; Version: 1.6
+ ; Generator: Khronos SPIR-V Tools Assembler; 0
+-; Bound: 138
++; Bound: 190
+ ; Schema: 0
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+-OpEntryPoint GLCompute %4 "main" %15
++OpEntryPoint GLCompute %4 "main" %138 %15
+ OpExecutionMode %4 LocalSize 1 1 1
+ OpSource ESSL 310
+ OpName %4 "main"
+ OpName %6 "f1("
+ OpName %8 "f2("
+ OpName %12 "x"
++OpName %138 "gl_GlobalInvocationID"
+ OpName %15 "gl_LocalInvocationID"
+-OpName %20 "y"
++OpName %20 "z"
+ OpName %27 "image"
+-OpName %44 "sum"
++OpName %44 "i"
+-OpName %46 "i"
+-OpName %56 "j"
+ OpName %80 "BufferOut"
+ OpMemberName %80 0 "o_uv4"
+ OpMemberName %80 1 "o_v3"
+ OpMemberName %80 2 "o_i"
+ OpName %82 ""
+ OpName %88 "BufferIn"
+ OpMemberName %88 0 "i_u"
+ OpMemberName %88 1 "i_v4"
+ OpMemberName %88 2 "i_f"
+ OpName %90 ""
+ OpName %101 "i"
+ OpName %128 "image2"
++OpDecorate %138 BuiltIn GlobalInvocationId
+ OpDecorate %15 BuiltIn LocalInvocationId
+ OpDecorate %27 DescriptorSet 0
+ OpDecorate %27 Binding 2
+ OpMemberDecorate %80 0 Offset 0
+ OpMemberDecorate %80 1 Offset 16
+ OpMemberDecorate %80 2 Offset 28
+ OpDecorate %80 BufferBlock
+ OpDecorate %82 DescriptorSet 0
+ OpDecorate %82 Binding 1
+ OpMemberDecorate %88 0 Offset 0
+ OpMemberDecorate %88 1 RowMajor
+ OpMemberDecorate %88 1 Offset 16
+ OpMemberDecorate %88 1 MatrixStride 16
+ OpMemberDecorate %88 2 Offset 80
+ OpDecorate %88 Block
+ OpDecorate %90 DescriptorSet 0
+ OpDecorate %90 Binding 0
+ OpDecorate %128 DescriptorSet 0
+ OpDecorate %128 Binding 3
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %10 = OpTypeInt 32 0
+ %11 = OpTypePointer Function %10
+ %13 = OpTypeVector %10 3
+ %14 = OpTypePointer Input %13
++%138 = OpVariable %14 Input
+ %15 = OpVariable %14 Input
+ %16 = OpConstant %10 0
+ %17 = OpTypePointer Input %10
+ %21 = OpConstant %10 1
+ %24 = OpTypeInt 32 1
+ %25 = OpTypeImage %24 2D 0 0 0 2 R32i
+ %26 = OpTypePointer UniformConstant %25
+ %27 = OpVariable %26 UniformConstant
+ %29 = OpTypeVector %10 2
+ %32 = OpTypeVector %24 2
+ %38 = OpTypeVector %24 4
+ %40 = OpConstant %10 2
+ %41 = OpConstant %10 3400
+ %42 = OpConstant %10 264
+ %43 = OpTypePointer Function %24
+ %45 = OpConstant %24 0
++%149 = OpTypePointer Uniform %10
+ %53 = OpConstant %24 2
+ %54 = OpTypeBool
+ %73 = OpConstant %24 1
+ %77 = OpTypeVector %10 4
+ %78 = OpTypeFloat 32
+ %79 = OpTypeVector %78 3
+ %80 = OpTypeStruct %77 %79 %24
+ %81 = OpTypePointer Uniform %80
+ %82 = OpVariable %81 Uniform
+ %84 = OpTypePointer Uniform %24
+ %86 = OpTypeVector %78 4
+ %87 = OpTypeMatrix %86 4
+ %88 = OpTypeStruct %10 %87 %78
+ %89 = OpTypePointer Uniform %88
+ %90 = OpVariable %89 Uniform
+-%91 = OpTypePointer Uniform %87
++%179 = OpTypeVector %78 2
+ %94 = OpTypePointer Uniform %77
+ %108 = OpConstant %24 3
+-%110 = OpTypePointer Uniform %79
+ %113 = OpTypePointer Uniform %78
+ %128 = OpVariable %26 UniformConstant
+ %130 = OpConstantComposite %32 %45 %45
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+-%136 = OpFunctionCall %2 %6
+ %137 = OpFunctionCall %2 %8
++%189 = OpFunctionCall %2 %6
+ OpReturn
+ OpFunctionEnd
+ %6 = OpFunction %2 None %3
+ %7 = OpLabel
+ %12 = OpVariable %11 Function
+ %20 = OpVariable %11 Function
+ %44 = OpVariable %43 Function
+-%46 = OpVariable %43 Function
+-%56 = OpVariable %43 Function
+-%18 = OpAccessChain %17 %15 %16
++%139 = OpAccessChain %17 %138 %16
+-%19 = OpLoad %10 %18
++%19 = OpLoad %10 %139
+ OpStore %12 %19
+-%22 = OpAccessChain %17 %15 %21
++%140 = OpAccessChain %17 %138 %21
+-%23 = OpLoad %10 %22
++%23 = OpLoad %10 %140
+ OpStore %20 %23
+-%28 = OpLoad %25 %27
+-%30 = OpLoad %13 %15
+-%31 = OpVectorShuffle %29 %30 %30 0 1
+-%33 = OpBitcast %32 %31
+-%34 = OpLoad %10 %12
+-%35 = OpLoad %10 %20
+-%36 = OpIAdd %10 %34 %35
+-%37 = OpBitcast %24 %36
+-%39 = OpCompositeConstruct %38 %37 %37 %37 %37
+-OpImageWrite %28 %33 %39
+-OpMemoryBarrier %40 %41
+-OpControlBarrier %40 %40 %42
+ OpStore %44 %45
+-OpStore %46 %45
+ OpBranch %47
+ %47 = OpLabel
+-OpLoopMerge %49 %50 None
++OpLoopMerge %49 %59 None
+ OpBranch %51
+ %51 = OpLabel
+-%52 = OpLoad %24 %46
++%52 = OpLoad %24 %44
+ %55 = OpSLessThan %54 %52 %53
+ OpBranchConditional %55 %48 %49
+ %48 = OpLabel
+-OpStore %56 %45
+-OpBranch %57
+-%57 = OpLabel
+-OpLoopMerge %59 %60 None
+-OpBranch %61
+-%61 = OpLabel
+-%62 = OpLoad %24 %56
+-%63 = OpSLessThan %54 %62 %53
+-OpBranchConditional %63 %58 %59
+-%58 = OpLabel
+-%64 = OpLoad %25 %27
+-%65 = OpLoad %24 %46
+-%66 = OpLoad %24 %56
+-%67 = OpCompositeConstruct %32 %65 %66
+-%68 = OpImageRead %38 %64 %67
+-%69 = OpCompositeExtract %24 %68 0
+-%70 = OpLoad %24 %44
+-%71 = OpIMul %24 %70 %69
++%141 = OpLoad %10 %12
++%142 = OpLoad %10 %20
++%143 = OpIAdd %10 %141 %142
++%144 = OpCompositeConstruct %29 %143 %143
++%145 = OpAccessChain %94 %82 %45
++%146 = OpLoad %77 %145
++%147 = OpVectorShuffle %29 %146 %146 0 1
++%148 = OpIAdd %29 %147 %144
++%150 = OpAccessChain %149 %82 %45 %16
++%151 = OpCompositeExtract %10 %148 0
+-OpStore %44 %71
++OpStore %150 %151
+-OpBranch %60
+-%60 = OpLabel
+-%72 = OpLoad %24 %56
+-%74 = OpIAdd %24 %72 %73
++%152 = OpAccessChain %149 %82 %45 %21
++%153 = OpCompositeExtract %10 %148 1
+-OpStore %56 %74
++OpStore %152 %153
+-OpBranch %57
++OpBranch %59
+ %59 = OpLabel
+-OpBranch %50
+-%50 = OpLabel
+-%75 = OpLoad %24 %46
++%75 = OpLoad %24 %44
+ %76 = OpIAdd %24 %75 %73
+-OpStore %46 %76
++OpStore %44 %76
+ OpBranch %47
+ %49 = OpLabel
++%154 = OpLoad %25 %128
++%155 = OpLoad %10 %12
++%156 = OpBitcast %24 %155
++%157 = OpLoad %10 %20
++%158 = OpBitcast %24 %157
++%159 = OpCompositeConstruct %32 %156 %158
++%160 = OpImageRead %38 %154 %159
++%161 = OpCompositeExtract %24 %160 1
++%162 = OpAccessChain %84 %82 %53
++OpStore %162 %161
+ OpMemoryBarrier %40 %41
+ OpControlBarrier %40 %40 %42
+-%83 = OpLoad %24 %44
++%163 = OpLoad %25 %27
++%164 = OpLoad %10 %20
++%165 = OpBitcast %24 %164
++%166 = OpLoad %10 %12
++%167 = OpBitcast %24 %166
++%168 = OpCompositeConstruct %32 %165 %167
+ %85 = OpAccessChain %84 %82 %53
+-OpStore %85 %83
++%169 = OpLoad %24 %85
++%170 = OpCompositeConstruct %38 %169 %45 %45 %45
++OpImageWrite %163 %168 %170
+ OpReturn
+ OpFunctionEnd
+ %8 = OpFunction %2 None %3
+ %9 = OpLabel
+ %101 = OpVariable %43 Function
+-%92 = OpAccessChain %91 %90 %73
+-%93 = OpLoad %87 %92
+-%95 = OpAccessChain %94 %82 %45
+-%96 = OpLoad %77 %95
+-%97 = OpConvertUToF %86 %96
+-%98 = OpMatrixTimesVector %86 %93 %97
+-%99 = OpConvertFToU %77 %98
+-%100 = OpAccessChain %94 %82 %45
+-OpStore %100 %99
++OpStore %101 %45
+-OpStore %101 %45
+ OpBranch %102
+ %102 = OpLabel
+-OpLoopMerge %104 %105 None
++OpLoopMerge %171 %172 None
+ OpBranch %106
+ %106 = OpLabel
+ %107 = OpLoad %24 %101
+ %109 = OpSLessThan %54 %107 %108
+-OpBranchConditional %109 %103 %104
++OpBranchConditional %109 %103 %171
+ %103 = OpLabel
+-%111 = OpAccessChain %110 %82 %73
+-%112 = OpLoad %79 %111
+-%114 = OpAccessChain %113 %90 %53
+-%115 = OpLoad %78 %114
+-%116 = OpVectorTimesScalar %79 %112 %115
+-%117 = OpConvertFToU %13 %116
+-%118 = OpCompositeExtract %10 %117 0
+-%119 = OpCompositeExtract %10 %117 1
+-%120 = OpCompositeExtract %10 %117 2
+-%121 = OpCompositeConstruct %77 %118 %119 %120 %16
+-%122 = OpAccessChain %94 %82 %45
+-%123 = OpLoad %77 %122
+-%124 = OpIAdd %77 %123 %121
+-%125 = OpAccessChain %94 %82 %45
+-OpStore %125 %124
+-OpBranch %105
+-%105 = OpLabel
+ %126 = OpLoad %24 %101
+-%127 = OpIAdd %24 %126 %73
++%173 = OpIEqual %54 %126 %45
++OpSelectionMerge %174 None
++OpBranchConditional %173 %104 %176
++%176 = OpLabel
++%177 = OpLoad %13 %15
++%178 = OpConvertUToF %79 %177
++%180 = OpCompositeExtract %78 %178 0
++%181 = OpCompositeExtract %78 %178 1
++%182 = OpCompositeConstruct %179 %180 %181
++%183 = OpAccessChain %113 %82 %73 %21
++%184 = OpCompositeExtract %78 %182 0
+-OpStore %101 %127
++OpStore %183 %184
++%185 = OpAccessChain %113 %82 %73 %40
++%186 = OpCompositeExtract %78 %182 1
++OpStore %185 %186
+-OpBranch %102
++OpBranch %174
+ %104 = OpLabel
+-OpMemoryBarrier %40 %41
+-OpControlBarrier %40 %40 %42
+ %129 = OpLoad %25 %128
+ %131 = OpImageRead %38 %129 %130
+ %132 = OpCompositeExtract %24 %131 0
+ %133 = OpConvertSToF %78 %132
+-%134 = OpCompositeConstruct %79 %133 %133 %133
+-%135 = OpAccessChain %110 %82 %73
++%175 = OpAccessChain %113 %82 %73 %16
+-OpStore %135 %134
++OpStore %175 %133
++OpBranch %174
++%174 = OpLabel
++OpBranch %172
++%172 = OpLabel
++%187 = OpLoad %24 %101
++%188 = OpIAdd %24 %187 %73
++OpStore %101 %188
++OpBranch %102
++%171 = OpLabel
+ OpReturn
+ OpFunctionEnd
+)";
+  Options options;
+  DoStringDiffTest(kSrc, kDst, kDiff, options);
+}
+
+TEST(DiffTest, LargeFunctionsLargeDiffsNoDebug) {
+  constexpr char kSrcNoDebug[] = R"(               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %4 "main" %15
+               OpExecutionMode %4 LocalSize 1 1 1
+               OpSource ESSL 310
+               OpDecorate %15 BuiltIn LocalInvocationId
+               OpDecorate %27 DescriptorSet 0
+               OpDecorate %27 Binding 2
+               OpMemberDecorate %80 0 Offset 0
+               OpMemberDecorate %80 1 Offset 16
+               OpMemberDecorate %80 2 Offset 28
+               OpDecorate %80 BufferBlock
+               OpDecorate %82 DescriptorSet 0
+               OpDecorate %82 Binding 1
+               OpMemberDecorate %88 0 Offset 0
+               OpMemberDecorate %88 1 RowMajor
+               OpMemberDecorate %88 1 Offset 16
+               OpMemberDecorate %88 1 MatrixStride 16
+               OpMemberDecorate %88 2 Offset 80
+               OpDecorate %88 Block
+               OpDecorate %90 DescriptorSet 0
+               OpDecorate %90 Binding 0
+               OpDecorate %128 DescriptorSet 0
+               OpDecorate %128 Binding 3
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+         %10 = OpTypeInt 32 0
+         %11 = OpTypePointer Function %10
+         %13 = OpTypeVector %10 3
+         %14 = OpTypePointer Input %13
+         %15 = OpVariable %14 Input
+         %16 = OpConstant %10 0
+         %17 = OpTypePointer Input %10
+         %21 = OpConstant %10 1
+         %24 = OpTypeInt 32 1
+         %25 = OpTypeImage %24 2D 0 0 0 2 R32i
+         %26 = OpTypePointer UniformConstant %25
+         %27 = OpVariable %26 UniformConstant
+         %29 = OpTypeVector %10 2
+         %32 = OpTypeVector %24 2
+         %38 = OpTypeVector %24 4
+         %40 = OpConstant %10 2
+         %41 = OpConstant %10 3400
+         %42 = OpConstant %10 264
+         %43 = OpTypePointer Function %24
+         %45 = OpConstant %24 0
+         %53 = OpConstant %24 2
+         %54 = OpTypeBool
+         %73 = OpConstant %24 1
+         %77 = OpTypeVector %10 4
+         %78 = OpTypeFloat 32
+         %79 = OpTypeVector %78 3
+         %80 = OpTypeStruct %77 %79 %24
+         %81 = OpTypePointer Uniform %80
+         %82 = OpVariable %81 Uniform
+         %84 = OpTypePointer Uniform %24
+         %86 = OpTypeVector %78 4
+         %87 = OpTypeMatrix %86 4
+         %88 = OpTypeStruct %10 %87 %78
+         %89 = OpTypePointer Uniform %88
+         %90 = OpVariable %89 Uniform
+         %91 = OpTypePointer Uniform %87
+         %94 = OpTypePointer Uniform %77
+        %108 = OpConstant %24 3
+        %110 = OpTypePointer Uniform %79
+        %113 = OpTypePointer Uniform %78
+        %128 = OpVariable %26 UniformConstant
+        %130 = OpConstantComposite %32 %45 %45
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+        %136 = OpFunctionCall %2 %6
+        %137 = OpFunctionCall %2 %8
+               OpReturn
+               OpFunctionEnd
+          %6 = OpFunction %2 None %3
+          %7 = OpLabel
+         %12 = OpVariable %11 Function
+         %20 = OpVariable %11 Function
+         %44 = OpVariable %43 Function
+         %46 = OpVariable %43 Function
+         %56 = OpVariable %43 Function
+         %18 = OpAccessChain %17 %15 %16
+         %19 = OpLoad %10 %18
+               OpStore %12 %19
+         %22 = OpAccessChain %17 %15 %21
+         %23 = OpLoad %10 %22
+               OpStore %20 %23
+         %28 = OpLoad %25 %27
+         %30 = OpLoad %13 %15
+         %31 = OpVectorShuffle %29 %30 %30 0 1
+         %33 = OpBitcast %32 %31
+         %34 = OpLoad %10 %12
+         %35 = OpLoad %10 %20
+         %36 = OpIAdd %10 %34 %35
+         %37 = OpBitcast %24 %36
+         %39 = OpCompositeConstruct %38 %37 %37 %37 %37
+               OpImageWrite %28 %33 %39
+               OpMemoryBarrier %40 %41
+               OpControlBarrier %40 %40 %42
+               OpStore %44 %45
+               OpStore %46 %45
+               OpBranch %47
+         %47 = OpLabel
+               OpLoopMerge %49 %50 None
+               OpBranch %51
+         %51 = OpLabel
+         %52 = OpLoad %24 %46
+         %55 = OpSLessThan %54 %52 %53
+               OpBranchConditional %55 %48 %49
+         %48 = OpLabel
+               OpStore %56 %45
+               OpBranch %57
+         %57 = OpLabel
+               OpLoopMerge %59 %60 None
+               OpBranch %61
+         %61 = OpLabel
+         %62 = OpLoad %24 %56
+         %63 = OpSLessThan %54 %62 %53
+               OpBranchConditional %63 %58 %59
+         %58 = OpLabel
+         %64 = OpLoad %25 %27
+         %65 = OpLoad %24 %46
+         %66 = OpLoad %24 %56
+         %67 = OpCompositeConstruct %32 %65 %66
+         %68 = OpImageRead %38 %64 %67
+         %69 = OpCompositeExtract %24 %68 0
+         %70 = OpLoad %24 %44
+         %71 = OpIMul %24 %70 %69
+               OpStore %44 %71
+               OpBranch %60
+         %60 = OpLabel
+         %72 = OpLoad %24 %56
+         %74 = OpIAdd %24 %72 %73
+               OpStore %56 %74
+               OpBranch %57
+         %59 = OpLabel
+               OpBranch %50
+         %50 = OpLabel
+         %75 = OpLoad %24 %46
+         %76 = OpIAdd %24 %75 %73
+               OpStore %46 %76
+               OpBranch %47
+         %49 = OpLabel
+               OpMemoryBarrier %40 %41
+               OpControlBarrier %40 %40 %42
+         %83 = OpLoad %24 %44
+         %85 = OpAccessChain %84 %82 %53
+               OpStore %85 %83
+               OpReturn
+               OpFunctionEnd
+          %8 = OpFunction %2 None %3
+          %9 = OpLabel
+        %101 = OpVariable %43 Function
+         %92 = OpAccessChain %91 %90 %73
+         %93 = OpLoad %87 %92
+         %95 = OpAccessChain %94 %82 %45
+         %96 = OpLoad %77 %95
+         %97 = OpConvertUToF %86 %96
+         %98 = OpMatrixTimesVector %86 %93 %97
+         %99 = OpConvertFToU %77 %98
+        %100 = OpAccessChain %94 %82 %45
+               OpStore %100 %99
+               OpStore %101 %45
+               OpBranch %102
+        %102 = OpLabel
+               OpLoopMerge %104 %105 None
+               OpBranch %106
+        %106 = OpLabel
+        %107 = OpLoad %24 %101
+        %109 = OpSLessThan %54 %107 %108
+               OpBranchConditional %109 %103 %104
+        %103 = OpLabel
+        %111 = OpAccessChain %110 %82 %73
+        %112 = OpLoad %79 %111
+        %114 = OpAccessChain %113 %90 %53
+        %115 = OpLoad %78 %114
+        %116 = OpVectorTimesScalar %79 %112 %115
+        %117 = OpConvertFToU %13 %116
+        %118 = OpCompositeExtract %10 %117 0
+        %119 = OpCompositeExtract %10 %117 1
+        %120 = OpCompositeExtract %10 %117 2
+        %121 = OpCompositeConstruct %77 %118 %119 %120 %16
+        %122 = OpAccessChain %94 %82 %45
+        %123 = OpLoad %77 %122
+        %124 = OpIAdd %77 %123 %121
+        %125 = OpAccessChain %94 %82 %45
+               OpStore %125 %124
+               OpBranch %105
+        %105 = OpLabel
+        %126 = OpLoad %24 %101
+        %127 = OpIAdd %24 %126 %73
+               OpStore %101 %127
+               OpBranch %102
+        %104 = OpLabel
+               OpMemoryBarrier %40 %41
+               OpControlBarrier %40 %40 %42
+        %129 = OpLoad %25 %128
+        %131 = OpImageRead %38 %129 %130
+        %132 = OpCompositeExtract %24 %131 0
+        %133 = OpConvertSToF %78 %132
+        %134 = OpCompositeConstruct %79 %133 %133 %133
+        %135 = OpAccessChain %110 %82 %73
+               OpStore %135 %134
+               OpReturn
+               OpFunctionEnd
+
+)";
+  constexpr char kDstNoDebug[] = R"(               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %4 "main" %15 %110
+               OpExecutionMode %4 LocalSize 1 1 1
+               OpSource ESSL 310
+               OpDecorate %15 BuiltIn GlobalInvocationId
+               OpMemberDecorate %40 0 Offset 0
+               OpMemberDecorate %40 1 Offset 16
+               OpMemberDecorate %40 2 Offset 28
+               OpDecorate %40 BufferBlock
+               OpDecorate %42 DescriptorSet 0
+               OpDecorate %42 Binding 1
+               OpDecorate %63 DescriptorSet 0
+               OpDecorate %63 Binding 3
+               OpDecorate %79 DescriptorSet 0
+               OpDecorate %79 Binding 2
+               OpDecorate %110 BuiltIn LocalInvocationId
+               OpMemberDecorate %127 0 Offset 0
+               OpMemberDecorate %127 1 RowMajor
+               OpMemberDecorate %127 1 Offset 16
+               OpMemberDecorate %127 1 MatrixStride 16
+               OpMemberDecorate %127 2 Offset 80
+               OpDecorate %127 Block
+               OpDecorate %129 DescriptorSet 0
+               OpDecorate %129 Binding 0
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+         %10 = OpTypeInt 32 0
+         %11 = OpTypePointer Function %10
+         %13 = OpTypeVector %10 3
+         %14 = OpTypePointer Input %13
+         %15 = OpVariable %14 Input
+         %16 = OpConstant %10 0
+         %17 = OpTypePointer Input %10
+         %21 = OpConstant %10 1
+         %24 = OpTypeInt 32 1
+         %25 = OpTypePointer Function %24
+         %27 = OpConstant %24 0
+         %34 = OpConstant %24 2
+         %35 = OpTypeBool
+         %37 = OpTypeVector %10 4
+         %38 = OpTypeFloat 32
+         %39 = OpTypeVector %38 3
+         %40 = OpTypeStruct %37 %39 %24
+         %41 = OpTypePointer Uniform %40
+         %42 = OpVariable %41 Uniform
+         %46 = OpTypeVector %10 2
+         %48 = OpTypePointer Uniform %37
+         %53 = OpTypePointer Uniform %10
+         %59 = OpConstant %24 1
+         %61 = OpTypeImage %24 2D 0 0 0 2 R32i
+         %62 = OpTypePointer UniformConstant %61
+         %63 = OpVariable %62 UniformConstant
+         %69 = OpTypeVector %24 2
+         %71 = OpTypeVector %24 4
+         %74 = OpTypePointer Uniform %24
+         %76 = OpConstant %10 2
+         %77 = OpConstant %10 3400
+         %78 = OpConstant %10 264
+         %79 = OpVariable %62 UniformConstant
+         %96 = OpConstant %24 3
+        %103 = OpConstantComposite %69 %27 %27
+        %107 = OpTypePointer Uniform %38
+        %110 = OpVariable %14 Input
+        %113 = OpTypeVector %38 2
+        %125 = OpTypeVector %38 4
+        %126 = OpTypeMatrix %125 4
+        %127 = OpTypeStruct %10 %126 %38
+        %128 = OpTypePointer Uniform %127
+        %129 = OpVariable %128 Uniform
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+        %123 = OpFunctionCall %2 %8
+        %124 = OpFunctionCall %2 %6
+               OpReturn
+               OpFunctionEnd
+          %6 = OpFunction %2 None %3
+          %7 = OpLabel
+         %12 = OpVariable %11 Function
+         %20 = OpVariable %11 Function
+         %26 = OpVariable %25 Function
+         %18 = OpAccessChain %17 %15 %16
+         %19 = OpLoad %10 %18
+               OpStore %12 %19
+         %22 = OpAccessChain %17 %15 %21
+         %23 = OpLoad %10 %22
+               OpStore %20 %23
+               OpStore %26 %27
+               OpBranch %28
+         %28 = OpLabel
+               OpLoopMerge %30 %31 None
+               OpBranch %32
+         %32 = OpLabel
+         %33 = OpLoad %24 %26
+         %36 = OpSLessThan %35 %33 %34
+               OpBranchConditional %36 %29 %30
+         %29 = OpLabel
+         %43 = OpLoad %10 %12
+         %44 = OpLoad %10 %20
+         %45 = OpIAdd %10 %43 %44
+         %47 = OpCompositeConstruct %46 %45 %45
+         %49 = OpAccessChain %48 %42 %27
+         %50 = OpLoad %37 %49
+         %51 = OpVectorShuffle %46 %50 %50 0 1
+         %52 = OpIAdd %46 %51 %47
+         %54 = OpAccessChain %53 %42 %27 %16
+         %55 = OpCompositeExtract %10 %52 0
+               OpStore %54 %55
+         %56 = OpAccessChain %53 %42 %27 %21
+         %57 = OpCompositeExtract %10 %52 1
+               OpStore %56 %57
+               OpBranch %31
+         %31 = OpLabel
+         %58 = OpLoad %24 %26
+         %60 = OpIAdd %24 %58 %59
+               OpStore %26 %60
+               OpBranch %28
+         %30 = OpLabel
+         %64 = OpLoad %61 %63
+         %65 = OpLoad %10 %12
+         %66 = OpBitcast %24 %65
+         %67 = OpLoad %10 %20
+         %68 = OpBitcast %24 %67
+         %70 = OpCompositeConstruct %69 %66 %68
+         %72 = OpImageRead %71 %64 %70
+         %73 = OpCompositeExtract %24 %72 1
+         %75 = OpAccessChain %74 %42 %34
+               OpStore %75 %73
+               OpMemoryBarrier %76 %77
+               OpControlBarrier %76 %76 %78
+         %80 = OpLoad %61 %79
+         %81 = OpLoad %10 %20
+         %82 = OpBitcast %24 %81
+         %83 = OpLoad %10 %12
+         %84 = OpBitcast %24 %83
+         %85 = OpCompositeConstruct %69 %82 %84
+         %86 = OpAccessChain %74 %42 %34
+         %87 = OpLoad %24 %86
+         %88 = OpCompositeConstruct %71 %87 %27 %27 %27
+               OpImageWrite %80 %85 %88
+               OpReturn
+               OpFunctionEnd
+          %8 = OpFunction %2 None %3
+          %9 = OpLabel
+         %89 = OpVariable %25 Function
+               OpStore %89 %27
+               OpBranch %90
+         %90 = OpLabel
+               OpLoopMerge %92 %93 None
+               OpBranch %94
+         %94 = OpLabel
+         %95 = OpLoad %24 %89
+         %97 = OpSLessThan %35 %95 %96
+               OpBranchConditional %97 %91 %92
+         %91 = OpLabel
+         %98 = OpLoad %24 %89
+         %99 = OpIEqual %35 %98 %27
+               OpSelectionMerge %101 None
+               OpBranchConditional %99 %100 %109
+        %100 = OpLabel
+        %102 = OpLoad %61 %63
+        %104 = OpImageRead %71 %102 %103
+        %105 = OpCompositeExtract %24 %104 0
+        %106 = OpConvertSToF %38 %105
+        %108 = OpAccessChain %107 %42 %59 %16
+               OpStore %108 %106
+               OpBranch %101
+        %109 = OpLabel
+        %111 = OpLoad %13 %110
+        %112 = OpConvertUToF %39 %111
+        %114 = OpCompositeExtract %38 %112 0
+        %115 = OpCompositeExtract %38 %112 1
+        %116 = OpCompositeConstruct %113 %114 %115
+        %117 = OpAccessChain %107 %42 %59 %21
+        %118 = OpCompositeExtract %38 %116 0
+               OpStore %117 %118
+        %119 = OpAccessChain %107 %42 %59 %76
+        %120 = OpCompositeExtract %38 %116 1
+               OpStore %119 %120
+               OpBranch %101
+        %101 = OpLabel
+               OpBranch %93
+         %93 = OpLabel
+        %121 = OpLoad %24 %89
+        %122 = OpIAdd %24 %121 %59
+               OpStore %89 %122
+               OpBranch %90
+         %92 = OpLabel
+               OpReturn
+               OpFunctionEnd
+
+)";
+  constexpr char kDiff[] = R"( ; SPIR-V
+ ; Version: 1.6
+ ; Generator: Khronos SPIR-V Tools Assembler; 0
+-; Bound: 138
++; Bound: 220
+ ; Schema: 0
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+-OpEntryPoint GLCompute %4 "main" %15
++OpEntryPoint GLCompute %4 "main" %143 %15
+ OpExecutionMode %4 LocalSize 1 1 1
+ OpSource ESSL 310
++OpDecorate %143 BuiltIn GlobalInvocationId
+ OpDecorate %15 BuiltIn LocalInvocationId
+ OpDecorate %27 DescriptorSet 0
+ OpDecorate %27 Binding 2
+ OpMemberDecorate %80 0 Offset 0
+ OpMemberDecorate %80 1 Offset 16
+ OpMemberDecorate %80 2 Offset 28
+ OpDecorate %80 BufferBlock
+ OpDecorate %82 DescriptorSet 0
+ OpDecorate %82 Binding 1
+ OpMemberDecorate %88 0 Offset 0
+ OpMemberDecorate %88 1 RowMajor
+ OpMemberDecorate %88 1 Offset 16
+ OpMemberDecorate %88 1 MatrixStride 16
+ OpMemberDecorate %88 2 Offset 80
+ OpDecorate %88 Block
+ OpDecorate %90 DescriptorSet 0
+ OpDecorate %90 Binding 0
+ OpDecorate %128 DescriptorSet 0
+ OpDecorate %128 Binding 3
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %10 = OpTypeInt 32 0
+ %11 = OpTypePointer Function %10
+ %13 = OpTypeVector %10 3
+ %14 = OpTypePointer Input %13
++%143 = OpVariable %14 Input
+ %15 = OpVariable %14 Input
+ %16 = OpConstant %10 0
+ %17 = OpTypePointer Input %10
+ %21 = OpConstant %10 1
+ %24 = OpTypeInt 32 1
+ %25 = OpTypeImage %24 2D 0 0 0 2 R32i
+ %26 = OpTypePointer UniformConstant %25
+ %27 = OpVariable %26 UniformConstant
+ %29 = OpTypeVector %10 2
+ %32 = OpTypeVector %24 2
+ %38 = OpTypeVector %24 4
+ %40 = OpConstant %10 2
+ %41 = OpConstant %10 3400
+ %42 = OpConstant %10 264
+ %43 = OpTypePointer Function %24
+ %45 = OpConstant %24 0
++%165 = OpTypePointer Uniform %10
+ %53 = OpConstant %24 2
+ %54 = OpTypeBool
+ %73 = OpConstant %24 1
+ %77 = OpTypeVector %10 4
+ %78 = OpTypeFloat 32
+ %79 = OpTypeVector %78 3
+ %80 = OpTypeStruct %77 %79 %24
+ %81 = OpTypePointer Uniform %80
+ %82 = OpVariable %81 Uniform
+ %84 = OpTypePointer Uniform %24
+ %86 = OpTypeVector %78 4
+ %87 = OpTypeMatrix %86 4
+ %88 = OpTypeStruct %10 %87 %78
+ %89 = OpTypePointer Uniform %88
+ %90 = OpVariable %89 Uniform
+-%91 = OpTypePointer Uniform %87
++%210 = OpTypeVector %78 2
+ %94 = OpTypePointer Uniform %77
+ %108 = OpConstant %24 3
+-%110 = OpTypePointer Uniform %79
+ %113 = OpTypePointer Uniform %78
+ %128 = OpVariable %26 UniformConstant
+ %130 = OpConstantComposite %32 %45 %45
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+-%136 = OpFunctionCall %2 %6
++%136 = OpFunctionCall %2 %140
+-%137 = OpFunctionCall %2 %8
++%137 = OpFunctionCall %2 %138
+ OpReturn
+ OpFunctionEnd
+-%6 = OpFunction %2 None %3
+-%7 = OpLabel
+-%12 = OpVariable %11 Function
+-%20 = OpVariable %11 Function
+-%44 = OpVariable %43 Function
+-%46 = OpVariable %43 Function
+-%56 = OpVariable %43 Function
+-%18 = OpAccessChain %17 %15 %16
+-%19 = OpLoad %10 %18
+-OpStore %12 %19
+-%22 = OpAccessChain %17 %15 %21
+-%23 = OpLoad %10 %22
+-OpStore %20 %23
+-%28 = OpLoad %25 %27
+-%30 = OpLoad %13 %15
+-%31 = OpVectorShuffle %29 %30 %30 0 1
+-%33 = OpBitcast %32 %31
+-%34 = OpLoad %10 %12
+-%35 = OpLoad %10 %20
+-%36 = OpIAdd %10 %34 %35
+-%37 = OpBitcast %24 %36
+-%39 = OpCompositeConstruct %38 %37 %37 %37 %37
+-OpImageWrite %28 %33 %39
+-OpMemoryBarrier %40 %41
+-OpControlBarrier %40 %40 %42
+-OpStore %44 %45
+-OpStore %46 %45
+-OpBranch %47
+-%47 = OpLabel
+-OpLoopMerge %49 %50 None
+-OpBranch %51
+-%51 = OpLabel
+-%52 = OpLoad %24 %46
+-%55 = OpSLessThan %54 %52 %53
+-OpBranchConditional %55 %48 %49
+-%48 = OpLabel
+-OpStore %56 %45
+-OpBranch %57
+-%57 = OpLabel
+-OpLoopMerge %59 %60 None
+-OpBranch %61
+-%61 = OpLabel
+-%62 = OpLoad %24 %56
+-%63 = OpSLessThan %54 %62 %53
+-OpBranchConditional %63 %58 %59
+-%58 = OpLabel
+-%64 = OpLoad %25 %27
+-%65 = OpLoad %24 %46
+-%66 = OpLoad %24 %56
+-%67 = OpCompositeConstruct %32 %65 %66
+-%68 = OpImageRead %38 %64 %67
+-%69 = OpCompositeExtract %24 %68 0
+-%70 = OpLoad %24 %44
+-%71 = OpIMul %24 %70 %69
+-OpStore %44 %71
+-OpBranch %60
+-%60 = OpLabel
+-%72 = OpLoad %24 %56
+-%74 = OpIAdd %24 %72 %73
+-OpStore %56 %74
+-OpBranch %57
+-%59 = OpLabel
+-OpBranch %50
+-%50 = OpLabel
+-%75 = OpLoad %24 %46
+-%76 = OpIAdd %24 %75 %73
+-OpStore %46 %76
+-OpBranch %47
+-%49 = OpLabel
+-OpMemoryBarrier %40 %41
+-OpControlBarrier %40 %40 %42
+-%83 = OpLoad %24 %44
+-%85 = OpAccessChain %84 %82 %53
+-OpStore %85 %83
+-OpReturn
+-OpFunctionEnd
+-%8 = OpFunction %2 None %3
+-%9 = OpLabel
+-%101 = OpVariable %43 Function
+-%92 = OpAccessChain %91 %90 %73
+-%93 = OpLoad %87 %92
+-%95 = OpAccessChain %94 %82 %45
+-%96 = OpLoad %77 %95
+-%97 = OpConvertUToF %86 %96
+-%98 = OpMatrixTimesVector %86 %93 %97
+-%99 = OpConvertFToU %77 %98
+-%100 = OpAccessChain %94 %82 %45
+-OpStore %100 %99
+-OpStore %101 %45
+-OpBranch %102
+-%102 = OpLabel
+-OpLoopMerge %104 %105 None
+-OpBranch %106
+-%106 = OpLabel
+-%107 = OpLoad %24 %101
+-%109 = OpSLessThan %54 %107 %108
+-OpBranchConditional %109 %103 %104
+-%103 = OpLabel
+-%111 = OpAccessChain %110 %82 %73
+-%112 = OpLoad %79 %111
+-%114 = OpAccessChain %113 %90 %53
+-%115 = OpLoad %78 %114
+-%116 = OpVectorTimesScalar %79 %112 %115
+-%117 = OpConvertFToU %13 %116
+-%118 = OpCompositeExtract %10 %117 0
+-%119 = OpCompositeExtract %10 %117 1
+-%120 = OpCompositeExtract %10 %117 2
+-%121 = OpCompositeConstruct %77 %118 %119 %120 %16
+-%122 = OpAccessChain %94 %82 %45
+-%123 = OpLoad %77 %122
+-%124 = OpIAdd %77 %123 %121
+-%125 = OpAccessChain %94 %82 %45
+-OpStore %125 %124
+-OpBranch %105
+-%105 = OpLabel
+-%126 = OpLoad %24 %101
+-%127 = OpIAdd %24 %126 %73
+-OpStore %101 %127
+-OpBranch %102
+-%104 = OpLabel
+-OpMemoryBarrier %40 %41
+-OpControlBarrier %40 %40 %42
+-%129 = OpLoad %25 %128
+-%131 = OpImageRead %38 %129 %130
+-%132 = OpCompositeExtract %24 %131 0
+-%133 = OpConvertSToF %78 %132
+-%134 = OpCompositeConstruct %79 %133 %133 %133
+-%135 = OpAccessChain %110 %82 %73
+-OpStore %135 %134
+-OpReturn
+-OpFunctionEnd
++%138 = OpFunction %2 None %3
++%139 = OpLabel
++%142 = OpVariable %11 Function
++%146 = OpVariable %11 Function
++%149 = OpVariable %43 Function
++%144 = OpAccessChain %17 %143 %16
++%145 = OpLoad %10 %144
++OpStore %142 %145
++%147 = OpAccessChain %17 %143 %21
++%148 = OpLoad %10 %147
++OpStore %146 %148
++OpStore %149 %45
++OpBranch %150
++%150 = OpLabel
++OpLoopMerge %152 %153 None
++OpBranch %154
++%154 = OpLabel
++%155 = OpLoad %24 %149
++%156 = OpSLessThan %54 %155 %53
++OpBranchConditional %156 %151 %152
++%151 = OpLabel
++%157 = OpLoad %10 %142
++%158 = OpLoad %10 %146
++%159 = OpIAdd %10 %157 %158
++%160 = OpCompositeConstruct %29 %159 %159
++%161 = OpAccessChain %94 %82 %45
++%162 = OpLoad %77 %161
++%163 = OpVectorShuffle %29 %162 %162 0 1
++%164 = OpIAdd %29 %163 %160
++%166 = OpAccessChain %165 %82 %45 %16
++%167 = OpCompositeExtract %10 %164 0
++OpStore %166 %167
++%168 = OpAccessChain %165 %82 %45 %21
++%169 = OpCompositeExtract %10 %164 1
++OpStore %168 %169
++OpBranch %153
++%153 = OpLabel
++%170 = OpLoad %24 %149
++%171 = OpIAdd %24 %170 %73
++OpStore %149 %171
++OpBranch %150
++%152 = OpLabel
++%172 = OpLoad %25 %128
++%173 = OpLoad %10 %142
++%174 = OpBitcast %24 %173
++%175 = OpLoad %10 %146
++%176 = OpBitcast %24 %175
++%177 = OpCompositeConstruct %32 %174 %176
++%178 = OpImageRead %38 %172 %177
++%179 = OpCompositeExtract %24 %178 1
++%180 = OpAccessChain %84 %82 %53
++OpStore %180 %179
++OpMemoryBarrier %40 %41
++OpControlBarrier %40 %40 %42
++%181 = OpLoad %25 %27
++%182 = OpLoad %10 %146
++%183 = OpBitcast %24 %182
++%184 = OpLoad %10 %142
++%185 = OpBitcast %24 %184
++%186 = OpCompositeConstruct %32 %183 %185
++%187 = OpAccessChain %84 %82 %53
++%188 = OpLoad %24 %187
++%189 = OpCompositeConstruct %38 %188 %45 %45 %45
++OpImageWrite %181 %186 %189
++OpReturn
++OpFunctionEnd
++%140 = OpFunction %2 None %3
++%141 = OpLabel
++%190 = OpVariable %43 Function
++OpStore %190 %45
++OpBranch %191
++%191 = OpLabel
++OpLoopMerge %193 %194 None
++OpBranch %195
++%195 = OpLabel
++%196 = OpLoad %24 %190
++%197 = OpSLessThan %54 %196 %108
++OpBranchConditional %197 %192 %193
++%192 = OpLabel
++%198 = OpLoad %24 %190
++%199 = OpIEqual %54 %198 %45
++OpSelectionMerge %201 None
++OpBranchConditional %199 %200 %207
++%207 = OpLabel
++%208 = OpLoad %13 %15
++%209 = OpConvertUToF %79 %208
++%211 = OpCompositeExtract %78 %209 0
++%212 = OpCompositeExtract %78 %209 1
++%213 = OpCompositeConstruct %210 %211 %212
++%214 = OpAccessChain %113 %82 %73 %21
++%215 = OpCompositeExtract %78 %213 0
++OpStore %214 %215
++%216 = OpAccessChain %113 %82 %73 %40
++%217 = OpCompositeExtract %78 %213 1
++OpStore %216 %217
++OpBranch %201
++%200 = OpLabel
++%202 = OpLoad %25 %128
++%203 = OpImageRead %38 %202 %130
++%204 = OpCompositeExtract %24 %203 0
++%205 = OpConvertSToF %78 %204
++%206 = OpAccessChain %113 %82 %73 %16
++OpStore %206 %205
++OpBranch %201
++%201 = OpLabel
++OpBranch %194
++%194 = OpLabel
++%218 = OpLoad %24 %190
++%219 = OpIAdd %24 %218 %73
++OpStore %190 %219
++OpBranch %191
++%193 = OpLabel
++OpReturn
++OpFunctionEnd
+)";
+  Options options;
+  DoStringDiffTest(kSrcNoDebug, kDstNoDebug, kDiff, options);
+}
+
+}  // namespace
+}  // namespace diff
+}  // namespace spvtools

+ 213 - 0
ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/large_functions_large_diffs_dst.spvasm

@@ -0,0 +1,213 @@
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %4 "main" %15 %110
+               OpExecutionMode %4 LocalSize 1 1 1
+               OpSource ESSL 310
+               OpName %4 "main"
+               OpName %6 "f1("
+               OpName %8 "f2("
+               OpName %12 "x"
+               OpName %15 "gl_GlobalInvocationID"
+               OpName %20 "z"
+               OpName %26 "i"
+               OpName %40 "BufferOut"
+               OpMemberName %40 0 "o_uv4"
+               OpMemberName %40 1 "o_v3"
+               OpMemberName %40 2 "o_i"
+               OpName %42 ""
+               OpName %63 "image2"
+               OpName %79 "image"
+               OpName %89 "i"
+               OpName %110 "gl_LocalInvocationID"
+               OpName %127 "BufferIn"
+               OpMemberName %127 0 "i_u"
+               OpMemberName %127 1 "i_v4"
+               OpMemberName %127 2 "i_f"
+               OpName %129 ""
+               OpDecorate %15 BuiltIn GlobalInvocationId
+               OpMemberDecorate %40 0 Offset 0
+               OpMemberDecorate %40 1 Offset 16
+               OpMemberDecorate %40 2 Offset 28
+               OpDecorate %40 BufferBlock
+               OpDecorate %42 DescriptorSet 0
+               OpDecorate %42 Binding 1
+               OpDecorate %63 DescriptorSet 0
+               OpDecorate %63 Binding 3
+               OpDecorate %79 DescriptorSet 0
+               OpDecorate %79 Binding 2
+               OpDecorate %110 BuiltIn LocalInvocationId
+               OpMemberDecorate %127 0 Offset 0
+               OpMemberDecorate %127 1 RowMajor
+               OpMemberDecorate %127 1 Offset 16
+               OpMemberDecorate %127 1 MatrixStride 16
+               OpMemberDecorate %127 2 Offset 80
+               OpDecorate %127 Block
+               OpDecorate %129 DescriptorSet 0
+               OpDecorate %129 Binding 0
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+         %10 = OpTypeInt 32 0
+         %11 = OpTypePointer Function %10
+         %13 = OpTypeVector %10 3
+         %14 = OpTypePointer Input %13
+         %15 = OpVariable %14 Input
+         %16 = OpConstant %10 0
+         %17 = OpTypePointer Input %10
+         %21 = OpConstant %10 1
+         %24 = OpTypeInt 32 1
+         %25 = OpTypePointer Function %24
+         %27 = OpConstant %24 0
+         %34 = OpConstant %24 2
+         %35 = OpTypeBool
+         %37 = OpTypeVector %10 4
+         %38 = OpTypeFloat 32
+         %39 = OpTypeVector %38 3
+         %40 = OpTypeStruct %37 %39 %24
+         %41 = OpTypePointer Uniform %40
+         %42 = OpVariable %41 Uniform
+         %46 = OpTypeVector %10 2
+         %48 = OpTypePointer Uniform %37
+         %53 = OpTypePointer Uniform %10
+         %59 = OpConstant %24 1
+         %61 = OpTypeImage %24 2D 0 0 0 2 R32i
+         %62 = OpTypePointer UniformConstant %61
+         %63 = OpVariable %62 UniformConstant
+         %69 = OpTypeVector %24 2
+         %71 = OpTypeVector %24 4
+         %74 = OpTypePointer Uniform %24
+         %76 = OpConstant %10 2
+         %77 = OpConstant %10 3400
+         %78 = OpConstant %10 264
+         %79 = OpVariable %62 UniformConstant
+         %96 = OpConstant %24 3
+        %103 = OpConstantComposite %69 %27 %27
+        %107 = OpTypePointer Uniform %38
+        %110 = OpVariable %14 Input
+        %113 = OpTypeVector %38 2
+        %125 = OpTypeVector %38 4
+        %126 = OpTypeMatrix %125 4
+        %127 = OpTypeStruct %10 %126 %38
+        %128 = OpTypePointer Uniform %127
+        %129 = OpVariable %128 Uniform
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+        %123 = OpFunctionCall %2 %8
+        %124 = OpFunctionCall %2 %6
+               OpReturn
+               OpFunctionEnd
+          %6 = OpFunction %2 None %3
+          %7 = OpLabel
+         %12 = OpVariable %11 Function
+         %20 = OpVariable %11 Function
+         %26 = OpVariable %25 Function
+         %18 = OpAccessChain %17 %15 %16
+         %19 = OpLoad %10 %18
+               OpStore %12 %19
+         %22 = OpAccessChain %17 %15 %21
+         %23 = OpLoad %10 %22
+               OpStore %20 %23
+               OpStore %26 %27
+               OpBranch %28
+         %28 = OpLabel
+               OpLoopMerge %30 %31 None
+               OpBranch %32
+         %32 = OpLabel
+         %33 = OpLoad %24 %26
+         %36 = OpSLessThan %35 %33 %34
+               OpBranchConditional %36 %29 %30
+         %29 = OpLabel
+         %43 = OpLoad %10 %12
+         %44 = OpLoad %10 %20
+         %45 = OpIAdd %10 %43 %44
+         %47 = OpCompositeConstruct %46 %45 %45
+         %49 = OpAccessChain %48 %42 %27
+         %50 = OpLoad %37 %49
+         %51 = OpVectorShuffle %46 %50 %50 0 1
+         %52 = OpIAdd %46 %51 %47
+         %54 = OpAccessChain %53 %42 %27 %16
+         %55 = OpCompositeExtract %10 %52 0
+               OpStore %54 %55
+         %56 = OpAccessChain %53 %42 %27 %21
+         %57 = OpCompositeExtract %10 %52 1
+               OpStore %56 %57
+               OpBranch %31
+         %31 = OpLabel
+         %58 = OpLoad %24 %26
+         %60 = OpIAdd %24 %58 %59
+               OpStore %26 %60
+               OpBranch %28
+         %30 = OpLabel
+         %64 = OpLoad %61 %63
+         %65 = OpLoad %10 %12
+         %66 = OpBitcast %24 %65
+         %67 = OpLoad %10 %20
+         %68 = OpBitcast %24 %67
+         %70 = OpCompositeConstruct %69 %66 %68
+         %72 = OpImageRead %71 %64 %70
+         %73 = OpCompositeExtract %24 %72 1
+         %75 = OpAccessChain %74 %42 %34
+               OpStore %75 %73
+               OpMemoryBarrier %76 %77
+               OpControlBarrier %76 %76 %78
+         %80 = OpLoad %61 %79
+         %81 = OpLoad %10 %20
+         %82 = OpBitcast %24 %81
+         %83 = OpLoad %10 %12
+         %84 = OpBitcast %24 %83
+         %85 = OpCompositeConstruct %69 %82 %84
+         %86 = OpAccessChain %74 %42 %34
+         %87 = OpLoad %24 %86
+         %88 = OpCompositeConstruct %71 %87 %27 %27 %27
+               OpImageWrite %80 %85 %88
+               OpReturn
+               OpFunctionEnd
+          %8 = OpFunction %2 None %3
+          %9 = OpLabel
+         %89 = OpVariable %25 Function
+               OpStore %89 %27
+               OpBranch %90
+         %90 = OpLabel
+               OpLoopMerge %92 %93 None
+               OpBranch %94
+         %94 = OpLabel
+         %95 = OpLoad %24 %89
+         %97 = OpSLessThan %35 %95 %96
+               OpBranchConditional %97 %91 %92
+         %91 = OpLabel
+         %98 = OpLoad %24 %89
+         %99 = OpIEqual %35 %98 %27
+               OpSelectionMerge %101 None
+               OpBranchConditional %99 %100 %109
+        %100 = OpLabel
+        %102 = OpLoad %61 %63
+        %104 = OpImageRead %71 %102 %103
+        %105 = OpCompositeExtract %24 %104 0
+        %106 = OpConvertSToF %38 %105
+        %108 = OpAccessChain %107 %42 %59 %16
+               OpStore %108 %106
+               OpBranch %101
+        %109 = OpLabel
+        %111 = OpLoad %13 %110
+        %112 = OpConvertUToF %39 %111
+        %114 = OpCompositeExtract %38 %112 0
+        %115 = OpCompositeExtract %38 %112 1
+        %116 = OpCompositeConstruct %113 %114 %115
+        %117 = OpAccessChain %107 %42 %59 %21
+        %118 = OpCompositeExtract %38 %116 0
+               OpStore %117 %118
+        %119 = OpAccessChain %107 %42 %59 %76
+        %120 = OpCompositeExtract %38 %116 1
+               OpStore %119 %120
+               OpBranch %101
+        %101 = OpLabel
+               OpBranch %93
+         %93 = OpLabel
+        %121 = OpLoad %24 %89
+        %122 = OpIAdd %24 %121 %59
+               OpStore %89 %122
+               OpBranch %90
+         %92 = OpLabel
+               OpReturn
+               OpFunctionEnd
+

+ 230 - 0
ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/large_functions_large_diffs_src.spvasm

@@ -0,0 +1,230 @@
+;; Test where src and dst have a few large functions with large differences.
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %4 "main" %15
+               OpExecutionMode %4 LocalSize 1 1 1
+               OpSource ESSL 310
+               OpName %4 "main"
+               OpName %6 "f1("
+               OpName %8 "f2("
+               OpName %12 "x"
+               OpName %15 "gl_LocalInvocationID"
+               OpName %20 "y"
+               OpName %27 "image"
+               OpName %44 "sum"
+               OpName %46 "i"
+               OpName %56 "j"
+               OpName %80 "BufferOut"
+               OpMemberName %80 0 "o_uv4"
+               OpMemberName %80 1 "o_v3"
+               OpMemberName %80 2 "o_i"
+               OpName %82 ""
+               OpName %88 "BufferIn"
+               OpMemberName %88 0 "i_u"
+               OpMemberName %88 1 "i_v4"
+               OpMemberName %88 2 "i_f"
+               OpName %90 ""
+               OpName %101 "i"
+               OpName %128 "image2"
+               OpDecorate %15 BuiltIn LocalInvocationId
+               OpDecorate %27 DescriptorSet 0
+               OpDecorate %27 Binding 2
+               OpMemberDecorate %80 0 Offset 0
+               OpMemberDecorate %80 1 Offset 16
+               OpMemberDecorate %80 2 Offset 28
+               OpDecorate %80 BufferBlock
+               OpDecorate %82 DescriptorSet 0
+               OpDecorate %82 Binding 1
+               OpMemberDecorate %88 0 Offset 0
+               OpMemberDecorate %88 1 RowMajor
+               OpMemberDecorate %88 1 Offset 16
+               OpMemberDecorate %88 1 MatrixStride 16
+               OpMemberDecorate %88 2 Offset 80
+               OpDecorate %88 Block
+               OpDecorate %90 DescriptorSet 0
+               OpDecorate %90 Binding 0
+               OpDecorate %128 DescriptorSet 0
+               OpDecorate %128 Binding 3
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+         %10 = OpTypeInt 32 0
+         %11 = OpTypePointer Function %10
+         %13 = OpTypeVector %10 3
+         %14 = OpTypePointer Input %13
+         %15 = OpVariable %14 Input
+         %16 = OpConstant %10 0
+         %17 = OpTypePointer Input %10
+         %21 = OpConstant %10 1
+         %24 = OpTypeInt 32 1
+         %25 = OpTypeImage %24 2D 0 0 0 2 R32i
+         %26 = OpTypePointer UniformConstant %25
+         %27 = OpVariable %26 UniformConstant
+         %29 = OpTypeVector %10 2
+         %32 = OpTypeVector %24 2
+         %38 = OpTypeVector %24 4
+         %40 = OpConstant %10 2
+         %41 = OpConstant %10 3400
+         %42 = OpConstant %10 264
+         %43 = OpTypePointer Function %24
+         %45 = OpConstant %24 0
+         %53 = OpConstant %24 2
+         %54 = OpTypeBool
+         %73 = OpConstant %24 1
+         %77 = OpTypeVector %10 4
+         %78 = OpTypeFloat 32
+         %79 = OpTypeVector %78 3
+         %80 = OpTypeStruct %77 %79 %24
+         %81 = OpTypePointer Uniform %80
+         %82 = OpVariable %81 Uniform
+         %84 = OpTypePointer Uniform %24
+         %86 = OpTypeVector %78 4
+         %87 = OpTypeMatrix %86 4
+         %88 = OpTypeStruct %10 %87 %78
+         %89 = OpTypePointer Uniform %88
+         %90 = OpVariable %89 Uniform
+         %91 = OpTypePointer Uniform %87
+         %94 = OpTypePointer Uniform %77
+        %108 = OpConstant %24 3
+        %110 = OpTypePointer Uniform %79
+        %113 = OpTypePointer Uniform %78
+        %128 = OpVariable %26 UniformConstant
+        %130 = OpConstantComposite %32 %45 %45
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+        %136 = OpFunctionCall %2 %6
+        %137 = OpFunctionCall %2 %8
+               OpReturn
+               OpFunctionEnd
+          %6 = OpFunction %2 None %3
+          %7 = OpLabel
+         %12 = OpVariable %11 Function
+         %20 = OpVariable %11 Function
+         %44 = OpVariable %43 Function
+         %46 = OpVariable %43 Function
+         %56 = OpVariable %43 Function
+         %18 = OpAccessChain %17 %15 %16
+         %19 = OpLoad %10 %18
+               OpStore %12 %19
+         %22 = OpAccessChain %17 %15 %21
+         %23 = OpLoad %10 %22
+               OpStore %20 %23
+         %28 = OpLoad %25 %27
+         %30 = OpLoad %13 %15
+         %31 = OpVectorShuffle %29 %30 %30 0 1
+         %33 = OpBitcast %32 %31
+         %34 = OpLoad %10 %12
+         %35 = OpLoad %10 %20
+         %36 = OpIAdd %10 %34 %35
+         %37 = OpBitcast %24 %36
+         %39 = OpCompositeConstruct %38 %37 %37 %37 %37
+               OpImageWrite %28 %33 %39
+               OpMemoryBarrier %40 %41
+               OpControlBarrier %40 %40 %42
+               OpStore %44 %45
+               OpStore %46 %45
+               OpBranch %47
+         %47 = OpLabel
+               OpLoopMerge %49 %50 None
+               OpBranch %51
+         %51 = OpLabel
+         %52 = OpLoad %24 %46
+         %55 = OpSLessThan %54 %52 %53
+               OpBranchConditional %55 %48 %49
+         %48 = OpLabel
+               OpStore %56 %45
+               OpBranch %57
+         %57 = OpLabel
+               OpLoopMerge %59 %60 None
+               OpBranch %61
+         %61 = OpLabel
+         %62 = OpLoad %24 %56
+         %63 = OpSLessThan %54 %62 %53
+               OpBranchConditional %63 %58 %59
+         %58 = OpLabel
+         %64 = OpLoad %25 %27
+         %65 = OpLoad %24 %46
+         %66 = OpLoad %24 %56
+         %67 = OpCompositeConstruct %32 %65 %66
+         %68 = OpImageRead %38 %64 %67
+         %69 = OpCompositeExtract %24 %68 0
+         %70 = OpLoad %24 %44
+         %71 = OpIMul %24 %70 %69
+               OpStore %44 %71
+               OpBranch %60
+         %60 = OpLabel
+         %72 = OpLoad %24 %56
+         %74 = OpIAdd %24 %72 %73
+               OpStore %56 %74
+               OpBranch %57
+         %59 = OpLabel
+               OpBranch %50
+         %50 = OpLabel
+         %75 = OpLoad %24 %46
+         %76 = OpIAdd %24 %75 %73
+               OpStore %46 %76
+               OpBranch %47
+         %49 = OpLabel
+               OpMemoryBarrier %40 %41
+               OpControlBarrier %40 %40 %42
+         %83 = OpLoad %24 %44
+         %85 = OpAccessChain %84 %82 %53
+               OpStore %85 %83
+               OpReturn
+               OpFunctionEnd
+          %8 = OpFunction %2 None %3
+          %9 = OpLabel
+        %101 = OpVariable %43 Function
+         %92 = OpAccessChain %91 %90 %73
+         %93 = OpLoad %87 %92
+         %95 = OpAccessChain %94 %82 %45
+         %96 = OpLoad %77 %95
+         %97 = OpConvertUToF %86 %96
+         %98 = OpMatrixTimesVector %86 %93 %97
+         %99 = OpConvertFToU %77 %98
+        %100 = OpAccessChain %94 %82 %45
+               OpStore %100 %99
+               OpStore %101 %45
+               OpBranch %102
+        %102 = OpLabel
+               OpLoopMerge %104 %105 None
+               OpBranch %106
+        %106 = OpLabel
+        %107 = OpLoad %24 %101
+        %109 = OpSLessThan %54 %107 %108
+               OpBranchConditional %109 %103 %104
+        %103 = OpLabel
+        %111 = OpAccessChain %110 %82 %73
+        %112 = OpLoad %79 %111
+        %114 = OpAccessChain %113 %90 %53
+        %115 = OpLoad %78 %114
+        %116 = OpVectorTimesScalar %79 %112 %115
+        %117 = OpConvertFToU %13 %116
+        %118 = OpCompositeExtract %10 %117 0
+        %119 = OpCompositeExtract %10 %117 1
+        %120 = OpCompositeExtract %10 %117 2
+        %121 = OpCompositeConstruct %77 %118 %119 %120 %16
+        %122 = OpAccessChain %94 %82 %45
+        %123 = OpLoad %77 %122
+        %124 = OpIAdd %77 %123 %121
+        %125 = OpAccessChain %94 %82 %45
+               OpStore %125 %124
+               OpBranch %105
+        %105 = OpLabel
+        %126 = OpLoad %24 %101
+        %127 = OpIAdd %24 %126 %73
+               OpStore %101 %127
+               OpBranch %102
+        %104 = OpLabel
+               OpMemoryBarrier %40 %41
+               OpControlBarrier %40 %40 %42
+        %129 = OpLoad %25 %128
+        %131 = OpImageRead %38 %129 %130
+        %132 = OpCompositeExtract %24 %131 0
+        %133 = OpConvertSToF %78 %132
+        %134 = OpCompositeConstruct %79 %133 %133 %133
+        %135 = OpAccessChain %110 %82 %73
+               OpStore %135 %134
+               OpReturn
+               OpFunctionEnd
+

+ 1364 - 0
ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/large_functions_small_diffs_autogen.cpp

@@ -0,0 +1,1364 @@
+// GENERATED FILE - DO NOT EDIT.
+// Generated by generate_tests.py
+//
+// 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 "../diff_test_utils.h"
+
+#include "gtest/gtest.h"
+
+namespace spvtools {
+namespace diff {
+namespace {
+
+// Test where src and dst have a few large functions with small differences.
+constexpr char kSrc[] = R"(               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %4 "main" %15
+               OpExecutionMode %4 LocalSize 1 1 1
+               OpSource ESSL 310
+               OpName %4 "main"
+               OpName %6 "f1("
+               OpName %8 "f2("
+               OpName %12 "x"
+               OpName %15 "gl_LocalInvocationID"
+               OpName %20 "y"
+               OpName %27 "image"
+               OpName %44 "sum"
+               OpName %46 "i"
+               OpName %56 "j"
+               OpName %80 "BufferOut"
+               OpMemberName %80 0 "o_uv4"
+               OpMemberName %80 1 "o_v3"
+               OpMemberName %80 2 "o_i"
+               OpName %82 ""
+               OpName %88 "BufferIn"
+               OpMemberName %88 0 "i_u"
+               OpMemberName %88 1 "i_v4"
+               OpMemberName %88 2 "i_f"
+               OpName %90 ""
+               OpName %101 "i"
+               OpDecorate %15 BuiltIn LocalInvocationId
+               OpDecorate %27 DescriptorSet 0
+               OpDecorate %27 Binding 2
+               OpMemberDecorate %80 0 Offset 0
+               OpMemberDecorate %80 1 Offset 16
+               OpMemberDecorate %80 2 Offset 28
+               OpDecorate %80 BufferBlock
+               OpDecorate %82 DescriptorSet 0
+               OpDecorate %82 Binding 1
+               OpMemberDecorate %88 0 Offset 0
+               OpMemberDecorate %88 1 RowMajor
+               OpMemberDecorate %88 1 Offset 16
+               OpMemberDecorate %88 1 MatrixStride 16
+               OpMemberDecorate %88 2 Offset 80
+               OpDecorate %88 Block
+               OpDecorate %90 DescriptorSet 0
+               OpDecorate %90 Binding 0
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+         %10 = OpTypeInt 32 0
+         %11 = OpTypePointer Function %10
+         %13 = OpTypeVector %10 3
+         %14 = OpTypePointer Input %13
+         %15 = OpVariable %14 Input
+         %16 = OpConstant %10 0
+         %17 = OpTypePointer Input %10
+         %21 = OpConstant %10 1
+         %24 = OpTypeInt 32 1
+         %25 = OpTypeImage %24 2D 0 0 0 2 R32i
+         %26 = OpTypePointer UniformConstant %25
+         %27 = OpVariable %26 UniformConstant
+         %29 = OpTypeVector %10 2
+         %32 = OpTypeVector %24 2
+         %38 = OpTypeVector %24 4
+         %40 = OpConstant %10 2
+         %41 = OpConstant %10 3400
+         %42 = OpConstant %10 264
+         %43 = OpTypePointer Function %24
+         %45 = OpConstant %24 0
+         %53 = OpConstant %24 2
+         %54 = OpTypeBool
+         %73 = OpConstant %24 1
+         %77 = OpTypeVector %10 4
+         %78 = OpTypeFloat 32
+         %79 = OpTypeVector %78 3
+         %80 = OpTypeStruct %77 %79 %24
+         %81 = OpTypePointer Uniform %80
+         %82 = OpVariable %81 Uniform
+         %84 = OpTypePointer Uniform %24
+         %86 = OpTypeVector %78 4
+         %87 = OpTypeMatrix %86 4
+         %88 = OpTypeStruct %10 %87 %78
+         %89 = OpTypePointer Uniform %88
+         %90 = OpVariable %89 Uniform
+         %91 = OpTypePointer Uniform %87
+         %94 = OpTypePointer Uniform %77
+        %108 = OpConstant %24 3
+        %110 = OpTypePointer Uniform %79
+        %113 = OpTypePointer Uniform %78
+        %129 = OpConstantComposite %32 %45 %45
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+        %135 = OpFunctionCall %2 %6
+        %136 = OpFunctionCall %2 %8
+               OpReturn
+               OpFunctionEnd
+          %6 = OpFunction %2 None %3
+          %7 = OpLabel
+         %12 = OpVariable %11 Function
+         %20 = OpVariable %11 Function
+         %44 = OpVariable %43 Function
+         %46 = OpVariable %43 Function
+         %56 = OpVariable %43 Function
+         %18 = OpAccessChain %17 %15 %16
+         %19 = OpLoad %10 %18
+               OpStore %12 %19
+         %22 = OpAccessChain %17 %15 %21
+         %23 = OpLoad %10 %22
+               OpStore %20 %23
+         %28 = OpLoad %25 %27
+         %30 = OpLoad %13 %15
+         %31 = OpVectorShuffle %29 %30 %30 0 1
+         %33 = OpBitcast %32 %31
+         %34 = OpLoad %10 %12
+         %35 = OpLoad %10 %20
+         %36 = OpIAdd %10 %34 %35
+         %37 = OpBitcast %24 %36
+         %39 = OpCompositeConstruct %38 %37 %37 %37 %37
+               OpImageWrite %28 %33 %39
+               OpMemoryBarrier %40 %41
+               OpControlBarrier %40 %40 %42
+               OpStore %44 %45
+               OpStore %46 %45
+               OpBranch %47
+         %47 = OpLabel
+               OpLoopMerge %49 %50 None
+               OpBranch %51
+         %51 = OpLabel
+         %52 = OpLoad %24 %46
+         %55 = OpSLessThan %54 %52 %53
+               OpBranchConditional %55 %48 %49
+         %48 = OpLabel
+               OpStore %56 %45
+               OpBranch %57
+         %57 = OpLabel
+               OpLoopMerge %59 %60 None
+               OpBranch %61
+         %61 = OpLabel
+         %62 = OpLoad %24 %56
+         %63 = OpSLessThan %54 %62 %53
+               OpBranchConditional %63 %58 %59
+         %58 = OpLabel
+         %64 = OpLoad %25 %27
+         %65 = OpLoad %24 %46
+         %66 = OpLoad %24 %56
+         %67 = OpCompositeConstruct %32 %65 %66
+         %68 = OpImageRead %38 %64 %67
+         %69 = OpCompositeExtract %24 %68 0
+         %70 = OpLoad %24 %44
+         %71 = OpIAdd %24 %70 %69
+               OpStore %44 %71
+               OpBranch %60
+         %60 = OpLabel
+         %72 = OpLoad %24 %56
+         %74 = OpIAdd %24 %72 %73
+               OpStore %56 %74
+               OpBranch %57
+         %59 = OpLabel
+               OpBranch %50
+         %50 = OpLabel
+         %75 = OpLoad %24 %46
+         %76 = OpIAdd %24 %75 %73
+               OpStore %46 %76
+               OpBranch %47
+         %49 = OpLabel
+               OpMemoryBarrier %40 %41
+               OpControlBarrier %40 %40 %42
+         %83 = OpLoad %24 %44
+         %85 = OpAccessChain %84 %82 %53
+               OpStore %85 %83
+               OpReturn
+               OpFunctionEnd
+          %8 = OpFunction %2 None %3
+          %9 = OpLabel
+        %101 = OpVariable %43 Function
+         %92 = OpAccessChain %91 %90 %73
+         %93 = OpLoad %87 %92
+         %95 = OpAccessChain %94 %82 %45
+         %96 = OpLoad %77 %95
+         %97 = OpConvertUToF %86 %96
+         %98 = OpMatrixTimesVector %86 %93 %97
+         %99 = OpConvertFToU %77 %98
+        %100 = OpAccessChain %94 %82 %45
+               OpStore %100 %99
+               OpStore %101 %45
+               OpBranch %102
+        %102 = OpLabel
+               OpLoopMerge %104 %105 None
+               OpBranch %106
+        %106 = OpLabel
+        %107 = OpLoad %24 %101
+        %109 = OpSLessThan %54 %107 %108
+               OpBranchConditional %109 %103 %104
+        %103 = OpLabel
+        %111 = OpAccessChain %110 %82 %73
+        %112 = OpLoad %79 %111
+        %114 = OpAccessChain %113 %90 %53
+        %115 = OpLoad %78 %114
+        %116 = OpVectorTimesScalar %79 %112 %115
+        %117 = OpConvertFToU %13 %116
+        %118 = OpCompositeExtract %10 %117 0
+        %119 = OpCompositeExtract %10 %117 1
+        %120 = OpCompositeExtract %10 %117 2
+        %121 = OpCompositeConstruct %77 %118 %119 %120 %16
+        %122 = OpAccessChain %94 %82 %45
+        %123 = OpLoad %77 %122
+        %124 = OpIAdd %77 %123 %121
+        %125 = OpAccessChain %94 %82 %45
+               OpStore %125 %124
+               OpBranch %105
+        %105 = OpLabel
+        %126 = OpLoad %24 %101
+        %127 = OpIAdd %24 %126 %73
+               OpStore %101 %127
+               OpBranch %102
+        %104 = OpLabel
+               OpMemoryBarrier %40 %41
+               OpControlBarrier %40 %40 %42
+        %128 = OpLoad %25 %27
+        %130 = OpImageRead %38 %128 %129
+        %131 = OpCompositeExtract %24 %130 0
+        %132 = OpConvertSToF %78 %131
+        %133 = OpCompositeConstruct %79 %132 %132 %132
+        %134 = OpAccessChain %110 %82 %73
+               OpStore %134 %133
+               OpReturn
+               OpFunctionEnd
+)";
+constexpr char kDst[] = R"(               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %4 "main" %15
+               OpExecutionMode %4 LocalSize 1 1 1
+               OpSource ESSL 310
+               OpName %4 "main"
+               OpName %6 "f1("
+               OpName %8 "f2("
+               OpName %12 "x"
+               OpName %15 "gl_LocalInvocationID"
+               OpName %20 "y"
+               OpName %27 "image"
+               OpName %44 "sum"
+               OpName %46 "i"
+               OpName %56 "j"
+               OpName %80 "BufferOut"
+               OpMemberName %80 0 "o_uv4"
+               OpMemberName %80 1 "o_v3"
+               OpMemberName %80 2 "o_i"
+               OpName %82 ""
+               OpName %88 "BufferIn"
+               OpMemberName %88 0 "i_u"
+               OpMemberName %88 1 "i_v4"
+               OpMemberName %88 2 "i_f"
+               OpName %90 ""
+               OpName %101 "i"
+               OpName %128 "image2"
+               OpDecorate %15 BuiltIn LocalInvocationId
+               OpDecorate %27 DescriptorSet 0
+               OpDecorate %27 Binding 2
+               OpMemberDecorate %80 0 Offset 0
+               OpMemberDecorate %80 1 Offset 16
+               OpMemberDecorate %80 2 Offset 28
+               OpDecorate %80 BufferBlock
+               OpDecorate %82 DescriptorSet 0
+               OpDecorate %82 Binding 1
+               OpMemberDecorate %88 0 Offset 0
+               OpMemberDecorate %88 1 RowMajor
+               OpMemberDecorate %88 1 Offset 16
+               OpMemberDecorate %88 1 MatrixStride 16
+               OpMemberDecorate %88 2 Offset 80
+               OpDecorate %88 Block
+               OpDecorate %90 DescriptorSet 0
+               OpDecorate %90 Binding 0
+               OpDecorate %128 DescriptorSet 0
+               OpDecorate %128 Binding 3
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+         %10 = OpTypeInt 32 0
+         %11 = OpTypePointer Function %10
+         %13 = OpTypeVector %10 3
+         %14 = OpTypePointer Input %13
+         %15 = OpVariable %14 Input
+         %16 = OpConstant %10 0
+         %17 = OpTypePointer Input %10
+         %21 = OpConstant %10 1
+         %24 = OpTypeInt 32 1
+         %25 = OpTypeImage %24 2D 0 0 0 2 R32i
+         %26 = OpTypePointer UniformConstant %25
+         %27 = OpVariable %26 UniformConstant
+         %29 = OpTypeVector %10 2
+         %32 = OpTypeVector %24 2
+         %38 = OpTypeVector %24 4
+         %40 = OpConstant %10 2
+         %41 = OpConstant %10 3400
+         %42 = OpConstant %10 264
+         %43 = OpTypePointer Function %24
+         %45 = OpConstant %24 0
+         %53 = OpConstant %24 2
+         %54 = OpTypeBool
+         %73 = OpConstant %24 1
+         %77 = OpTypeVector %10 4
+         %78 = OpTypeFloat 32
+         %79 = OpTypeVector %78 3
+         %80 = OpTypeStruct %77 %79 %24
+         %81 = OpTypePointer Uniform %80
+         %82 = OpVariable %81 Uniform
+         %84 = OpTypePointer Uniform %24
+         %86 = OpTypeVector %78 4
+         %87 = OpTypeMatrix %86 4
+         %88 = OpTypeStruct %10 %87 %78
+         %89 = OpTypePointer Uniform %88
+         %90 = OpVariable %89 Uniform
+         %91 = OpTypePointer Uniform %87
+         %94 = OpTypePointer Uniform %77
+        %108 = OpConstant %24 3
+        %110 = OpTypePointer Uniform %79
+        %113 = OpTypePointer Uniform %78
+        %128 = OpVariable %26 UniformConstant
+        %130 = OpConstantComposite %32 %45 %45
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+        %136 = OpFunctionCall %2 %6
+        %137 = OpFunctionCall %2 %8
+               OpReturn
+               OpFunctionEnd
+          %6 = OpFunction %2 None %3
+          %7 = OpLabel
+         %12 = OpVariable %11 Function
+         %20 = OpVariable %11 Function
+         %44 = OpVariable %43 Function
+         %46 = OpVariable %43 Function
+         %56 = OpVariable %43 Function
+         %18 = OpAccessChain %17 %15 %16
+         %19 = OpLoad %10 %18
+               OpStore %12 %19
+         %22 = OpAccessChain %17 %15 %21
+         %23 = OpLoad %10 %22
+               OpStore %20 %23
+         %28 = OpLoad %25 %27
+         %30 = OpLoad %13 %15
+         %31 = OpVectorShuffle %29 %30 %30 0 1
+         %33 = OpBitcast %32 %31
+         %34 = OpLoad %10 %12
+         %35 = OpLoad %10 %20
+         %36 = OpIAdd %10 %34 %35
+         %37 = OpBitcast %24 %36
+         %39 = OpCompositeConstruct %38 %37 %37 %37 %37
+               OpImageWrite %28 %33 %39
+               OpMemoryBarrier %40 %41
+               OpControlBarrier %40 %40 %42
+               OpStore %44 %45
+               OpStore %46 %45
+               OpBranch %47
+         %47 = OpLabel
+               OpLoopMerge %49 %50 None
+               OpBranch %51
+         %51 = OpLabel
+         %52 = OpLoad %24 %46
+         %55 = OpSLessThan %54 %52 %53
+               OpBranchConditional %55 %48 %49
+         %48 = OpLabel
+               OpStore %56 %45
+               OpBranch %57
+         %57 = OpLabel
+               OpLoopMerge %59 %60 None
+               OpBranch %61
+         %61 = OpLabel
+         %62 = OpLoad %24 %56
+         %63 = OpSLessThan %54 %62 %53
+               OpBranchConditional %63 %58 %59
+         %58 = OpLabel
+         %64 = OpLoad %25 %27
+         %65 = OpLoad %24 %46
+         %66 = OpLoad %24 %56
+         %67 = OpCompositeConstruct %32 %65 %66
+         %68 = OpImageRead %38 %64 %67
+         %69 = OpCompositeExtract %24 %68 0
+         %70 = OpLoad %24 %44
+         %71 = OpIMul %24 %70 %69
+               OpStore %44 %71
+               OpBranch %60
+         %60 = OpLabel
+         %72 = OpLoad %24 %56
+         %74 = OpIAdd %24 %72 %73
+               OpStore %56 %74
+               OpBranch %57
+         %59 = OpLabel
+               OpBranch %50
+         %50 = OpLabel
+         %75 = OpLoad %24 %46
+         %76 = OpIAdd %24 %75 %73
+               OpStore %46 %76
+               OpBranch %47
+         %49 = OpLabel
+               OpMemoryBarrier %40 %41
+               OpControlBarrier %40 %40 %42
+         %83 = OpLoad %24 %44
+         %85 = OpAccessChain %84 %82 %53
+               OpStore %85 %83
+               OpReturn
+               OpFunctionEnd
+          %8 = OpFunction %2 None %3
+          %9 = OpLabel
+        %101 = OpVariable %43 Function
+         %92 = OpAccessChain %91 %90 %73
+         %93 = OpLoad %87 %92
+         %95 = OpAccessChain %94 %82 %45
+         %96 = OpLoad %77 %95
+         %97 = OpConvertUToF %86 %96
+         %98 = OpMatrixTimesVector %86 %93 %97
+         %99 = OpConvertFToU %77 %98
+        %100 = OpAccessChain %94 %82 %45
+               OpStore %100 %99
+               OpStore %101 %45
+               OpBranch %102
+        %102 = OpLabel
+               OpLoopMerge %104 %105 None
+               OpBranch %106
+        %106 = OpLabel
+        %107 = OpLoad %24 %101
+        %109 = OpSLessThan %54 %107 %108
+               OpBranchConditional %109 %103 %104
+        %103 = OpLabel
+        %111 = OpAccessChain %110 %82 %73
+        %112 = OpLoad %79 %111
+        %114 = OpAccessChain %113 %90 %53
+        %115 = OpLoad %78 %114
+        %116 = OpVectorTimesScalar %79 %112 %115
+        %117 = OpConvertFToU %13 %116
+        %118 = OpCompositeExtract %10 %117 0
+        %119 = OpCompositeExtract %10 %117 1
+        %120 = OpCompositeExtract %10 %117 2
+        %121 = OpCompositeConstruct %77 %118 %119 %120 %16
+        %122 = OpAccessChain %94 %82 %45
+        %123 = OpLoad %77 %122
+        %124 = OpIAdd %77 %123 %121
+        %125 = OpAccessChain %94 %82 %45
+               OpStore %125 %124
+               OpBranch %105
+        %105 = OpLabel
+        %126 = OpLoad %24 %101
+        %127 = OpIAdd %24 %126 %73
+               OpStore %101 %127
+               OpBranch %102
+        %104 = OpLabel
+               OpMemoryBarrier %40 %41
+               OpControlBarrier %40 %40 %42
+        %129 = OpLoad %25 %128
+        %131 = OpImageRead %38 %129 %130
+        %132 = OpCompositeExtract %24 %131 0
+        %133 = OpConvertSToF %78 %132
+        %134 = OpCompositeConstruct %79 %133 %133 %133
+        %135 = OpAccessChain %110 %82 %73
+               OpStore %135 %134
+               OpReturn
+               OpFunctionEnd
+
+)";
+
+TEST(DiffTest, LargeFunctionsSmallDiffs) {
+  constexpr char kDiff[] = R"( ; SPIR-V
+ ; Version: 1.6
+ ; Generator: Khronos SPIR-V Tools Assembler; 0
+-; Bound: 137
++; Bound: 140
+ ; Schema: 0
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %4 "main" %15
+ OpExecutionMode %4 LocalSize 1 1 1
+ OpSource ESSL 310
+ OpName %4 "main"
+ OpName %6 "f1("
+ OpName %8 "f2("
+ OpName %12 "x"
+ OpName %15 "gl_LocalInvocationID"
+ OpName %20 "y"
+ OpName %27 "image"
+ OpName %44 "sum"
+ OpName %46 "i"
+ OpName %56 "j"
+ OpName %80 "BufferOut"
+ OpMemberName %80 0 "o_uv4"
+ OpMemberName %80 1 "o_v3"
+ OpMemberName %80 2 "o_i"
+ OpName %82 ""
+ OpName %88 "BufferIn"
+ OpMemberName %88 0 "i_u"
+ OpMemberName %88 1 "i_v4"
+ OpMemberName %88 2 "i_f"
+ OpName %90 ""
+ OpName %101 "i"
++OpName %138 "image2"
+ OpDecorate %15 BuiltIn LocalInvocationId
+ OpDecorate %27 DescriptorSet 0
+ OpDecorate %27 Binding 2
+ OpMemberDecorate %80 0 Offset 0
+ OpMemberDecorate %80 1 Offset 16
+ OpMemberDecorate %80 2 Offset 28
+ OpDecorate %80 BufferBlock
+ OpDecorate %82 DescriptorSet 0
+ OpDecorate %82 Binding 1
+ OpMemberDecorate %88 0 Offset 0
+ OpMemberDecorate %88 1 RowMajor
+ OpMemberDecorate %88 1 Offset 16
+ OpMemberDecorate %88 1 MatrixStride 16
+ OpMemberDecorate %88 2 Offset 80
+ OpDecorate %88 Block
+ OpDecorate %90 DescriptorSet 0
+ OpDecorate %90 Binding 0
++OpDecorate %138 DescriptorSet 0
++OpDecorate %138 Binding 3
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %10 = OpTypeInt 32 0
+ %11 = OpTypePointer Function %10
+ %13 = OpTypeVector %10 3
+ %14 = OpTypePointer Input %13
+ %15 = OpVariable %14 Input
+ %16 = OpConstant %10 0
+ %17 = OpTypePointer Input %10
+ %21 = OpConstant %10 1
+ %24 = OpTypeInt 32 1
+ %25 = OpTypeImage %24 2D 0 0 0 2 R32i
+ %26 = OpTypePointer UniformConstant %25
+ %27 = OpVariable %26 UniformConstant
+ %29 = OpTypeVector %10 2
+ %32 = OpTypeVector %24 2
+ %38 = OpTypeVector %24 4
+ %40 = OpConstant %10 2
+ %41 = OpConstant %10 3400
+ %42 = OpConstant %10 264
+ %43 = OpTypePointer Function %24
+ %45 = OpConstant %24 0
+ %53 = OpConstant %24 2
+ %54 = OpTypeBool
+ %73 = OpConstant %24 1
+ %77 = OpTypeVector %10 4
+ %78 = OpTypeFloat 32
+ %79 = OpTypeVector %78 3
+ %80 = OpTypeStruct %77 %79 %24
+ %81 = OpTypePointer Uniform %80
+ %82 = OpVariable %81 Uniform
+ %84 = OpTypePointer Uniform %24
+ %86 = OpTypeVector %78 4
+ %87 = OpTypeMatrix %86 4
+ %88 = OpTypeStruct %10 %87 %78
+ %89 = OpTypePointer Uniform %88
+ %90 = OpVariable %89 Uniform
+ %91 = OpTypePointer Uniform %87
+ %94 = OpTypePointer Uniform %77
+ %108 = OpConstant %24 3
+ %110 = OpTypePointer Uniform %79
+ %113 = OpTypePointer Uniform %78
++%138 = OpVariable %26 UniformConstant
+ %129 = OpConstantComposite %32 %45 %45
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ %135 = OpFunctionCall %2 %6
+ %136 = OpFunctionCall %2 %8
+ OpReturn
+ OpFunctionEnd
+ %6 = OpFunction %2 None %3
+ %7 = OpLabel
+ %12 = OpVariable %11 Function
+ %20 = OpVariable %11 Function
+ %44 = OpVariable %43 Function
+ %46 = OpVariable %43 Function
+ %56 = OpVariable %43 Function
+ %18 = OpAccessChain %17 %15 %16
+ %19 = OpLoad %10 %18
+ OpStore %12 %19
+ %22 = OpAccessChain %17 %15 %21
+ %23 = OpLoad %10 %22
+ OpStore %20 %23
+ %28 = OpLoad %25 %27
+ %30 = OpLoad %13 %15
+ %31 = OpVectorShuffle %29 %30 %30 0 1
+ %33 = OpBitcast %32 %31
+ %34 = OpLoad %10 %12
+ %35 = OpLoad %10 %20
+ %36 = OpIAdd %10 %34 %35
+ %37 = OpBitcast %24 %36
+ %39 = OpCompositeConstruct %38 %37 %37 %37 %37
+ OpImageWrite %28 %33 %39
+ OpMemoryBarrier %40 %41
+ OpControlBarrier %40 %40 %42
+ OpStore %44 %45
+ OpStore %46 %45
+ OpBranch %47
+ %47 = OpLabel
+ OpLoopMerge %49 %50 None
+ OpBranch %51
+ %51 = OpLabel
+ %52 = OpLoad %24 %46
+ %55 = OpSLessThan %54 %52 %53
+ OpBranchConditional %55 %48 %49
+ %48 = OpLabel
+ OpStore %56 %45
+ OpBranch %57
+ %57 = OpLabel
+ OpLoopMerge %59 %60 None
+ OpBranch %61
+ %61 = OpLabel
+ %62 = OpLoad %24 %56
+ %63 = OpSLessThan %54 %62 %53
+ OpBranchConditional %63 %58 %59
+ %58 = OpLabel
+ %64 = OpLoad %25 %27
+ %65 = OpLoad %24 %46
+ %66 = OpLoad %24 %56
+ %67 = OpCompositeConstruct %32 %65 %66
+ %68 = OpImageRead %38 %64 %67
+ %69 = OpCompositeExtract %24 %68 0
+ %70 = OpLoad %24 %44
+-%71 = OpIAdd %24 %70 %69
++%137 = OpIMul %24 %70 %69
+-OpStore %44 %71
++OpStore %44 %137
+ OpBranch %60
+ %60 = OpLabel
+ %72 = OpLoad %24 %56
+ %74 = OpIAdd %24 %72 %73
+ OpStore %56 %74
+ OpBranch %57
+ %59 = OpLabel
+ OpBranch %50
+ %50 = OpLabel
+ %75 = OpLoad %24 %46
+ %76 = OpIAdd %24 %75 %73
+ OpStore %46 %76
+ OpBranch %47
+ %49 = OpLabel
+ OpMemoryBarrier %40 %41
+ OpControlBarrier %40 %40 %42
+ %83 = OpLoad %24 %44
+ %85 = OpAccessChain %84 %82 %53
+ OpStore %85 %83
+ OpReturn
+ OpFunctionEnd
+ %8 = OpFunction %2 None %3
+ %9 = OpLabel
+ %101 = OpVariable %43 Function
+ %92 = OpAccessChain %91 %90 %73
+ %93 = OpLoad %87 %92
+ %95 = OpAccessChain %94 %82 %45
+ %96 = OpLoad %77 %95
+ %97 = OpConvertUToF %86 %96
+ %98 = OpMatrixTimesVector %86 %93 %97
+ %99 = OpConvertFToU %77 %98
+ %100 = OpAccessChain %94 %82 %45
+ OpStore %100 %99
+ OpStore %101 %45
+ OpBranch %102
+ %102 = OpLabel
+ OpLoopMerge %104 %105 None
+ OpBranch %106
+ %106 = OpLabel
+ %107 = OpLoad %24 %101
+ %109 = OpSLessThan %54 %107 %108
+ OpBranchConditional %109 %103 %104
+ %103 = OpLabel
+ %111 = OpAccessChain %110 %82 %73
+ %112 = OpLoad %79 %111
+ %114 = OpAccessChain %113 %90 %53
+ %115 = OpLoad %78 %114
+ %116 = OpVectorTimesScalar %79 %112 %115
+ %117 = OpConvertFToU %13 %116
+ %118 = OpCompositeExtract %10 %117 0
+ %119 = OpCompositeExtract %10 %117 1
+ %120 = OpCompositeExtract %10 %117 2
+ %121 = OpCompositeConstruct %77 %118 %119 %120 %16
+ %122 = OpAccessChain %94 %82 %45
+ %123 = OpLoad %77 %122
+ %124 = OpIAdd %77 %123 %121
+ %125 = OpAccessChain %94 %82 %45
+ OpStore %125 %124
+ OpBranch %105
+ %105 = OpLabel
+ %126 = OpLoad %24 %101
+ %127 = OpIAdd %24 %126 %73
+ OpStore %101 %127
+ OpBranch %102
+ %104 = OpLabel
+ OpMemoryBarrier %40 %41
+ OpControlBarrier %40 %40 %42
+-%128 = OpLoad %25 %27
++%139 = OpLoad %25 %138
+-%130 = OpImageRead %38 %128 %129
++%130 = OpImageRead %38 %139 %129
+ %131 = OpCompositeExtract %24 %130 0
+ %132 = OpConvertSToF %78 %131
+ %133 = OpCompositeConstruct %79 %132 %132 %132
+ %134 = OpAccessChain %110 %82 %73
+ OpStore %134 %133
+ OpReturn
+ OpFunctionEnd
+)";
+  Options options;
+  DoStringDiffTest(kSrc, kDst, kDiff, options);
+}
+
+TEST(DiffTest, LargeFunctionsSmallDiffsNoDebug) {
+  constexpr char kSrcNoDebug[] = R"(               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %4 "main" %15
+               OpExecutionMode %4 LocalSize 1 1 1
+               OpSource ESSL 310
+               OpDecorate %15 BuiltIn LocalInvocationId
+               OpDecorate %27 DescriptorSet 0
+               OpDecorate %27 Binding 2
+               OpMemberDecorate %80 0 Offset 0
+               OpMemberDecorate %80 1 Offset 16
+               OpMemberDecorate %80 2 Offset 28
+               OpDecorate %80 BufferBlock
+               OpDecorate %82 DescriptorSet 0
+               OpDecorate %82 Binding 1
+               OpMemberDecorate %88 0 Offset 0
+               OpMemberDecorate %88 1 RowMajor
+               OpMemberDecorate %88 1 Offset 16
+               OpMemberDecorate %88 1 MatrixStride 16
+               OpMemberDecorate %88 2 Offset 80
+               OpDecorate %88 Block
+               OpDecorate %90 DescriptorSet 0
+               OpDecorate %90 Binding 0
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+         %10 = OpTypeInt 32 0
+         %11 = OpTypePointer Function %10
+         %13 = OpTypeVector %10 3
+         %14 = OpTypePointer Input %13
+         %15 = OpVariable %14 Input
+         %16 = OpConstant %10 0
+         %17 = OpTypePointer Input %10
+         %21 = OpConstant %10 1
+         %24 = OpTypeInt 32 1
+         %25 = OpTypeImage %24 2D 0 0 0 2 R32i
+         %26 = OpTypePointer UniformConstant %25
+         %27 = OpVariable %26 UniformConstant
+         %29 = OpTypeVector %10 2
+         %32 = OpTypeVector %24 2
+         %38 = OpTypeVector %24 4
+         %40 = OpConstant %10 2
+         %41 = OpConstant %10 3400
+         %42 = OpConstant %10 264
+         %43 = OpTypePointer Function %24
+         %45 = OpConstant %24 0
+         %53 = OpConstant %24 2
+         %54 = OpTypeBool
+         %73 = OpConstant %24 1
+         %77 = OpTypeVector %10 4
+         %78 = OpTypeFloat 32
+         %79 = OpTypeVector %78 3
+         %80 = OpTypeStruct %77 %79 %24
+         %81 = OpTypePointer Uniform %80
+         %82 = OpVariable %81 Uniform
+         %84 = OpTypePointer Uniform %24
+         %86 = OpTypeVector %78 4
+         %87 = OpTypeMatrix %86 4
+         %88 = OpTypeStruct %10 %87 %78
+         %89 = OpTypePointer Uniform %88
+         %90 = OpVariable %89 Uniform
+         %91 = OpTypePointer Uniform %87
+         %94 = OpTypePointer Uniform %77
+        %108 = OpConstant %24 3
+        %110 = OpTypePointer Uniform %79
+        %113 = OpTypePointer Uniform %78
+        %129 = OpConstantComposite %32 %45 %45
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+        %135 = OpFunctionCall %2 %6
+        %136 = OpFunctionCall %2 %8
+               OpReturn
+               OpFunctionEnd
+          %6 = OpFunction %2 None %3
+          %7 = OpLabel
+         %12 = OpVariable %11 Function
+         %20 = OpVariable %11 Function
+         %44 = OpVariable %43 Function
+         %46 = OpVariable %43 Function
+         %56 = OpVariable %43 Function
+         %18 = OpAccessChain %17 %15 %16
+         %19 = OpLoad %10 %18
+               OpStore %12 %19
+         %22 = OpAccessChain %17 %15 %21
+         %23 = OpLoad %10 %22
+               OpStore %20 %23
+         %28 = OpLoad %25 %27
+         %30 = OpLoad %13 %15
+         %31 = OpVectorShuffle %29 %30 %30 0 1
+         %33 = OpBitcast %32 %31
+         %34 = OpLoad %10 %12
+         %35 = OpLoad %10 %20
+         %36 = OpIAdd %10 %34 %35
+         %37 = OpBitcast %24 %36
+         %39 = OpCompositeConstruct %38 %37 %37 %37 %37
+               OpImageWrite %28 %33 %39
+               OpMemoryBarrier %40 %41
+               OpControlBarrier %40 %40 %42
+               OpStore %44 %45
+               OpStore %46 %45
+               OpBranch %47
+         %47 = OpLabel
+               OpLoopMerge %49 %50 None
+               OpBranch %51
+         %51 = OpLabel
+         %52 = OpLoad %24 %46
+         %55 = OpSLessThan %54 %52 %53
+               OpBranchConditional %55 %48 %49
+         %48 = OpLabel
+               OpStore %56 %45
+               OpBranch %57
+         %57 = OpLabel
+               OpLoopMerge %59 %60 None
+               OpBranch %61
+         %61 = OpLabel
+         %62 = OpLoad %24 %56
+         %63 = OpSLessThan %54 %62 %53
+               OpBranchConditional %63 %58 %59
+         %58 = OpLabel
+         %64 = OpLoad %25 %27
+         %65 = OpLoad %24 %46
+         %66 = OpLoad %24 %56
+         %67 = OpCompositeConstruct %32 %65 %66
+         %68 = OpImageRead %38 %64 %67
+         %69 = OpCompositeExtract %24 %68 0
+         %70 = OpLoad %24 %44
+         %71 = OpIAdd %24 %70 %69
+               OpStore %44 %71
+               OpBranch %60
+         %60 = OpLabel
+         %72 = OpLoad %24 %56
+         %74 = OpIAdd %24 %72 %73
+               OpStore %56 %74
+               OpBranch %57
+         %59 = OpLabel
+               OpBranch %50
+         %50 = OpLabel
+         %75 = OpLoad %24 %46
+         %76 = OpIAdd %24 %75 %73
+               OpStore %46 %76
+               OpBranch %47
+         %49 = OpLabel
+               OpMemoryBarrier %40 %41
+               OpControlBarrier %40 %40 %42
+         %83 = OpLoad %24 %44
+         %85 = OpAccessChain %84 %82 %53
+               OpStore %85 %83
+               OpReturn
+               OpFunctionEnd
+          %8 = OpFunction %2 None %3
+          %9 = OpLabel
+        %101 = OpVariable %43 Function
+         %92 = OpAccessChain %91 %90 %73
+         %93 = OpLoad %87 %92
+         %95 = OpAccessChain %94 %82 %45
+         %96 = OpLoad %77 %95
+         %97 = OpConvertUToF %86 %96
+         %98 = OpMatrixTimesVector %86 %93 %97
+         %99 = OpConvertFToU %77 %98
+        %100 = OpAccessChain %94 %82 %45
+               OpStore %100 %99
+               OpStore %101 %45
+               OpBranch %102
+        %102 = OpLabel
+               OpLoopMerge %104 %105 None
+               OpBranch %106
+        %106 = OpLabel
+        %107 = OpLoad %24 %101
+        %109 = OpSLessThan %54 %107 %108
+               OpBranchConditional %109 %103 %104
+        %103 = OpLabel
+        %111 = OpAccessChain %110 %82 %73
+        %112 = OpLoad %79 %111
+        %114 = OpAccessChain %113 %90 %53
+        %115 = OpLoad %78 %114
+        %116 = OpVectorTimesScalar %79 %112 %115
+        %117 = OpConvertFToU %13 %116
+        %118 = OpCompositeExtract %10 %117 0
+        %119 = OpCompositeExtract %10 %117 1
+        %120 = OpCompositeExtract %10 %117 2
+        %121 = OpCompositeConstruct %77 %118 %119 %120 %16
+        %122 = OpAccessChain %94 %82 %45
+        %123 = OpLoad %77 %122
+        %124 = OpIAdd %77 %123 %121
+        %125 = OpAccessChain %94 %82 %45
+               OpStore %125 %124
+               OpBranch %105
+        %105 = OpLabel
+        %126 = OpLoad %24 %101
+        %127 = OpIAdd %24 %126 %73
+               OpStore %101 %127
+               OpBranch %102
+        %104 = OpLabel
+               OpMemoryBarrier %40 %41
+               OpControlBarrier %40 %40 %42
+        %128 = OpLoad %25 %27
+        %130 = OpImageRead %38 %128 %129
+        %131 = OpCompositeExtract %24 %130 0
+        %132 = OpConvertSToF %78 %131
+        %133 = OpCompositeConstruct %79 %132 %132 %132
+        %134 = OpAccessChain %110 %82 %73
+               OpStore %134 %133
+               OpReturn
+               OpFunctionEnd
+
+)";
+  constexpr char kDstNoDebug[] = R"(               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %4 "main" %15
+               OpExecutionMode %4 LocalSize 1 1 1
+               OpSource ESSL 310
+               OpDecorate %15 BuiltIn LocalInvocationId
+               OpDecorate %27 DescriptorSet 0
+               OpDecorate %27 Binding 2
+               OpMemberDecorate %80 0 Offset 0
+               OpMemberDecorate %80 1 Offset 16
+               OpMemberDecorate %80 2 Offset 28
+               OpDecorate %80 BufferBlock
+               OpDecorate %82 DescriptorSet 0
+               OpDecorate %82 Binding 1
+               OpMemberDecorate %88 0 Offset 0
+               OpMemberDecorate %88 1 RowMajor
+               OpMemberDecorate %88 1 Offset 16
+               OpMemberDecorate %88 1 MatrixStride 16
+               OpMemberDecorate %88 2 Offset 80
+               OpDecorate %88 Block
+               OpDecorate %90 DescriptorSet 0
+               OpDecorate %90 Binding 0
+               OpDecorate %128 DescriptorSet 0
+               OpDecorate %128 Binding 3
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+         %10 = OpTypeInt 32 0
+         %11 = OpTypePointer Function %10
+         %13 = OpTypeVector %10 3
+         %14 = OpTypePointer Input %13
+         %15 = OpVariable %14 Input
+         %16 = OpConstant %10 0
+         %17 = OpTypePointer Input %10
+         %21 = OpConstant %10 1
+         %24 = OpTypeInt 32 1
+         %25 = OpTypeImage %24 2D 0 0 0 2 R32i
+         %26 = OpTypePointer UniformConstant %25
+         %27 = OpVariable %26 UniformConstant
+         %29 = OpTypeVector %10 2
+         %32 = OpTypeVector %24 2
+         %38 = OpTypeVector %24 4
+         %40 = OpConstant %10 2
+         %41 = OpConstant %10 3400
+         %42 = OpConstant %10 264
+         %43 = OpTypePointer Function %24
+         %45 = OpConstant %24 0
+         %53 = OpConstant %24 2
+         %54 = OpTypeBool
+         %73 = OpConstant %24 1
+         %77 = OpTypeVector %10 4
+         %78 = OpTypeFloat 32
+         %79 = OpTypeVector %78 3
+         %80 = OpTypeStruct %77 %79 %24
+         %81 = OpTypePointer Uniform %80
+         %82 = OpVariable %81 Uniform
+         %84 = OpTypePointer Uniform %24
+         %86 = OpTypeVector %78 4
+         %87 = OpTypeMatrix %86 4
+         %88 = OpTypeStruct %10 %87 %78
+         %89 = OpTypePointer Uniform %88
+         %90 = OpVariable %89 Uniform
+         %91 = OpTypePointer Uniform %87
+         %94 = OpTypePointer Uniform %77
+        %108 = OpConstant %24 3
+        %110 = OpTypePointer Uniform %79
+        %113 = OpTypePointer Uniform %78
+        %128 = OpVariable %26 UniformConstant
+        %130 = OpConstantComposite %32 %45 %45
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+        %136 = OpFunctionCall %2 %6
+        %137 = OpFunctionCall %2 %8
+               OpReturn
+               OpFunctionEnd
+          %6 = OpFunction %2 None %3
+          %7 = OpLabel
+         %12 = OpVariable %11 Function
+         %20 = OpVariable %11 Function
+         %44 = OpVariable %43 Function
+         %46 = OpVariable %43 Function
+         %56 = OpVariable %43 Function
+         %18 = OpAccessChain %17 %15 %16
+         %19 = OpLoad %10 %18
+               OpStore %12 %19
+         %22 = OpAccessChain %17 %15 %21
+         %23 = OpLoad %10 %22
+               OpStore %20 %23
+         %28 = OpLoad %25 %27
+         %30 = OpLoad %13 %15
+         %31 = OpVectorShuffle %29 %30 %30 0 1
+         %33 = OpBitcast %32 %31
+         %34 = OpLoad %10 %12
+         %35 = OpLoad %10 %20
+         %36 = OpIAdd %10 %34 %35
+         %37 = OpBitcast %24 %36
+         %39 = OpCompositeConstruct %38 %37 %37 %37 %37
+               OpImageWrite %28 %33 %39
+               OpMemoryBarrier %40 %41
+               OpControlBarrier %40 %40 %42
+               OpStore %44 %45
+               OpStore %46 %45
+               OpBranch %47
+         %47 = OpLabel
+               OpLoopMerge %49 %50 None
+               OpBranch %51
+         %51 = OpLabel
+         %52 = OpLoad %24 %46
+         %55 = OpSLessThan %54 %52 %53
+               OpBranchConditional %55 %48 %49
+         %48 = OpLabel
+               OpStore %56 %45
+               OpBranch %57
+         %57 = OpLabel
+               OpLoopMerge %59 %60 None
+               OpBranch %61
+         %61 = OpLabel
+         %62 = OpLoad %24 %56
+         %63 = OpSLessThan %54 %62 %53
+               OpBranchConditional %63 %58 %59
+         %58 = OpLabel
+         %64 = OpLoad %25 %27
+         %65 = OpLoad %24 %46
+         %66 = OpLoad %24 %56
+         %67 = OpCompositeConstruct %32 %65 %66
+         %68 = OpImageRead %38 %64 %67
+         %69 = OpCompositeExtract %24 %68 0
+         %70 = OpLoad %24 %44
+         %71 = OpIMul %24 %70 %69
+               OpStore %44 %71
+               OpBranch %60
+         %60 = OpLabel
+         %72 = OpLoad %24 %56
+         %74 = OpIAdd %24 %72 %73
+               OpStore %56 %74
+               OpBranch %57
+         %59 = OpLabel
+               OpBranch %50
+         %50 = OpLabel
+         %75 = OpLoad %24 %46
+         %76 = OpIAdd %24 %75 %73
+               OpStore %46 %76
+               OpBranch %47
+         %49 = OpLabel
+               OpMemoryBarrier %40 %41
+               OpControlBarrier %40 %40 %42
+         %83 = OpLoad %24 %44
+         %85 = OpAccessChain %84 %82 %53
+               OpStore %85 %83
+               OpReturn
+               OpFunctionEnd
+          %8 = OpFunction %2 None %3
+          %9 = OpLabel
+        %101 = OpVariable %43 Function
+         %92 = OpAccessChain %91 %90 %73
+         %93 = OpLoad %87 %92
+         %95 = OpAccessChain %94 %82 %45
+         %96 = OpLoad %77 %95
+         %97 = OpConvertUToF %86 %96
+         %98 = OpMatrixTimesVector %86 %93 %97
+         %99 = OpConvertFToU %77 %98
+        %100 = OpAccessChain %94 %82 %45
+               OpStore %100 %99
+               OpStore %101 %45
+               OpBranch %102
+        %102 = OpLabel
+               OpLoopMerge %104 %105 None
+               OpBranch %106
+        %106 = OpLabel
+        %107 = OpLoad %24 %101
+        %109 = OpSLessThan %54 %107 %108
+               OpBranchConditional %109 %103 %104
+        %103 = OpLabel
+        %111 = OpAccessChain %110 %82 %73
+        %112 = OpLoad %79 %111
+        %114 = OpAccessChain %113 %90 %53
+        %115 = OpLoad %78 %114
+        %116 = OpVectorTimesScalar %79 %112 %115
+        %117 = OpConvertFToU %13 %116
+        %118 = OpCompositeExtract %10 %117 0
+        %119 = OpCompositeExtract %10 %117 1
+        %120 = OpCompositeExtract %10 %117 2
+        %121 = OpCompositeConstruct %77 %118 %119 %120 %16
+        %122 = OpAccessChain %94 %82 %45
+        %123 = OpLoad %77 %122
+        %124 = OpIAdd %77 %123 %121
+        %125 = OpAccessChain %94 %82 %45
+               OpStore %125 %124
+               OpBranch %105
+        %105 = OpLabel
+        %126 = OpLoad %24 %101
+        %127 = OpIAdd %24 %126 %73
+               OpStore %101 %127
+               OpBranch %102
+        %104 = OpLabel
+               OpMemoryBarrier %40 %41
+               OpControlBarrier %40 %40 %42
+        %129 = OpLoad %25 %128
+        %131 = OpImageRead %38 %129 %130
+        %132 = OpCompositeExtract %24 %131 0
+        %133 = OpConvertSToF %78 %132
+        %134 = OpCompositeConstruct %79 %133 %133 %133
+        %135 = OpAccessChain %110 %82 %73
+               OpStore %135 %134
+               OpReturn
+               OpFunctionEnd
+
+)";
+  constexpr char kDiff[] = R"( ; SPIR-V
+ ; Version: 1.6
+ ; Generator: Khronos SPIR-V Tools Assembler; 0
+-; Bound: 137
++; Bound: 140
+ ; Schema: 0
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %4 "main" %15
+ OpExecutionMode %4 LocalSize 1 1 1
+ OpSource ESSL 310
+ OpDecorate %15 BuiltIn LocalInvocationId
+ OpDecorate %27 DescriptorSet 0
+ OpDecorate %27 Binding 2
+ OpMemberDecorate %80 0 Offset 0
+ OpMemberDecorate %80 1 Offset 16
+ OpMemberDecorate %80 2 Offset 28
+ OpDecorate %80 BufferBlock
+ OpDecorate %82 DescriptorSet 0
+ OpDecorate %82 Binding 1
+ OpMemberDecorate %88 0 Offset 0
+ OpMemberDecorate %88 1 RowMajor
+ OpMemberDecorate %88 1 Offset 16
+ OpMemberDecorate %88 1 MatrixStride 16
+ OpMemberDecorate %88 2 Offset 80
+ OpDecorate %88 Block
+ OpDecorate %90 DescriptorSet 0
+ OpDecorate %90 Binding 0
++OpDecorate %138 DescriptorSet 0
++OpDecorate %138 Binding 3
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %10 = OpTypeInt 32 0
+ %11 = OpTypePointer Function %10
+ %13 = OpTypeVector %10 3
+ %14 = OpTypePointer Input %13
+ %15 = OpVariable %14 Input
+ %16 = OpConstant %10 0
+ %17 = OpTypePointer Input %10
+ %21 = OpConstant %10 1
+ %24 = OpTypeInt 32 1
+ %25 = OpTypeImage %24 2D 0 0 0 2 R32i
+ %26 = OpTypePointer UniformConstant %25
+ %27 = OpVariable %26 UniformConstant
+ %29 = OpTypeVector %10 2
+ %32 = OpTypeVector %24 2
+ %38 = OpTypeVector %24 4
+ %40 = OpConstant %10 2
+ %41 = OpConstant %10 3400
+ %42 = OpConstant %10 264
+ %43 = OpTypePointer Function %24
+ %45 = OpConstant %24 0
+ %53 = OpConstant %24 2
+ %54 = OpTypeBool
+ %73 = OpConstant %24 1
+ %77 = OpTypeVector %10 4
+ %78 = OpTypeFloat 32
+ %79 = OpTypeVector %78 3
+ %80 = OpTypeStruct %77 %79 %24
+ %81 = OpTypePointer Uniform %80
+ %82 = OpVariable %81 Uniform
+ %84 = OpTypePointer Uniform %24
+ %86 = OpTypeVector %78 4
+ %87 = OpTypeMatrix %86 4
+ %88 = OpTypeStruct %10 %87 %78
+ %89 = OpTypePointer Uniform %88
+ %90 = OpVariable %89 Uniform
+ %91 = OpTypePointer Uniform %87
+ %94 = OpTypePointer Uniform %77
+ %108 = OpConstant %24 3
+ %110 = OpTypePointer Uniform %79
+ %113 = OpTypePointer Uniform %78
++%138 = OpVariable %26 UniformConstant
+ %129 = OpConstantComposite %32 %45 %45
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ %135 = OpFunctionCall %2 %6
+ %136 = OpFunctionCall %2 %8
+ OpReturn
+ OpFunctionEnd
+ %6 = OpFunction %2 None %3
+ %7 = OpLabel
+ %12 = OpVariable %11 Function
+ %20 = OpVariable %11 Function
+ %44 = OpVariable %43 Function
+ %46 = OpVariable %43 Function
+ %56 = OpVariable %43 Function
+ %18 = OpAccessChain %17 %15 %16
+ %19 = OpLoad %10 %18
+ OpStore %12 %19
+ %22 = OpAccessChain %17 %15 %21
+ %23 = OpLoad %10 %22
+ OpStore %20 %23
+ %28 = OpLoad %25 %27
+ %30 = OpLoad %13 %15
+ %31 = OpVectorShuffle %29 %30 %30 0 1
+ %33 = OpBitcast %32 %31
+ %34 = OpLoad %10 %12
+ %35 = OpLoad %10 %20
+ %36 = OpIAdd %10 %34 %35
+ %37 = OpBitcast %24 %36
+ %39 = OpCompositeConstruct %38 %37 %37 %37 %37
+ OpImageWrite %28 %33 %39
+ OpMemoryBarrier %40 %41
+ OpControlBarrier %40 %40 %42
+ OpStore %44 %45
+ OpStore %46 %45
+ OpBranch %47
+ %47 = OpLabel
+ OpLoopMerge %49 %50 None
+ OpBranch %51
+ %51 = OpLabel
+ %52 = OpLoad %24 %46
+ %55 = OpSLessThan %54 %52 %53
+ OpBranchConditional %55 %48 %49
+ %48 = OpLabel
+ OpStore %56 %45
+ OpBranch %57
+ %57 = OpLabel
+ OpLoopMerge %59 %60 None
+ OpBranch %61
+ %61 = OpLabel
+ %62 = OpLoad %24 %56
+ %63 = OpSLessThan %54 %62 %53
+ OpBranchConditional %63 %58 %59
+ %58 = OpLabel
+ %64 = OpLoad %25 %27
+ %65 = OpLoad %24 %46
+ %66 = OpLoad %24 %56
+ %67 = OpCompositeConstruct %32 %65 %66
+ %68 = OpImageRead %38 %64 %67
+ %69 = OpCompositeExtract %24 %68 0
+ %70 = OpLoad %24 %44
+-%71 = OpIAdd %24 %70 %69
++%137 = OpIMul %24 %70 %69
+-OpStore %44 %71
++OpStore %44 %137
+ OpBranch %60
+ %60 = OpLabel
+ %72 = OpLoad %24 %56
+ %74 = OpIAdd %24 %72 %73
+ OpStore %56 %74
+ OpBranch %57
+ %59 = OpLabel
+ OpBranch %50
+ %50 = OpLabel
+ %75 = OpLoad %24 %46
+ %76 = OpIAdd %24 %75 %73
+ OpStore %46 %76
+ OpBranch %47
+ %49 = OpLabel
+ OpMemoryBarrier %40 %41
+ OpControlBarrier %40 %40 %42
+ %83 = OpLoad %24 %44
+ %85 = OpAccessChain %84 %82 %53
+ OpStore %85 %83
+ OpReturn
+ OpFunctionEnd
+ %8 = OpFunction %2 None %3
+ %9 = OpLabel
+ %101 = OpVariable %43 Function
+ %92 = OpAccessChain %91 %90 %73
+ %93 = OpLoad %87 %92
+ %95 = OpAccessChain %94 %82 %45
+ %96 = OpLoad %77 %95
+ %97 = OpConvertUToF %86 %96
+ %98 = OpMatrixTimesVector %86 %93 %97
+ %99 = OpConvertFToU %77 %98
+ %100 = OpAccessChain %94 %82 %45
+ OpStore %100 %99
+ OpStore %101 %45
+ OpBranch %102
+ %102 = OpLabel
+ OpLoopMerge %104 %105 None
+ OpBranch %106
+ %106 = OpLabel
+ %107 = OpLoad %24 %101
+ %109 = OpSLessThan %54 %107 %108
+ OpBranchConditional %109 %103 %104
+ %103 = OpLabel
+ %111 = OpAccessChain %110 %82 %73
+ %112 = OpLoad %79 %111
+ %114 = OpAccessChain %113 %90 %53
+ %115 = OpLoad %78 %114
+ %116 = OpVectorTimesScalar %79 %112 %115
+ %117 = OpConvertFToU %13 %116
+ %118 = OpCompositeExtract %10 %117 0
+ %119 = OpCompositeExtract %10 %117 1
+ %120 = OpCompositeExtract %10 %117 2
+ %121 = OpCompositeConstruct %77 %118 %119 %120 %16
+ %122 = OpAccessChain %94 %82 %45
+ %123 = OpLoad %77 %122
+ %124 = OpIAdd %77 %123 %121
+ %125 = OpAccessChain %94 %82 %45
+ OpStore %125 %124
+ OpBranch %105
+ %105 = OpLabel
+ %126 = OpLoad %24 %101
+ %127 = OpIAdd %24 %126 %73
+ OpStore %101 %127
+ OpBranch %102
+ %104 = OpLabel
+ OpMemoryBarrier %40 %41
+ OpControlBarrier %40 %40 %42
+-%128 = OpLoad %25 %27
++%139 = OpLoad %25 %138
+-%130 = OpImageRead %38 %128 %129
++%130 = OpImageRead %38 %139 %129
+ %131 = OpCompositeExtract %24 %130 0
+ %132 = OpConvertSToF %78 %131
+ %133 = OpCompositeConstruct %79 %132 %132 %132
+ %134 = OpAccessChain %110 %82 %73
+ OpStore %134 %133
+ OpReturn
+ OpFunctionEnd
+)";
+  Options options;
+  DoStringDiffTest(kSrcNoDebug, kDstNoDebug, kDiff, options);
+}
+
+}  // namespace
+}  // namespace diff
+}  // namespace spvtools

+ 229 - 0
ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/large_functions_small_diffs_dst.spvasm

@@ -0,0 +1,229 @@
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %4 "main" %15
+               OpExecutionMode %4 LocalSize 1 1 1
+               OpSource ESSL 310
+               OpName %4 "main"
+               OpName %6 "f1("
+               OpName %8 "f2("
+               OpName %12 "x"
+               OpName %15 "gl_LocalInvocationID"
+               OpName %20 "y"
+               OpName %27 "image"
+               OpName %44 "sum"
+               OpName %46 "i"
+               OpName %56 "j"
+               OpName %80 "BufferOut"
+               OpMemberName %80 0 "o_uv4"
+               OpMemberName %80 1 "o_v3"
+               OpMemberName %80 2 "o_i"
+               OpName %82 ""
+               OpName %88 "BufferIn"
+               OpMemberName %88 0 "i_u"
+               OpMemberName %88 1 "i_v4"
+               OpMemberName %88 2 "i_f"
+               OpName %90 ""
+               OpName %101 "i"
+               OpName %128 "image2"
+               OpDecorate %15 BuiltIn LocalInvocationId
+               OpDecorate %27 DescriptorSet 0
+               OpDecorate %27 Binding 2
+               OpMemberDecorate %80 0 Offset 0
+               OpMemberDecorate %80 1 Offset 16
+               OpMemberDecorate %80 2 Offset 28
+               OpDecorate %80 BufferBlock
+               OpDecorate %82 DescriptorSet 0
+               OpDecorate %82 Binding 1
+               OpMemberDecorate %88 0 Offset 0
+               OpMemberDecorate %88 1 RowMajor
+               OpMemberDecorate %88 1 Offset 16
+               OpMemberDecorate %88 1 MatrixStride 16
+               OpMemberDecorate %88 2 Offset 80
+               OpDecorate %88 Block
+               OpDecorate %90 DescriptorSet 0
+               OpDecorate %90 Binding 0
+               OpDecorate %128 DescriptorSet 0
+               OpDecorate %128 Binding 3
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+         %10 = OpTypeInt 32 0
+         %11 = OpTypePointer Function %10
+         %13 = OpTypeVector %10 3
+         %14 = OpTypePointer Input %13
+         %15 = OpVariable %14 Input
+         %16 = OpConstant %10 0
+         %17 = OpTypePointer Input %10
+         %21 = OpConstant %10 1
+         %24 = OpTypeInt 32 1
+         %25 = OpTypeImage %24 2D 0 0 0 2 R32i
+         %26 = OpTypePointer UniformConstant %25
+         %27 = OpVariable %26 UniformConstant
+         %29 = OpTypeVector %10 2
+         %32 = OpTypeVector %24 2
+         %38 = OpTypeVector %24 4
+         %40 = OpConstant %10 2
+         %41 = OpConstant %10 3400
+         %42 = OpConstant %10 264
+         %43 = OpTypePointer Function %24
+         %45 = OpConstant %24 0
+         %53 = OpConstant %24 2
+         %54 = OpTypeBool
+         %73 = OpConstant %24 1
+         %77 = OpTypeVector %10 4
+         %78 = OpTypeFloat 32
+         %79 = OpTypeVector %78 3
+         %80 = OpTypeStruct %77 %79 %24
+         %81 = OpTypePointer Uniform %80
+         %82 = OpVariable %81 Uniform
+         %84 = OpTypePointer Uniform %24
+         %86 = OpTypeVector %78 4
+         %87 = OpTypeMatrix %86 4
+         %88 = OpTypeStruct %10 %87 %78
+         %89 = OpTypePointer Uniform %88
+         %90 = OpVariable %89 Uniform
+         %91 = OpTypePointer Uniform %87
+         %94 = OpTypePointer Uniform %77
+        %108 = OpConstant %24 3
+        %110 = OpTypePointer Uniform %79
+        %113 = OpTypePointer Uniform %78
+        %128 = OpVariable %26 UniformConstant
+        %130 = OpConstantComposite %32 %45 %45
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+        %136 = OpFunctionCall %2 %6
+        %137 = OpFunctionCall %2 %8
+               OpReturn
+               OpFunctionEnd
+          %6 = OpFunction %2 None %3
+          %7 = OpLabel
+         %12 = OpVariable %11 Function
+         %20 = OpVariable %11 Function
+         %44 = OpVariable %43 Function
+         %46 = OpVariable %43 Function
+         %56 = OpVariable %43 Function
+         %18 = OpAccessChain %17 %15 %16
+         %19 = OpLoad %10 %18
+               OpStore %12 %19
+         %22 = OpAccessChain %17 %15 %21
+         %23 = OpLoad %10 %22
+               OpStore %20 %23
+         %28 = OpLoad %25 %27
+         %30 = OpLoad %13 %15
+         %31 = OpVectorShuffle %29 %30 %30 0 1
+         %33 = OpBitcast %32 %31
+         %34 = OpLoad %10 %12
+         %35 = OpLoad %10 %20
+         %36 = OpIAdd %10 %34 %35
+         %37 = OpBitcast %24 %36
+         %39 = OpCompositeConstruct %38 %37 %37 %37 %37
+               OpImageWrite %28 %33 %39
+               OpMemoryBarrier %40 %41
+               OpControlBarrier %40 %40 %42
+               OpStore %44 %45
+               OpStore %46 %45
+               OpBranch %47
+         %47 = OpLabel
+               OpLoopMerge %49 %50 None
+               OpBranch %51
+         %51 = OpLabel
+         %52 = OpLoad %24 %46
+         %55 = OpSLessThan %54 %52 %53
+               OpBranchConditional %55 %48 %49
+         %48 = OpLabel
+               OpStore %56 %45
+               OpBranch %57
+         %57 = OpLabel
+               OpLoopMerge %59 %60 None
+               OpBranch %61
+         %61 = OpLabel
+         %62 = OpLoad %24 %56
+         %63 = OpSLessThan %54 %62 %53
+               OpBranchConditional %63 %58 %59
+         %58 = OpLabel
+         %64 = OpLoad %25 %27
+         %65 = OpLoad %24 %46
+         %66 = OpLoad %24 %56
+         %67 = OpCompositeConstruct %32 %65 %66
+         %68 = OpImageRead %38 %64 %67
+         %69 = OpCompositeExtract %24 %68 0
+         %70 = OpLoad %24 %44
+         %71 = OpIMul %24 %70 %69
+               OpStore %44 %71
+               OpBranch %60
+         %60 = OpLabel
+         %72 = OpLoad %24 %56
+         %74 = OpIAdd %24 %72 %73
+               OpStore %56 %74
+               OpBranch %57
+         %59 = OpLabel
+               OpBranch %50
+         %50 = OpLabel
+         %75 = OpLoad %24 %46
+         %76 = OpIAdd %24 %75 %73
+               OpStore %46 %76
+               OpBranch %47
+         %49 = OpLabel
+               OpMemoryBarrier %40 %41
+               OpControlBarrier %40 %40 %42
+         %83 = OpLoad %24 %44
+         %85 = OpAccessChain %84 %82 %53
+               OpStore %85 %83
+               OpReturn
+               OpFunctionEnd
+          %8 = OpFunction %2 None %3
+          %9 = OpLabel
+        %101 = OpVariable %43 Function
+         %92 = OpAccessChain %91 %90 %73
+         %93 = OpLoad %87 %92
+         %95 = OpAccessChain %94 %82 %45
+         %96 = OpLoad %77 %95
+         %97 = OpConvertUToF %86 %96
+         %98 = OpMatrixTimesVector %86 %93 %97
+         %99 = OpConvertFToU %77 %98
+        %100 = OpAccessChain %94 %82 %45
+               OpStore %100 %99
+               OpStore %101 %45
+               OpBranch %102
+        %102 = OpLabel
+               OpLoopMerge %104 %105 None
+               OpBranch %106
+        %106 = OpLabel
+        %107 = OpLoad %24 %101
+        %109 = OpSLessThan %54 %107 %108
+               OpBranchConditional %109 %103 %104
+        %103 = OpLabel
+        %111 = OpAccessChain %110 %82 %73
+        %112 = OpLoad %79 %111
+        %114 = OpAccessChain %113 %90 %53
+        %115 = OpLoad %78 %114
+        %116 = OpVectorTimesScalar %79 %112 %115
+        %117 = OpConvertFToU %13 %116
+        %118 = OpCompositeExtract %10 %117 0
+        %119 = OpCompositeExtract %10 %117 1
+        %120 = OpCompositeExtract %10 %117 2
+        %121 = OpCompositeConstruct %77 %118 %119 %120 %16
+        %122 = OpAccessChain %94 %82 %45
+        %123 = OpLoad %77 %122
+        %124 = OpIAdd %77 %123 %121
+        %125 = OpAccessChain %94 %82 %45
+               OpStore %125 %124
+               OpBranch %105
+        %105 = OpLabel
+        %126 = OpLoad %24 %101
+        %127 = OpIAdd %24 %126 %73
+               OpStore %101 %127
+               OpBranch %102
+        %104 = OpLabel
+               OpMemoryBarrier %40 %41
+               OpControlBarrier %40 %40 %42
+        %129 = OpLoad %25 %128
+        %131 = OpImageRead %38 %129 %130
+        %132 = OpCompositeExtract %24 %131 0
+        %133 = OpConvertSToF %78 %132
+        %134 = OpCompositeConstruct %79 %133 %133 %133
+        %135 = OpAccessChain %110 %82 %73
+               OpStore %135 %134
+               OpReturn
+               OpFunctionEnd
+

+ 226 - 0
ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/large_functions_small_diffs_src.spvasm

@@ -0,0 +1,226 @@
+;; Test where src and dst have a few large functions with small differences.
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %4 "main" %15
+               OpExecutionMode %4 LocalSize 1 1 1
+               OpSource ESSL 310
+               OpName %4 "main"
+               OpName %6 "f1("
+               OpName %8 "f2("
+               OpName %12 "x"
+               OpName %15 "gl_LocalInvocationID"
+               OpName %20 "y"
+               OpName %27 "image"
+               OpName %44 "sum"
+               OpName %46 "i"
+               OpName %56 "j"
+               OpName %80 "BufferOut"
+               OpMemberName %80 0 "o_uv4"
+               OpMemberName %80 1 "o_v3"
+               OpMemberName %80 2 "o_i"
+               OpName %82 ""
+               OpName %88 "BufferIn"
+               OpMemberName %88 0 "i_u"
+               OpMemberName %88 1 "i_v4"
+               OpMemberName %88 2 "i_f"
+               OpName %90 ""
+               OpName %101 "i"
+               OpDecorate %15 BuiltIn LocalInvocationId
+               OpDecorate %27 DescriptorSet 0
+               OpDecorate %27 Binding 2
+               OpMemberDecorate %80 0 Offset 0
+               OpMemberDecorate %80 1 Offset 16
+               OpMemberDecorate %80 2 Offset 28
+               OpDecorate %80 BufferBlock
+               OpDecorate %82 DescriptorSet 0
+               OpDecorate %82 Binding 1
+               OpMemberDecorate %88 0 Offset 0
+               OpMemberDecorate %88 1 RowMajor
+               OpMemberDecorate %88 1 Offset 16
+               OpMemberDecorate %88 1 MatrixStride 16
+               OpMemberDecorate %88 2 Offset 80
+               OpDecorate %88 Block
+               OpDecorate %90 DescriptorSet 0
+               OpDecorate %90 Binding 0
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+         %10 = OpTypeInt 32 0
+         %11 = OpTypePointer Function %10
+         %13 = OpTypeVector %10 3
+         %14 = OpTypePointer Input %13
+         %15 = OpVariable %14 Input
+         %16 = OpConstant %10 0
+         %17 = OpTypePointer Input %10
+         %21 = OpConstant %10 1
+         %24 = OpTypeInt 32 1
+         %25 = OpTypeImage %24 2D 0 0 0 2 R32i
+         %26 = OpTypePointer UniformConstant %25
+         %27 = OpVariable %26 UniformConstant
+         %29 = OpTypeVector %10 2
+         %32 = OpTypeVector %24 2
+         %38 = OpTypeVector %24 4
+         %40 = OpConstant %10 2
+         %41 = OpConstant %10 3400
+         %42 = OpConstant %10 264
+         %43 = OpTypePointer Function %24
+         %45 = OpConstant %24 0
+         %53 = OpConstant %24 2
+         %54 = OpTypeBool
+         %73 = OpConstant %24 1
+         %77 = OpTypeVector %10 4
+         %78 = OpTypeFloat 32
+         %79 = OpTypeVector %78 3
+         %80 = OpTypeStruct %77 %79 %24
+         %81 = OpTypePointer Uniform %80
+         %82 = OpVariable %81 Uniform
+         %84 = OpTypePointer Uniform %24
+         %86 = OpTypeVector %78 4
+         %87 = OpTypeMatrix %86 4
+         %88 = OpTypeStruct %10 %87 %78
+         %89 = OpTypePointer Uniform %88
+         %90 = OpVariable %89 Uniform
+         %91 = OpTypePointer Uniform %87
+         %94 = OpTypePointer Uniform %77
+        %108 = OpConstant %24 3
+        %110 = OpTypePointer Uniform %79
+        %113 = OpTypePointer Uniform %78
+        %129 = OpConstantComposite %32 %45 %45
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+        %135 = OpFunctionCall %2 %6
+        %136 = OpFunctionCall %2 %8
+               OpReturn
+               OpFunctionEnd
+          %6 = OpFunction %2 None %3
+          %7 = OpLabel
+         %12 = OpVariable %11 Function
+         %20 = OpVariable %11 Function
+         %44 = OpVariable %43 Function
+         %46 = OpVariable %43 Function
+         %56 = OpVariable %43 Function
+         %18 = OpAccessChain %17 %15 %16
+         %19 = OpLoad %10 %18
+               OpStore %12 %19
+         %22 = OpAccessChain %17 %15 %21
+         %23 = OpLoad %10 %22
+               OpStore %20 %23
+         %28 = OpLoad %25 %27
+         %30 = OpLoad %13 %15
+         %31 = OpVectorShuffle %29 %30 %30 0 1
+         %33 = OpBitcast %32 %31
+         %34 = OpLoad %10 %12
+         %35 = OpLoad %10 %20
+         %36 = OpIAdd %10 %34 %35
+         %37 = OpBitcast %24 %36
+         %39 = OpCompositeConstruct %38 %37 %37 %37 %37
+               OpImageWrite %28 %33 %39
+               OpMemoryBarrier %40 %41
+               OpControlBarrier %40 %40 %42
+               OpStore %44 %45
+               OpStore %46 %45
+               OpBranch %47
+         %47 = OpLabel
+               OpLoopMerge %49 %50 None
+               OpBranch %51
+         %51 = OpLabel
+         %52 = OpLoad %24 %46
+         %55 = OpSLessThan %54 %52 %53
+               OpBranchConditional %55 %48 %49
+         %48 = OpLabel
+               OpStore %56 %45
+               OpBranch %57
+         %57 = OpLabel
+               OpLoopMerge %59 %60 None
+               OpBranch %61
+         %61 = OpLabel
+         %62 = OpLoad %24 %56
+         %63 = OpSLessThan %54 %62 %53
+               OpBranchConditional %63 %58 %59
+         %58 = OpLabel
+         %64 = OpLoad %25 %27
+         %65 = OpLoad %24 %46
+         %66 = OpLoad %24 %56
+         %67 = OpCompositeConstruct %32 %65 %66
+         %68 = OpImageRead %38 %64 %67
+         %69 = OpCompositeExtract %24 %68 0
+         %70 = OpLoad %24 %44
+         %71 = OpIAdd %24 %70 %69
+               OpStore %44 %71
+               OpBranch %60
+         %60 = OpLabel
+         %72 = OpLoad %24 %56
+         %74 = OpIAdd %24 %72 %73
+               OpStore %56 %74
+               OpBranch %57
+         %59 = OpLabel
+               OpBranch %50
+         %50 = OpLabel
+         %75 = OpLoad %24 %46
+         %76 = OpIAdd %24 %75 %73
+               OpStore %46 %76
+               OpBranch %47
+         %49 = OpLabel
+               OpMemoryBarrier %40 %41
+               OpControlBarrier %40 %40 %42
+         %83 = OpLoad %24 %44
+         %85 = OpAccessChain %84 %82 %53
+               OpStore %85 %83
+               OpReturn
+               OpFunctionEnd
+          %8 = OpFunction %2 None %3
+          %9 = OpLabel
+        %101 = OpVariable %43 Function
+         %92 = OpAccessChain %91 %90 %73
+         %93 = OpLoad %87 %92
+         %95 = OpAccessChain %94 %82 %45
+         %96 = OpLoad %77 %95
+         %97 = OpConvertUToF %86 %96
+         %98 = OpMatrixTimesVector %86 %93 %97
+         %99 = OpConvertFToU %77 %98
+        %100 = OpAccessChain %94 %82 %45
+               OpStore %100 %99
+               OpStore %101 %45
+               OpBranch %102
+        %102 = OpLabel
+               OpLoopMerge %104 %105 None
+               OpBranch %106
+        %106 = OpLabel
+        %107 = OpLoad %24 %101
+        %109 = OpSLessThan %54 %107 %108
+               OpBranchConditional %109 %103 %104
+        %103 = OpLabel
+        %111 = OpAccessChain %110 %82 %73
+        %112 = OpLoad %79 %111
+        %114 = OpAccessChain %113 %90 %53
+        %115 = OpLoad %78 %114
+        %116 = OpVectorTimesScalar %79 %112 %115
+        %117 = OpConvertFToU %13 %116
+        %118 = OpCompositeExtract %10 %117 0
+        %119 = OpCompositeExtract %10 %117 1
+        %120 = OpCompositeExtract %10 %117 2
+        %121 = OpCompositeConstruct %77 %118 %119 %120 %16
+        %122 = OpAccessChain %94 %82 %45
+        %123 = OpLoad %77 %122
+        %124 = OpIAdd %77 %123 %121
+        %125 = OpAccessChain %94 %82 %45
+               OpStore %125 %124
+               OpBranch %105
+        %105 = OpLabel
+        %126 = OpLoad %24 %101
+        %127 = OpIAdd %24 %126 %73
+               OpStore %101 %127
+               OpBranch %102
+        %104 = OpLabel
+               OpMemoryBarrier %40 %41
+               OpControlBarrier %40 %40 %42
+        %128 = OpLoad %25 %27
+        %130 = OpImageRead %38 %128 %129
+        %131 = OpCompositeExtract %24 %130 0
+        %132 = OpConvertSToF %78 %131
+        %133 = OpCompositeConstruct %79 %132 %132 %132
+        %134 = OpAccessChain %110 %82 %73
+               OpStore %134 %133
+               OpReturn
+               OpFunctionEnd
+

+ 330 - 0
ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/multiple_different_entry_points_autogen.cpp

@@ -0,0 +1,330 @@
+// GENERATED FILE - DO NOT EDIT.
+// Generated by generate_tests.py
+//
+// 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 "../diff_test_utils.h"
+
+#include "gtest/gtest.h"
+
+namespace spvtools {
+namespace diff {
+namespace {
+
+// Basic test for multiple entry points.  The entry points have different
+// execution models and so can be trivially matched.
+constexpr char kSrc[] = R"(               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Vertex %mainv "mainv" %vo %a
+               OpEntryPoint Fragment %mainf "mainf" %color %vi
+	       OpExecutionMode %mainf OriginUpperLeft
+               OpSource ESSL 310
+               OpName %mainv "mainv"
+               OpName %mainf "mainf"
+               OpName %a "a"
+               OpName %vo "v"
+               OpName %vi "v"
+               OpName %color "color"
+               OpDecorate %a Location 0
+               OpDecorate %vo Location 0
+               OpDecorate %vi Location 0
+               OpDecorate %color Location 0
+	       OpDecorate %color RelaxedPrecision
+	       OpDecorate %vi RelaxedPrecision
+               OpDecorate %12 RelaxedPrecision
+               OpDecorate %13 RelaxedPrecision
+
+       %void = OpTypeVoid
+          %3 = OpTypeFunction %void
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+
+%_ptr_Input_float = OpTypePointer Input %float
+          %a = OpVariable %_ptr_Input_float Input
+%_ptr_Output_float = OpTypePointer Output %float
+         %vo = OpVariable %_ptr_Output_float Output
+         %vi = OpVariable %_ptr_Input_float Input
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+      %color = OpVariable %_ptr_Output_v4float Output
+
+      %mainv = OpFunction %void None %3
+          %5 = OpLabel
+         %11 = OpLoad %float %a
+               OpStore %vo %11
+               OpReturn
+               OpFunctionEnd
+
+      %mainf = OpFunction %void None %3
+          %6 = OpLabel
+         %12 = OpLoad %float %vi
+	 %13 = OpCompositeConstruct %v4float %12 %12 %12 %12
+               OpStore %color %13
+               OpReturn
+               OpFunctionEnd)";
+constexpr char kDst[] = R"(               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %frag "frag" %vi %color
+               OpEntryPoint Vertex %vert "vert" %a %vo
+	       OpExecutionMode %frag OriginUpperLeft
+               OpSource ESSL 310
+               OpName %frag "frag"
+               OpName %vert "vert"
+               OpName %vo "v"
+               OpName %a "a"
+               OpName %color "color"
+               OpName %vi "v"
+               OpDecorate %vi Location 0
+               OpDecorate %color Location 0
+               OpDecorate %a Location 0
+               OpDecorate %vo Location 0
+	       OpDecorate %color RelaxedPrecision
+	       OpDecorate %vi RelaxedPrecision
+               OpDecorate %14 RelaxedPrecision
+               OpDecorate %17 RelaxedPrecision
+
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+       %void = OpTypeVoid
+          %3 = OpTypeFunction %void
+
+%_ptr_Output_float = OpTypePointer Output %float
+         %vo = OpVariable %_ptr_Output_float Output
+%_ptr_Input_float = OpTypePointer Input %float
+          %a = OpVariable %_ptr_Input_float Input
+         %vi = OpVariable %_ptr_Input_float Input
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+      %color = OpVariable %_ptr_Output_v4float Output
+
+       %frag = OpFunction %void None %3
+          %7 = OpLabel
+         %14 = OpLoad %float %vi
+	 %17 = OpCompositeConstruct %v4float %14 %14 %14 %14
+               OpStore %color %17
+               OpReturn
+               OpFunctionEnd
+
+       %vert = OpFunction %void None %3
+          %8 = OpLabel
+         %13 = OpLoad %float %a
+               OpStore %vo %13
+               OpReturn
+               OpFunctionEnd
+)";
+
+TEST(DiffTest, MultipleDifferentEntryPoints) {
+  constexpr char kDiff[] = R"( ; SPIR-V
+ ; Version: 1.6
+ ; Generator: Khronos SPIR-V Tools Assembler; 0
+ ; Bound: 20
+ ; Schema: 0
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+-OpEntryPoint Vertex %2 "mainv" %4 %7
++OpEntryPoint Vertex %2 "vert" %7 %4
+-OpEntryPoint Fragment %8 "mainf" %9 %10
++OpEntryPoint Fragment %8 "frag" %10 %9
+ OpExecutionMode %8 OriginUpperLeft
+ OpSource ESSL 310
+-OpName %2 "mainv"
++OpName %2 "vert"
+-OpName %8 "mainf"
++OpName %8 "frag"
+ OpName %7 "a"
+ OpName %4 "v"
+ OpName %10 "v"
+ OpName %9 "color"
+ OpDecorate %7 Location 0
+ OpDecorate %4 Location 0
+ OpDecorate %10 Location 0
+ OpDecorate %9 Location 0
+ OpDecorate %9 RelaxedPrecision
+ OpDecorate %10 RelaxedPrecision
+ OpDecorate %12 RelaxedPrecision
+ OpDecorate %13 RelaxedPrecision
+ %14 = OpTypeVoid
+ %3 = OpTypeFunction %14
+ %15 = OpTypeFloat 32
+ %16 = OpTypeVector %15 4
+ %17 = OpTypePointer Input %15
+ %7 = OpVariable %17 Input
+ %18 = OpTypePointer Output %15
+ %4 = OpVariable %18 Output
+ %10 = OpVariable %17 Input
+ %19 = OpTypePointer Output %16
+ %9 = OpVariable %19 Output
+ %2 = OpFunction %14 None %3
+ %5 = OpLabel
+ %11 = OpLoad %15 %7
+ OpStore %4 %11
+ OpReturn
+ OpFunctionEnd
+ %8 = OpFunction %14 None %3
+ %6 = OpLabel
+ %12 = OpLoad %15 %10
+ %13 = OpCompositeConstruct %16 %12 %12 %12 %12
+ OpStore %9 %13
+ OpReturn
+ OpFunctionEnd
+)";
+  Options options;
+  DoStringDiffTest(kSrc, kDst, kDiff, options);
+}
+
+TEST(DiffTest, MultipleDifferentEntryPointsNoDebug) {
+  constexpr char kSrcNoDebug[] = R"(               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Vertex %mainv "mainv" %vo %a
+               OpEntryPoint Fragment %mainf "mainf" %color %vi
+	       OpExecutionMode %mainf OriginUpperLeft
+               OpSource ESSL 310
+               OpDecorate %a Location 0
+               OpDecorate %vo Location 0
+               OpDecorate %vi Location 0
+               OpDecorate %color Location 0
+	       OpDecorate %color RelaxedPrecision
+	       OpDecorate %vi RelaxedPrecision
+               OpDecorate %12 RelaxedPrecision
+               OpDecorate %13 RelaxedPrecision
+
+       %void = OpTypeVoid
+          %3 = OpTypeFunction %void
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+
+%_ptr_Input_float = OpTypePointer Input %float
+          %a = OpVariable %_ptr_Input_float Input
+%_ptr_Output_float = OpTypePointer Output %float
+         %vo = OpVariable %_ptr_Output_float Output
+         %vi = OpVariable %_ptr_Input_float Input
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+      %color = OpVariable %_ptr_Output_v4float Output
+
+      %mainv = OpFunction %void None %3
+          %5 = OpLabel
+         %11 = OpLoad %float %a
+               OpStore %vo %11
+               OpReturn
+               OpFunctionEnd
+
+      %mainf = OpFunction %void None %3
+          %6 = OpLabel
+         %12 = OpLoad %float %vi
+	 %13 = OpCompositeConstruct %v4float %12 %12 %12 %12
+               OpStore %color %13
+               OpReturn
+               OpFunctionEnd
+)";
+  constexpr char kDstNoDebug[] = R"(               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %frag "frag" %vi %color
+               OpEntryPoint Vertex %vert "vert" %a %vo
+	       OpExecutionMode %frag OriginUpperLeft
+               OpSource ESSL 310
+               OpDecorate %vi Location 0
+               OpDecorate %color Location 0
+               OpDecorate %a Location 0
+               OpDecorate %vo Location 0
+	       OpDecorate %color RelaxedPrecision
+	       OpDecorate %vi RelaxedPrecision
+               OpDecorate %14 RelaxedPrecision
+               OpDecorate %17 RelaxedPrecision
+
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+       %void = OpTypeVoid
+          %3 = OpTypeFunction %void
+
+%_ptr_Output_float = OpTypePointer Output %float
+         %vo = OpVariable %_ptr_Output_float Output
+%_ptr_Input_float = OpTypePointer Input %float
+          %a = OpVariable %_ptr_Input_float Input
+         %vi = OpVariable %_ptr_Input_float Input
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+      %color = OpVariable %_ptr_Output_v4float Output
+
+       %frag = OpFunction %void None %3
+          %7 = OpLabel
+         %14 = OpLoad %float %vi
+	 %17 = OpCompositeConstruct %v4float %14 %14 %14 %14
+               OpStore %color %17
+               OpReturn
+               OpFunctionEnd
+
+       %vert = OpFunction %void None %3
+          %8 = OpLabel
+         %13 = OpLoad %float %a
+               OpStore %vo %13
+               OpReturn
+               OpFunctionEnd
+)";
+  constexpr char kDiff[] = R"( ; SPIR-V
+ ; Version: 1.6
+ ; Generator: Khronos SPIR-V Tools Assembler; 0
+ ; Bound: 20
+ ; Schema: 0
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+-OpEntryPoint Vertex %2 "mainv" %4 %7
++OpEntryPoint Vertex %2 "vert" %7 %4
+-OpEntryPoint Fragment %8 "mainf" %9 %10
++OpEntryPoint Fragment %8 "frag" %10 %9
+ OpExecutionMode %8 OriginUpperLeft
+ OpSource ESSL 310
+ OpDecorate %7 Location 0
+ OpDecorate %4 Location 0
+ OpDecorate %10 Location 0
+ OpDecorate %9 Location 0
+ OpDecorate %9 RelaxedPrecision
+ OpDecorate %10 RelaxedPrecision
+ OpDecorate %12 RelaxedPrecision
+ OpDecorate %13 RelaxedPrecision
+ %14 = OpTypeVoid
+ %3 = OpTypeFunction %14
+ %15 = OpTypeFloat 32
+ %16 = OpTypeVector %15 4
+ %17 = OpTypePointer Input %15
+ %7 = OpVariable %17 Input
+ %18 = OpTypePointer Output %15
+ %4 = OpVariable %18 Output
+ %10 = OpVariable %17 Input
+ %19 = OpTypePointer Output %16
+ %9 = OpVariable %19 Output
+ %2 = OpFunction %14 None %3
+ %5 = OpLabel
+ %11 = OpLoad %15 %7
+ OpStore %4 %11
+ OpReturn
+ OpFunctionEnd
+ %8 = OpFunction %14 None %3
+ %6 = OpLabel
+ %12 = OpLoad %15 %10
+ %13 = OpCompositeConstruct %16 %12 %12 %12 %12
+ OpStore %9 %13
+ OpReturn
+ OpFunctionEnd
+)";
+  Options options;
+  DoStringDiffTest(kSrcNoDebug, kDstNoDebug, kDiff, options);
+}
+
+}  // namespace
+}  // namespace diff
+}  // namespace spvtools

+ 49 - 0
ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/multiple_different_entry_points_dst.spvasm

@@ -0,0 +1,49 @@
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %frag "frag" %vi %color
+               OpEntryPoint Vertex %vert "vert" %a %vo
+	       OpExecutionMode %frag OriginUpperLeft
+               OpSource ESSL 310
+               OpName %frag "frag"
+               OpName %vert "vert"
+               OpName %vo "v"
+               OpName %a "a"
+               OpName %color "color"
+               OpName %vi "v"
+               OpDecorate %vi Location 0
+               OpDecorate %color Location 0
+               OpDecorate %a Location 0
+               OpDecorate %vo Location 0
+	       OpDecorate %color RelaxedPrecision
+	       OpDecorate %vi RelaxedPrecision
+               OpDecorate %14 RelaxedPrecision
+               OpDecorate %17 RelaxedPrecision
+
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+       %void = OpTypeVoid
+          %3 = OpTypeFunction %void
+
+%_ptr_Output_float = OpTypePointer Output %float
+         %vo = OpVariable %_ptr_Output_float Output
+%_ptr_Input_float = OpTypePointer Input %float
+          %a = OpVariable %_ptr_Input_float Input
+         %vi = OpVariable %_ptr_Input_float Input
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+      %color = OpVariable %_ptr_Output_v4float Output
+
+       %frag = OpFunction %void None %3
+          %7 = OpLabel
+         %14 = OpLoad %float %vi
+	 %17 = OpCompositeConstruct %v4float %14 %14 %14 %14
+               OpStore %color %17
+               OpReturn
+               OpFunctionEnd
+
+       %vert = OpFunction %void None %3
+          %8 = OpLabel
+         %13 = OpLoad %float %a
+               OpStore %vo %13
+               OpReturn
+               OpFunctionEnd

+ 51 - 0
ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/multiple_different_entry_points_src.spvasm

@@ -0,0 +1,51 @@
+;; Basic test for multiple entry points.  The entry points have different
+;; execution models and so can be trivially matched.
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Vertex %mainv "mainv" %vo %a
+               OpEntryPoint Fragment %mainf "mainf" %color %vi
+	       OpExecutionMode %mainf OriginUpperLeft
+               OpSource ESSL 310
+               OpName %mainv "mainv"
+               OpName %mainf "mainf"
+               OpName %a "a"
+               OpName %vo "v"
+               OpName %vi "v"
+               OpName %color "color"
+               OpDecorate %a Location 0
+               OpDecorate %vo Location 0
+               OpDecorate %vi Location 0
+               OpDecorate %color Location 0
+	       OpDecorate %color RelaxedPrecision
+	       OpDecorate %vi RelaxedPrecision
+               OpDecorate %12 RelaxedPrecision
+               OpDecorate %13 RelaxedPrecision
+
+       %void = OpTypeVoid
+          %3 = OpTypeFunction %void
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+
+%_ptr_Input_float = OpTypePointer Input %float
+          %a = OpVariable %_ptr_Input_float Input
+%_ptr_Output_float = OpTypePointer Output %float
+         %vo = OpVariable %_ptr_Output_float Output
+         %vi = OpVariable %_ptr_Input_float Input
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+      %color = OpVariable %_ptr_Output_v4float Output
+
+      %mainv = OpFunction %void None %3
+          %5 = OpLabel
+         %11 = OpLoad %float %a
+               OpStore %vo %11
+               OpReturn
+               OpFunctionEnd
+
+      %mainf = OpFunction %void None %3
+          %6 = OpLabel
+         %12 = OpLoad %float %vi
+	 %13 = OpCompositeConstruct %v4float %12 %12 %12 %12
+               OpStore %color %13
+               OpReturn
+               OpFunctionEnd

+ 375 - 0
ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/multiple_same_entry_points_autogen.cpp

@@ -0,0 +1,375 @@
+// GENERATED FILE - DO NOT EDIT.
+// Generated by generate_tests.py
+//
+// 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 "../diff_test_utils.h"
+
+#include "gtest/gtest.h"
+
+namespace spvtools {
+namespace diff {
+namespace {
+
+// Test for multiple entry points with the same execution model.
+constexpr char kSrc[] = R"(               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Vertex %4 "main1" %8 %10
+               OpEntryPoint Vertex %12 "main2" %13 %14 %15
+               OpSource ESSL 310
+               OpName %4 "main1"
+               OpName %12 "main2"
+               OpName %8 "v"
+               OpName %10 "a"
+               OpName %13 "v"
+               OpName %14 "a"
+               OpName %15 "b"
+               OpDecorate %8 Location 0
+               OpDecorate %10 Location 0
+               OpDecorate %13 Location 0
+               OpDecorate %14 Location 0
+               OpDecorate %15 Location 1
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeFloat 32
+
+          %7 = OpTypePointer Output %6
+          %9 = OpTypePointer Input %6
+          %8 = OpVariable %7 Output
+         %10 = OpVariable %9 Input
+         %13 = OpVariable %7 Output
+         %14 = OpVariable %9 Input
+         %15 = OpVariable %9 Input
+
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+         %11 = OpLoad %6 %10
+               OpStore %8 %11
+               OpReturn
+               OpFunctionEnd
+
+         %12 = OpFunction %2 None %3
+         %16 = OpLabel
+         %17 = OpLoad %6 %14
+         %18 = OpLoad %6 %15
+         %19 = OpFAdd %6 %17 %18
+               OpStore %13 %19
+               OpReturn
+               OpFunctionEnd)";
+constexpr char kDst[] = R"(               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Vertex %4 "main2" %13 %14 %15
+               OpEntryPoint Vertex %12 "main1" %8 %10
+               OpSource ESSL 310
+               OpName %12 "main1"
+               OpName %4 "main2"
+               OpName %8 "v"
+               OpName %10 "a"
+               OpName %13 "v"
+               OpName %14 "a"
+               OpName %15 "b"
+               OpDecorate %8 Location 0
+               OpDecorate %10 Location 0
+               OpDecorate %13 Location 0
+               OpDecorate %14 Location 0
+               OpDecorate %15 Location 1
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeFloat 32
+
+          %7 = OpTypePointer Output %6
+          %9 = OpTypePointer Input %6
+          %8 = OpVariable %7 Output
+         %10 = OpVariable %9 Input
+         %13 = OpVariable %7 Output
+         %14 = OpVariable %9 Input
+         %15 = OpVariable %9 Input
+
+         %4 = OpFunction %2 None %3
+         %16 = OpLabel
+         %17 = OpLoad %6 %14
+         %18 = OpLoad %6 %15
+         %19 = OpFAdd %6 %17 %18
+               OpStore %13 %19
+               OpReturn
+               OpFunctionEnd
+
+         %12 = OpFunction %2 None %3
+          %5 = OpLabel
+         %11 = OpLoad %6 %10
+               OpStore %8 %11
+               OpReturn
+               OpFunctionEnd
+)";
+
+TEST(DiffTest, MultipleSameEntryPoints) {
+  constexpr char kDiff[] = R"( ; SPIR-V
+ ; Version: 1.6
+ ; Generator: Khronos SPIR-V Tools Assembler; 0
+ ; Bound: 20
+ ; Schema: 0
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
++OpEntryPoint Vertex %12 "main2" %13 %14 %15
+ OpEntryPoint Vertex %4 "main1" %8 %10
+-OpEntryPoint Vertex %12 "main2" %13 %14 %15
+ OpSource ESSL 310
+ OpName %4 "main1"
+ OpName %12 "main2"
+ OpName %8 "v"
+ OpName %10 "a"
+ OpName %13 "v"
+ OpName %14 "a"
+ OpName %15 "b"
+ OpDecorate %8 Location 0
+ OpDecorate %10 Location 0
+ OpDecorate %13 Location 0
+ OpDecorate %14 Location 0
+ OpDecorate %15 Location 1
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %6 = OpTypeFloat 32
+ %7 = OpTypePointer Output %6
+ %9 = OpTypePointer Input %6
+ %8 = OpVariable %7 Output
+ %10 = OpVariable %9 Input
+ %13 = OpVariable %7 Output
+ %14 = OpVariable %9 Input
+ %15 = OpVariable %9 Input
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ %11 = OpLoad %6 %10
+ OpStore %8 %11
+ OpReturn
+ OpFunctionEnd
+ %12 = OpFunction %2 None %3
+ %16 = OpLabel
+ %17 = OpLoad %6 %14
+ %18 = OpLoad %6 %15
+ %19 = OpFAdd %6 %17 %18
+ OpStore %13 %19
+ OpReturn
+ OpFunctionEnd
+)";
+  Options options;
+  DoStringDiffTest(kSrc, kDst, kDiff, options);
+}
+
+TEST(DiffTest, MultipleSameEntryPointsNoDebug) {
+  constexpr char kSrcNoDebug[] = R"(               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Vertex %4 "main1" %8 %10
+               OpEntryPoint Vertex %12 "main2" %13 %14 %15
+               OpSource ESSL 310
+               OpDecorate %8 Location 0
+               OpDecorate %10 Location 0
+               OpDecorate %13 Location 0
+               OpDecorate %14 Location 0
+               OpDecorate %15 Location 1
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeFloat 32
+
+          %7 = OpTypePointer Output %6
+          %9 = OpTypePointer Input %6
+          %8 = OpVariable %7 Output
+         %10 = OpVariable %9 Input
+         %13 = OpVariable %7 Output
+         %14 = OpVariable %9 Input
+         %15 = OpVariable %9 Input
+
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+         %11 = OpLoad %6 %10
+               OpStore %8 %11
+               OpReturn
+               OpFunctionEnd
+
+         %12 = OpFunction %2 None %3
+         %16 = OpLabel
+         %17 = OpLoad %6 %14
+         %18 = OpLoad %6 %15
+         %19 = OpFAdd %6 %17 %18
+               OpStore %13 %19
+               OpReturn
+               OpFunctionEnd
+)";
+  constexpr char kDstNoDebug[] = R"(               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Vertex %4 "main2" %13 %14 %15
+               OpEntryPoint Vertex %12 "main1" %8 %10
+               OpSource ESSL 310
+               OpDecorate %8 Location 0
+               OpDecorate %10 Location 0
+               OpDecorate %13 Location 0
+               OpDecorate %14 Location 0
+               OpDecorate %15 Location 1
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeFloat 32
+
+          %7 = OpTypePointer Output %6
+          %9 = OpTypePointer Input %6
+          %8 = OpVariable %7 Output
+         %10 = OpVariable %9 Input
+         %13 = OpVariable %7 Output
+         %14 = OpVariable %9 Input
+         %15 = OpVariable %9 Input
+
+         %4 = OpFunction %2 None %3
+         %16 = OpLabel
+         %17 = OpLoad %6 %14
+         %18 = OpLoad %6 %15
+         %19 = OpFAdd %6 %17 %18
+               OpStore %13 %19
+               OpReturn
+               OpFunctionEnd
+
+         %12 = OpFunction %2 None %3
+          %5 = OpLabel
+         %11 = OpLoad %6 %10
+               OpStore %8 %11
+               OpReturn
+               OpFunctionEnd
+)";
+  constexpr char kDiff[] = R"( ; SPIR-V
+ ; Version: 1.6
+ ; Generator: Khronos SPIR-V Tools Assembler; 0
+ ; Bound: 20
+ ; Schema: 0
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
++OpEntryPoint Vertex %12 "main2" %13 %14 %15
+ OpEntryPoint Vertex %4 "main1" %8 %10
+-OpEntryPoint Vertex %12 "main2" %13 %14 %15
+ OpSource ESSL 310
+ OpDecorate %8 Location 0
+ OpDecorate %10 Location 0
+ OpDecorate %13 Location 0
+ OpDecorate %14 Location 0
+ OpDecorate %15 Location 1
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %6 = OpTypeFloat 32
+ %7 = OpTypePointer Output %6
+ %9 = OpTypePointer Input %6
+ %8 = OpVariable %7 Output
+ %10 = OpVariable %9 Input
+ %13 = OpVariable %7 Output
+ %14 = OpVariable %9 Input
+ %15 = OpVariable %9 Input
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ %11 = OpLoad %6 %10
+ OpStore %8 %11
+ OpReturn
+ OpFunctionEnd
+ %12 = OpFunction %2 None %3
+ %16 = OpLabel
+ %17 = OpLoad %6 %14
+ %18 = OpLoad %6 %15
+ %19 = OpFAdd %6 %17 %18
+ OpStore %13 %19
+ OpReturn
+ OpFunctionEnd
+)";
+  Options options;
+  DoStringDiffTest(kSrcNoDebug, kDstNoDebug, kDiff, options);
+}
+
+TEST(DiffTest, MultipleSameEntryPointsDumpIds) {
+  constexpr char kDiff[] = R"( ; SPIR-V
+ ; Version: 1.6
+ ; Generator: Khronos SPIR-V Tools Assembler; 0
+ ; Bound: 20
+ ; Schema: 0
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
++OpEntryPoint Vertex %12 "main2" %13 %14 %15
+ OpEntryPoint Vertex %4 "main1" %8 %10
+-OpEntryPoint Vertex %12 "main2" %13 %14 %15
+ OpSource ESSL 310
+ OpName %4 "main1"
+ OpName %12 "main2"
+ OpName %8 "v"
+ OpName %10 "a"
+ OpName %13 "v"
+ OpName %14 "a"
+ OpName %15 "b"
+ OpDecorate %8 Location 0
+ OpDecorate %10 Location 0
+ OpDecorate %13 Location 0
+ OpDecorate %14 Location 0
+ OpDecorate %15 Location 1
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %6 = OpTypeFloat 32
+ %7 = OpTypePointer Output %6
+ %9 = OpTypePointer Input %6
+ %8 = OpVariable %7 Output
+ %10 = OpVariable %9 Input
+ %13 = OpVariable %7 Output
+ %14 = OpVariable %9 Input
+ %15 = OpVariable %9 Input
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ %11 = OpLoad %6 %10
+ OpStore %8 %11
+ OpReturn
+ OpFunctionEnd
+ %12 = OpFunction %2 None %3
+ %16 = OpLabel
+ %17 = OpLoad %6 %14
+ %18 = OpLoad %6 %15
+ %19 = OpFAdd %6 %17 %18
+ OpStore %13 %19
+ OpReturn
+ OpFunctionEnd
+ Src ->  Dst
+   1 ->    1 [ExtInstImport]
+   2 ->    2 [TypeVoid]
+   3 ->    3 [TypeFunction]
+   4 ->   12 [Function]
+   5 ->    5 [Label]
+   6 ->    6 [TypeFloat]
+   7 ->    7 [TypePointer]
+   8 ->    8 [Variable]
+   9 ->    9 [TypePointer]
+  10 ->   10 [Variable]
+  11 ->   11 [Load]
+  12 ->    4 [Function]
+  13 ->   13 [Variable]
+  14 ->   14 [Variable]
+  15 ->   15 [Variable]
+  16 ->   16 [Label]
+  17 ->   17 [Load]
+  18 ->   18 [Load]
+  19 ->   19 [FAdd]
+)";
+  Options options;
+  options.dump_id_map = true;
+  DoStringDiffTest(kSrc, kDst, kDiff, options);
+}
+
+}  // namespace
+}  // namespace diff
+}  // namespace spvtools

+ 45 - 0
ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/multiple_same_entry_points_dst.spvasm

@@ -0,0 +1,45 @@
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Vertex %4 "main2" %13 %14 %15
+               OpEntryPoint Vertex %12 "main1" %8 %10
+               OpSource ESSL 310
+               OpName %12 "main1"
+               OpName %4 "main2"
+               OpName %8 "v"
+               OpName %10 "a"
+               OpName %13 "v"
+               OpName %14 "a"
+               OpName %15 "b"
+               OpDecorate %8 Location 0
+               OpDecorate %10 Location 0
+               OpDecorate %13 Location 0
+               OpDecorate %14 Location 0
+               OpDecorate %15 Location 1
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeFloat 32
+
+          %7 = OpTypePointer Output %6
+          %9 = OpTypePointer Input %6
+          %8 = OpVariable %7 Output
+         %10 = OpVariable %9 Input
+         %13 = OpVariable %7 Output
+         %14 = OpVariable %9 Input
+         %15 = OpVariable %9 Input
+
+         %4 = OpFunction %2 None %3
+         %16 = OpLabel
+         %17 = OpLoad %6 %14
+         %18 = OpLoad %6 %15
+         %19 = OpFAdd %6 %17 %18
+               OpStore %13 %19
+               OpReturn
+               OpFunctionEnd
+
+         %12 = OpFunction %2 None %3
+          %5 = OpLabel
+         %11 = OpLoad %6 %10
+               OpStore %8 %11
+               OpReturn
+               OpFunctionEnd

+ 46 - 0
ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/multiple_same_entry_points_src.spvasm

@@ -0,0 +1,46 @@
+;; Test for multiple entry points with the same execution model.
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Vertex %4 "main1" %8 %10
+               OpEntryPoint Vertex %12 "main2" %13 %14 %15
+               OpSource ESSL 310
+               OpName %4 "main1"
+               OpName %12 "main2"
+               OpName %8 "v"
+               OpName %10 "a"
+               OpName %13 "v"
+               OpName %14 "a"
+               OpName %15 "b"
+               OpDecorate %8 Location 0
+               OpDecorate %10 Location 0
+               OpDecorate %13 Location 0
+               OpDecorate %14 Location 0
+               OpDecorate %15 Location 1
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeFloat 32
+
+          %7 = OpTypePointer Output %6
+          %9 = OpTypePointer Input %6
+          %8 = OpVariable %7 Output
+         %10 = OpVariable %9 Input
+         %13 = OpVariable %7 Output
+         %14 = OpVariable %9 Input
+         %15 = OpVariable %9 Input
+
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+         %11 = OpLoad %6 %10
+               OpStore %8 %11
+               OpReturn
+               OpFunctionEnd
+
+         %12 = OpFunction %2 None %3
+         %16 = OpLabel
+         %17 = OpLoad %6 %14
+         %18 = OpLoad %6 %15
+         %19 = OpFAdd %6 %17 %18
+               OpStore %13 %19
+               OpReturn
+               OpFunctionEnd

+ 568 - 0
ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/reordered_if_blocks_autogen.cpp

@@ -0,0 +1,568 @@
+// GENERATED FILE - DO NOT EDIT.
+// Generated by generate_tests.py
+//
+// 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 "../diff_test_utils.h"
+
+#include "gtest/gtest.h"
+
+namespace spvtools {
+namespace diff {
+namespace {
+
+// Test where src and dst have the true and false blocks of an if reordered.
+constexpr char kSrc[] = R"(               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %4 "main" %8 %44
+               OpExecutionMode %4 OriginUpperLeft
+               OpSource ESSL 310
+               OpName %4 "main"
+               OpName %8 "v"
+               OpName %44 "color"
+               OpDecorate %8 RelaxedPrecision
+               OpDecorate %8 Location 0
+               OpDecorate %9 RelaxedPrecision
+               OpDecorate %18 RelaxedPrecision
+               OpDecorate %19 RelaxedPrecision
+               OpDecorate %20 RelaxedPrecision
+               OpDecorate %23 RelaxedPrecision
+               OpDecorate %24 RelaxedPrecision
+               OpDecorate %25 RelaxedPrecision
+               OpDecorate %26 RelaxedPrecision
+               OpDecorate %27 RelaxedPrecision
+               OpDecorate %28 RelaxedPrecision
+               OpDecorate %29 RelaxedPrecision
+               OpDecorate %30 RelaxedPrecision
+               OpDecorate %31 RelaxedPrecision
+               OpDecorate %33 RelaxedPrecision
+               OpDecorate %34 RelaxedPrecision
+               OpDecorate %35 RelaxedPrecision
+               OpDecorate %36 RelaxedPrecision
+               OpDecorate %37 RelaxedPrecision
+               OpDecorate %39 RelaxedPrecision
+               OpDecorate %40 RelaxedPrecision
+               OpDecorate %41 RelaxedPrecision
+               OpDecorate %42 RelaxedPrecision
+               OpDecorate %44 RelaxedPrecision
+               OpDecorate %44 Location 0
+               OpDecorate %45 RelaxedPrecision
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeFloat 32
+          %7 = OpTypePointer Input %6
+          %8 = OpVariable %7 Input
+         %10 = OpConstant %6 0
+         %11 = OpTypeBool
+         %15 = OpTypeVector %6 4
+         %16 = OpTypePointer Function %15
+         %21 = OpConstant %6 -0.5
+         %22 = OpConstant %6 -0.300000012
+         %38 = OpConstant %6 0.5
+         %43 = OpTypePointer Output %15
+         %44 = OpVariable %43 Output
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+          %9 = OpLoad %6 %8
+         %12 = OpFOrdLessThanEqual %11 %9 %10
+               OpSelectionMerge %14 None
+               OpBranchConditional %12 %13 %32
+         %13 = OpLabel
+         %18 = OpLoad %6 %8
+         %19 = OpExtInst %6 %1 Log %18
+         %20 = OpLoad %6 %8
+         %23 = OpExtInst %6 %1 FClamp %20 %21 %22
+         %24 = OpFMul %6 %19 %23
+         %25 = OpLoad %6 %8
+         %26 = OpExtInst %6 %1 Sin %25
+         %27 = OpLoad %6 %8
+         %28 = OpExtInst %6 %1 Cos %27
+         %29 = OpLoad %6 %8
+         %30 = OpExtInst %6 %1 Exp %29
+         %31 = OpCompositeConstruct %15 %24 %26 %28 %30
+               OpBranch %14
+         %32 = OpLabel
+         %33 = OpLoad %6 %8
+         %34 = OpExtInst %6 %1 Sqrt %33
+         %35 = OpLoad %6 %8
+         %36 = OpExtInst %6 %1 FSign %35
+         %37 = OpLoad %6 %8
+         %39 = OpExtInst %6 %1 FMax %37 %38
+         %40 = OpLoad %6 %8
+         %41 = OpExtInst %6 %1 Floor %40
+         %42 = OpCompositeConstruct %15 %34 %36 %39 %41
+               OpBranch %14
+         %14 = OpLabel
+         %45 = OpPhi %15 %31 %13 %42 %32
+               OpStore %44 %45
+               OpReturn
+               OpFunctionEnd)";
+constexpr char kDst[] = R"(               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %4 "main" %8 %44
+               OpExecutionMode %4 OriginUpperLeft
+               OpSource ESSL 310
+               OpName %4 "main"
+               OpName %8 "v"
+               OpName %44 "color"
+               OpDecorate %8 RelaxedPrecision
+               OpDecorate %8 Location 0
+               OpDecorate %9 RelaxedPrecision
+               OpDecorate %18 RelaxedPrecision
+               OpDecorate %19 RelaxedPrecision
+               OpDecorate %20 RelaxedPrecision
+               OpDecorate %21 RelaxedPrecision
+               OpDecorate %22 RelaxedPrecision
+               OpDecorate %24 RelaxedPrecision
+               OpDecorate %25 RelaxedPrecision
+               OpDecorate %26 RelaxedPrecision
+               OpDecorate %27 RelaxedPrecision
+               OpDecorate %29 RelaxedPrecision
+               OpDecorate %30 RelaxedPrecision
+               OpDecorate %31 RelaxedPrecision
+               OpDecorate %34 RelaxedPrecision
+               OpDecorate %35 RelaxedPrecision
+               OpDecorate %36 RelaxedPrecision
+               OpDecorate %37 RelaxedPrecision
+               OpDecorate %38 RelaxedPrecision
+               OpDecorate %39 RelaxedPrecision
+               OpDecorate %40 RelaxedPrecision
+               OpDecorate %41 RelaxedPrecision
+               OpDecorate %42 RelaxedPrecision
+               OpDecorate %44 RelaxedPrecision
+               OpDecorate %44 Location 0
+               OpDecorate %45 RelaxedPrecision
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeFloat 32
+          %7 = OpTypePointer Input %6
+          %8 = OpVariable %7 Input
+         %10 = OpConstant %6 0
+         %11 = OpTypeBool
+         %15 = OpTypeVector %6 4
+         %16 = OpTypePointer Function %15
+         %23 = OpConstant %6 0.5
+         %32 = OpConstant %6 -0.5
+         %33 = OpConstant %6 -0.300000012
+         %43 = OpTypePointer Output %15
+         %44 = OpVariable %43 Output
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+          %9 = OpLoad %6 %8
+         %12 = OpFOrdLessThanEqual %11 %9 %10
+               OpSelectionMerge %14 None
+               OpBranchConditional %12 %28 %13
+         %13 = OpLabel
+         %18 = OpLoad %6 %8
+         %19 = OpExtInst %6 %1 Sqrt %18
+         %20 = OpLoad %6 %8
+         %21 = OpExtInst %6 %1 FSign %20
+         %22 = OpLoad %6 %8
+         %24 = OpExtInst %6 %1 FMax %22 %23
+         %25 = OpLoad %6 %8
+         %26 = OpExtInst %6 %1 Floor %25
+         %27 = OpCompositeConstruct %15 %19 %21 %24 %26
+               OpBranch %14
+         %28 = OpLabel
+         %29 = OpLoad %6 %8
+         %30 = OpExtInst %6 %1 Log %29
+         %31 = OpLoad %6 %8
+         %34 = OpExtInst %6 %1 FClamp %31 %32 %33
+         %35 = OpFMul %6 %30 %34
+         %36 = OpLoad %6 %8
+         %37 = OpExtInst %6 %1 Sin %36
+         %38 = OpLoad %6 %8
+         %39 = OpExtInst %6 %1 Cos %38
+         %40 = OpLoad %6 %8
+         %41 = OpExtInst %6 %1 Exp %40
+         %42 = OpCompositeConstruct %15 %35 %37 %39 %41
+               OpBranch %14
+         %14 = OpLabel
+         %45 = OpPhi %15 %27 %13 %42 %28
+               OpStore %44 %45
+               OpReturn
+               OpFunctionEnd
+
+)";
+
+TEST(DiffTest, ReorderedIfBlocks) {
+  constexpr char kDiff[] = R"( ; SPIR-V
+ ; Version: 1.6
+ ; Generator: Khronos SPIR-V Tools Assembler; 0
+-; Bound: 46
++; Bound: 47
+ ; Schema: 0
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main" %8 %44
+ OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 310
+ OpName %4 "main"
+ OpName %8 "v"
+ OpName %44 "color"
+ OpDecorate %8 RelaxedPrecision
+ OpDecorate %8 Location 0
+ OpDecorate %9 RelaxedPrecision
+ OpDecorate %18 RelaxedPrecision
+ OpDecorate %19 RelaxedPrecision
+ OpDecorate %20 RelaxedPrecision
+ OpDecorate %23 RelaxedPrecision
+ OpDecorate %24 RelaxedPrecision
+ OpDecorate %25 RelaxedPrecision
+ OpDecorate %26 RelaxedPrecision
+ OpDecorate %27 RelaxedPrecision
+ OpDecorate %28 RelaxedPrecision
+ OpDecorate %29 RelaxedPrecision
+ OpDecorate %30 RelaxedPrecision
+ OpDecorate %31 RelaxedPrecision
+ OpDecorate %33 RelaxedPrecision
+ OpDecorate %34 RelaxedPrecision
+ OpDecorate %35 RelaxedPrecision
+ OpDecorate %36 RelaxedPrecision
+ OpDecorate %37 RelaxedPrecision
+ OpDecorate %39 RelaxedPrecision
+ OpDecorate %40 RelaxedPrecision
+ OpDecorate %41 RelaxedPrecision
+ OpDecorate %42 RelaxedPrecision
+ OpDecorate %44 RelaxedPrecision
+ OpDecorate %44 Location 0
+ OpDecorate %45 RelaxedPrecision
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %6 = OpTypeFloat 32
+ %7 = OpTypePointer Input %6
+ %8 = OpVariable %7 Input
+ %10 = OpConstant %6 0
+ %11 = OpTypeBool
+ %15 = OpTypeVector %6 4
+ %16 = OpTypePointer Function %15
+ %21 = OpConstant %6 -0.5
+ %22 = OpConstant %6 -0.300000012
+ %38 = OpConstant %6 0.5
+ %43 = OpTypePointer Output %15
+ %44 = OpVariable %43 Output
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ %9 = OpLoad %6 %8
+ %12 = OpFOrdLessThanEqual %11 %9 %10
+ OpSelectionMerge %14 None
+ OpBranchConditional %12 %13 %32
+ %32 = OpLabel
+ %33 = OpLoad %6 %8
+ %34 = OpExtInst %6 %1 Sqrt %33
+ %35 = OpLoad %6 %8
+ %36 = OpExtInst %6 %1 FSign %35
+ %37 = OpLoad %6 %8
+ %39 = OpExtInst %6 %1 FMax %37 %38
+ %40 = OpLoad %6 %8
+ %41 = OpExtInst %6 %1 Floor %40
+ %42 = OpCompositeConstruct %15 %34 %36 %39 %41
+ OpBranch %14
+ %13 = OpLabel
+ %18 = OpLoad %6 %8
+ %19 = OpExtInst %6 %1 Log %18
+ %20 = OpLoad %6 %8
+ %23 = OpExtInst %6 %1 FClamp %20 %21 %22
+ %24 = OpFMul %6 %19 %23
+ %25 = OpLoad %6 %8
+ %26 = OpExtInst %6 %1 Sin %25
+ %27 = OpLoad %6 %8
+ %28 = OpExtInst %6 %1 Cos %27
+ %29 = OpLoad %6 %8
+ %30 = OpExtInst %6 %1 Exp %29
+ %31 = OpCompositeConstruct %15 %24 %26 %28 %30
+ OpBranch %14
+ %14 = OpLabel
+-%45 = OpPhi %15 %31 %13 %42 %32
++%45 = OpPhi %15 %42 %32 %31 %13
+ OpStore %44 %45
+ OpReturn
+ OpFunctionEnd
+)";
+  Options options;
+  DoStringDiffTest(kSrc, kDst, kDiff, options);
+}
+
+TEST(DiffTest, ReorderedIfBlocksNoDebug) {
+  constexpr char kSrcNoDebug[] = R"(               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %4 "main" %8 %44
+               OpExecutionMode %4 OriginUpperLeft
+               OpSource ESSL 310
+               OpDecorate %8 RelaxedPrecision
+               OpDecorate %8 Location 0
+               OpDecorate %9 RelaxedPrecision
+               OpDecorate %18 RelaxedPrecision
+               OpDecorate %19 RelaxedPrecision
+               OpDecorate %20 RelaxedPrecision
+               OpDecorate %23 RelaxedPrecision
+               OpDecorate %24 RelaxedPrecision
+               OpDecorate %25 RelaxedPrecision
+               OpDecorate %26 RelaxedPrecision
+               OpDecorate %27 RelaxedPrecision
+               OpDecorate %28 RelaxedPrecision
+               OpDecorate %29 RelaxedPrecision
+               OpDecorate %30 RelaxedPrecision
+               OpDecorate %31 RelaxedPrecision
+               OpDecorate %33 RelaxedPrecision
+               OpDecorate %34 RelaxedPrecision
+               OpDecorate %35 RelaxedPrecision
+               OpDecorate %36 RelaxedPrecision
+               OpDecorate %37 RelaxedPrecision
+               OpDecorate %39 RelaxedPrecision
+               OpDecorate %40 RelaxedPrecision
+               OpDecorate %41 RelaxedPrecision
+               OpDecorate %42 RelaxedPrecision
+               OpDecorate %44 RelaxedPrecision
+               OpDecorate %44 Location 0
+               OpDecorate %45 RelaxedPrecision
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeFloat 32
+          %7 = OpTypePointer Input %6
+          %8 = OpVariable %7 Input
+         %10 = OpConstant %6 0
+         %11 = OpTypeBool
+         %15 = OpTypeVector %6 4
+         %16 = OpTypePointer Function %15
+         %21 = OpConstant %6 -0.5
+         %22 = OpConstant %6 -0.300000012
+         %38 = OpConstant %6 0.5
+         %43 = OpTypePointer Output %15
+         %44 = OpVariable %43 Output
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+          %9 = OpLoad %6 %8
+         %12 = OpFOrdLessThanEqual %11 %9 %10
+               OpSelectionMerge %14 None
+               OpBranchConditional %12 %13 %32
+         %13 = OpLabel
+         %18 = OpLoad %6 %8
+         %19 = OpExtInst %6 %1 Log %18
+         %20 = OpLoad %6 %8
+         %23 = OpExtInst %6 %1 FClamp %20 %21 %22
+         %24 = OpFMul %6 %19 %23
+         %25 = OpLoad %6 %8
+         %26 = OpExtInst %6 %1 Sin %25
+         %27 = OpLoad %6 %8
+         %28 = OpExtInst %6 %1 Cos %27
+         %29 = OpLoad %6 %8
+         %30 = OpExtInst %6 %1 Exp %29
+         %31 = OpCompositeConstruct %15 %24 %26 %28 %30
+               OpBranch %14
+         %32 = OpLabel
+         %33 = OpLoad %6 %8
+         %34 = OpExtInst %6 %1 Sqrt %33
+         %35 = OpLoad %6 %8
+         %36 = OpExtInst %6 %1 FSign %35
+         %37 = OpLoad %6 %8
+         %39 = OpExtInst %6 %1 FMax %37 %38
+         %40 = OpLoad %6 %8
+         %41 = OpExtInst %6 %1 Floor %40
+         %42 = OpCompositeConstruct %15 %34 %36 %39 %41
+               OpBranch %14
+         %14 = OpLabel
+         %45 = OpPhi %15 %31 %13 %42 %32
+               OpStore %44 %45
+               OpReturn
+               OpFunctionEnd
+)";
+  constexpr char kDstNoDebug[] = R"(               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %4 "main" %8 %44
+               OpExecutionMode %4 OriginUpperLeft
+               OpSource ESSL 310
+               OpDecorate %8 RelaxedPrecision
+               OpDecorate %8 Location 0
+               OpDecorate %9 RelaxedPrecision
+               OpDecorate %18 RelaxedPrecision
+               OpDecorate %19 RelaxedPrecision
+               OpDecorate %20 RelaxedPrecision
+               OpDecorate %21 RelaxedPrecision
+               OpDecorate %22 RelaxedPrecision
+               OpDecorate %24 RelaxedPrecision
+               OpDecorate %25 RelaxedPrecision
+               OpDecorate %26 RelaxedPrecision
+               OpDecorate %27 RelaxedPrecision
+               OpDecorate %29 RelaxedPrecision
+               OpDecorate %30 RelaxedPrecision
+               OpDecorate %31 RelaxedPrecision
+               OpDecorate %34 RelaxedPrecision
+               OpDecorate %35 RelaxedPrecision
+               OpDecorate %36 RelaxedPrecision
+               OpDecorate %37 RelaxedPrecision
+               OpDecorate %38 RelaxedPrecision
+               OpDecorate %39 RelaxedPrecision
+               OpDecorate %40 RelaxedPrecision
+               OpDecorate %41 RelaxedPrecision
+               OpDecorate %42 RelaxedPrecision
+               OpDecorate %44 RelaxedPrecision
+               OpDecorate %44 Location 0
+               OpDecorate %45 RelaxedPrecision
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeFloat 32
+          %7 = OpTypePointer Input %6
+          %8 = OpVariable %7 Input
+         %10 = OpConstant %6 0
+         %11 = OpTypeBool
+         %15 = OpTypeVector %6 4
+         %16 = OpTypePointer Function %15
+         %23 = OpConstant %6 0.5
+         %32 = OpConstant %6 -0.5
+         %33 = OpConstant %6 -0.300000012
+         %43 = OpTypePointer Output %15
+         %44 = OpVariable %43 Output
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+          %9 = OpLoad %6 %8
+         %12 = OpFOrdLessThanEqual %11 %9 %10
+               OpSelectionMerge %14 None
+               OpBranchConditional %12 %28 %13
+         %13 = OpLabel
+         %18 = OpLoad %6 %8
+         %19 = OpExtInst %6 %1 Sqrt %18
+         %20 = OpLoad %6 %8
+         %21 = OpExtInst %6 %1 FSign %20
+         %22 = OpLoad %6 %8
+         %24 = OpExtInst %6 %1 FMax %22 %23
+         %25 = OpLoad %6 %8
+         %26 = OpExtInst %6 %1 Floor %25
+         %27 = OpCompositeConstruct %15 %19 %21 %24 %26
+               OpBranch %14
+         %28 = OpLabel
+         %29 = OpLoad %6 %8
+         %30 = OpExtInst %6 %1 Log %29
+         %31 = OpLoad %6 %8
+         %34 = OpExtInst %6 %1 FClamp %31 %32 %33
+         %35 = OpFMul %6 %30 %34
+         %36 = OpLoad %6 %8
+         %37 = OpExtInst %6 %1 Sin %36
+         %38 = OpLoad %6 %8
+         %39 = OpExtInst %6 %1 Cos %38
+         %40 = OpLoad %6 %8
+         %41 = OpExtInst %6 %1 Exp %40
+         %42 = OpCompositeConstruct %15 %35 %37 %39 %41
+               OpBranch %14
+         %14 = OpLabel
+         %45 = OpPhi %15 %27 %13 %42 %28
+               OpStore %44 %45
+               OpReturn
+               OpFunctionEnd
+
+)";
+  constexpr char kDiff[] = R"( ; SPIR-V
+ ; Version: 1.6
+ ; Generator: Khronos SPIR-V Tools Assembler; 0
+-; Bound: 46
++; Bound: 47
+ ; Schema: 0
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main" %8 %44
+ OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 310
+ OpDecorate %8 RelaxedPrecision
+ OpDecorate %8 Location 0
+ OpDecorate %9 RelaxedPrecision
+ OpDecorate %18 RelaxedPrecision
+ OpDecorate %19 RelaxedPrecision
+ OpDecorate %20 RelaxedPrecision
+ OpDecorate %23 RelaxedPrecision
+ OpDecorate %24 RelaxedPrecision
+ OpDecorate %25 RelaxedPrecision
+ OpDecorate %26 RelaxedPrecision
+ OpDecorate %27 RelaxedPrecision
+ OpDecorate %28 RelaxedPrecision
+ OpDecorate %29 RelaxedPrecision
+ OpDecorate %30 RelaxedPrecision
+ OpDecorate %31 RelaxedPrecision
+ OpDecorate %33 RelaxedPrecision
+ OpDecorate %34 RelaxedPrecision
+ OpDecorate %35 RelaxedPrecision
+ OpDecorate %36 RelaxedPrecision
+ OpDecorate %37 RelaxedPrecision
+ OpDecorate %39 RelaxedPrecision
+ OpDecorate %40 RelaxedPrecision
+ OpDecorate %41 RelaxedPrecision
+ OpDecorate %42 RelaxedPrecision
+ OpDecorate %44 RelaxedPrecision
+ OpDecorate %44 Location 0
+ OpDecorate %45 RelaxedPrecision
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %6 = OpTypeFloat 32
+ %7 = OpTypePointer Input %6
+ %8 = OpVariable %7 Input
+ %10 = OpConstant %6 0
+ %11 = OpTypeBool
+ %15 = OpTypeVector %6 4
+ %16 = OpTypePointer Function %15
+ %21 = OpConstant %6 -0.5
+ %22 = OpConstant %6 -0.300000012
+ %38 = OpConstant %6 0.5
+ %43 = OpTypePointer Output %15
+ %44 = OpVariable %43 Output
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ %9 = OpLoad %6 %8
+ %12 = OpFOrdLessThanEqual %11 %9 %10
+ OpSelectionMerge %14 None
+ OpBranchConditional %12 %13 %32
+ %32 = OpLabel
+ %33 = OpLoad %6 %8
+ %34 = OpExtInst %6 %1 Sqrt %33
+ %35 = OpLoad %6 %8
+ %36 = OpExtInst %6 %1 FSign %35
+ %37 = OpLoad %6 %8
+ %39 = OpExtInst %6 %1 FMax %37 %38
+ %40 = OpLoad %6 %8
+ %41 = OpExtInst %6 %1 Floor %40
+ %42 = OpCompositeConstruct %15 %34 %36 %39 %41
+ OpBranch %14
+ %13 = OpLabel
+ %18 = OpLoad %6 %8
+ %19 = OpExtInst %6 %1 Log %18
+ %20 = OpLoad %6 %8
+ %23 = OpExtInst %6 %1 FClamp %20 %21 %22
+ %24 = OpFMul %6 %19 %23
+ %25 = OpLoad %6 %8
+ %26 = OpExtInst %6 %1 Sin %25
+ %27 = OpLoad %6 %8
+ %28 = OpExtInst %6 %1 Cos %27
+ %29 = OpLoad %6 %8
+ %30 = OpExtInst %6 %1 Exp %29
+ %31 = OpCompositeConstruct %15 %24 %26 %28 %30
+ OpBranch %14
+ %14 = OpLabel
+-%45 = OpPhi %15 %31 %13 %42 %32
++%45 = OpPhi %15 %42 %32 %31 %13
+ OpStore %44 %45
+ OpReturn
+ OpFunctionEnd
+)";
+  Options options;
+  DoStringDiffTest(kSrcNoDebug, kDstNoDebug, kDiff, options);
+}
+
+}  // namespace
+}  // namespace diff
+}  // namespace spvtools

+ 87 - 0
ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/reordered_if_blocks_dst.spvasm

@@ -0,0 +1,87 @@
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %4 "main" %8 %44
+               OpExecutionMode %4 OriginUpperLeft
+               OpSource ESSL 310
+               OpName %4 "main"
+               OpName %8 "v"
+               OpName %44 "color"
+               OpDecorate %8 RelaxedPrecision
+               OpDecorate %8 Location 0
+               OpDecorate %9 RelaxedPrecision
+               OpDecorate %18 RelaxedPrecision
+               OpDecorate %19 RelaxedPrecision
+               OpDecorate %20 RelaxedPrecision
+               OpDecorate %21 RelaxedPrecision
+               OpDecorate %22 RelaxedPrecision
+               OpDecorate %24 RelaxedPrecision
+               OpDecorate %25 RelaxedPrecision
+               OpDecorate %26 RelaxedPrecision
+               OpDecorate %27 RelaxedPrecision
+               OpDecorate %29 RelaxedPrecision
+               OpDecorate %30 RelaxedPrecision
+               OpDecorate %31 RelaxedPrecision
+               OpDecorate %34 RelaxedPrecision
+               OpDecorate %35 RelaxedPrecision
+               OpDecorate %36 RelaxedPrecision
+               OpDecorate %37 RelaxedPrecision
+               OpDecorate %38 RelaxedPrecision
+               OpDecorate %39 RelaxedPrecision
+               OpDecorate %40 RelaxedPrecision
+               OpDecorate %41 RelaxedPrecision
+               OpDecorate %42 RelaxedPrecision
+               OpDecorate %44 RelaxedPrecision
+               OpDecorate %44 Location 0
+               OpDecorate %45 RelaxedPrecision
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeFloat 32
+          %7 = OpTypePointer Input %6
+          %8 = OpVariable %7 Input
+         %10 = OpConstant %6 0
+         %11 = OpTypeBool
+         %15 = OpTypeVector %6 4
+         %16 = OpTypePointer Function %15
+         %23 = OpConstant %6 0.5
+         %32 = OpConstant %6 -0.5
+         %33 = OpConstant %6 -0.300000012
+         %43 = OpTypePointer Output %15
+         %44 = OpVariable %43 Output
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+          %9 = OpLoad %6 %8
+         %12 = OpFOrdLessThanEqual %11 %9 %10
+               OpSelectionMerge %14 None
+               OpBranchConditional %12 %28 %13
+         %13 = OpLabel
+         %18 = OpLoad %6 %8
+         %19 = OpExtInst %6 %1 Sqrt %18
+         %20 = OpLoad %6 %8
+         %21 = OpExtInst %6 %1 FSign %20
+         %22 = OpLoad %6 %8
+         %24 = OpExtInst %6 %1 FMax %22 %23
+         %25 = OpLoad %6 %8
+         %26 = OpExtInst %6 %1 Floor %25
+         %27 = OpCompositeConstruct %15 %19 %21 %24 %26
+               OpBranch %14
+         %28 = OpLabel
+         %29 = OpLoad %6 %8
+         %30 = OpExtInst %6 %1 Log %29
+         %31 = OpLoad %6 %8
+         %34 = OpExtInst %6 %1 FClamp %31 %32 %33
+         %35 = OpFMul %6 %30 %34
+         %36 = OpLoad %6 %8
+         %37 = OpExtInst %6 %1 Sin %36
+         %38 = OpLoad %6 %8
+         %39 = OpExtInst %6 %1 Cos %38
+         %40 = OpLoad %6 %8
+         %41 = OpExtInst %6 %1 Exp %40
+         %42 = OpCompositeConstruct %15 %35 %37 %39 %41
+               OpBranch %14
+         %14 = OpLabel
+         %45 = OpPhi %15 %27 %13 %42 %28
+               OpStore %44 %45
+               OpReturn
+               OpFunctionEnd
+

+ 87 - 0
ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/reordered_if_blocks_src.spvasm

@@ -0,0 +1,87 @@
+;; Test where src and dst have the true and false blocks of an if reordered.
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %4 "main" %8 %44
+               OpExecutionMode %4 OriginUpperLeft
+               OpSource ESSL 310
+               OpName %4 "main"
+               OpName %8 "v"
+               OpName %44 "color"
+               OpDecorate %8 RelaxedPrecision
+               OpDecorate %8 Location 0
+               OpDecorate %9 RelaxedPrecision
+               OpDecorate %18 RelaxedPrecision
+               OpDecorate %19 RelaxedPrecision
+               OpDecorate %20 RelaxedPrecision
+               OpDecorate %23 RelaxedPrecision
+               OpDecorate %24 RelaxedPrecision
+               OpDecorate %25 RelaxedPrecision
+               OpDecorate %26 RelaxedPrecision
+               OpDecorate %27 RelaxedPrecision
+               OpDecorate %28 RelaxedPrecision
+               OpDecorate %29 RelaxedPrecision
+               OpDecorate %30 RelaxedPrecision
+               OpDecorate %31 RelaxedPrecision
+               OpDecorate %33 RelaxedPrecision
+               OpDecorate %34 RelaxedPrecision
+               OpDecorate %35 RelaxedPrecision
+               OpDecorate %36 RelaxedPrecision
+               OpDecorate %37 RelaxedPrecision
+               OpDecorate %39 RelaxedPrecision
+               OpDecorate %40 RelaxedPrecision
+               OpDecorate %41 RelaxedPrecision
+               OpDecorate %42 RelaxedPrecision
+               OpDecorate %44 RelaxedPrecision
+               OpDecorate %44 Location 0
+               OpDecorate %45 RelaxedPrecision
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeFloat 32
+          %7 = OpTypePointer Input %6
+          %8 = OpVariable %7 Input
+         %10 = OpConstant %6 0
+         %11 = OpTypeBool
+         %15 = OpTypeVector %6 4
+         %16 = OpTypePointer Function %15
+         %21 = OpConstant %6 -0.5
+         %22 = OpConstant %6 -0.300000012
+         %38 = OpConstant %6 0.5
+         %43 = OpTypePointer Output %15
+         %44 = OpVariable %43 Output
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+          %9 = OpLoad %6 %8
+         %12 = OpFOrdLessThanEqual %11 %9 %10
+               OpSelectionMerge %14 None
+               OpBranchConditional %12 %13 %32
+         %13 = OpLabel
+         %18 = OpLoad %6 %8
+         %19 = OpExtInst %6 %1 Log %18
+         %20 = OpLoad %6 %8
+         %23 = OpExtInst %6 %1 FClamp %20 %21 %22
+         %24 = OpFMul %6 %19 %23
+         %25 = OpLoad %6 %8
+         %26 = OpExtInst %6 %1 Sin %25
+         %27 = OpLoad %6 %8
+         %28 = OpExtInst %6 %1 Cos %27
+         %29 = OpLoad %6 %8
+         %30 = OpExtInst %6 %1 Exp %29
+         %31 = OpCompositeConstruct %15 %24 %26 %28 %30
+               OpBranch %14
+         %32 = OpLabel
+         %33 = OpLoad %6 %8
+         %34 = OpExtInst %6 %1 Sqrt %33
+         %35 = OpLoad %6 %8
+         %36 = OpExtInst %6 %1 FSign %35
+         %37 = OpLoad %6 %8
+         %39 = OpExtInst %6 %1 FMax %37 %38
+         %40 = OpLoad %6 %8
+         %41 = OpExtInst %6 %1 Floor %40
+         %42 = OpCompositeConstruct %15 %34 %36 %39 %41
+               OpBranch %14
+         %14 = OpLabel
+         %45 = OpPhi %15 %31 %13 %42 %32
+               OpStore %44 %45
+               OpReturn
+               OpFunctionEnd

+ 582 - 0
ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/reordered_switch_blocks_autogen.cpp

@@ -0,0 +1,582 @@
+// GENERATED FILE - DO NOT EDIT.
+// Generated by generate_tests.py
+//
+// 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 "../diff_test_utils.h"
+
+#include "gtest/gtest.h"
+
+namespace spvtools {
+namespace diff {
+namespace {
+
+// Test where src and dst have cases of a switch in different order.
+constexpr char kSrc[] = R"(               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %4 "main"
+               OpExecutionMode %4 LocalSize 1 1 1
+               OpSource ESSL 310
+               OpName %4 "main"
+               OpName %7 "BufferIn"
+               OpMemberName %7 0 "i"
+               OpName %9 ""
+               OpName %23 "BufferOut"
+               OpMemberName %23 0 "o"
+               OpName %25 ""
+               OpMemberDecorate %7 0 Offset 0
+               OpDecorate %7 Block
+               OpDecorate %9 DescriptorSet 0
+               OpDecorate %9 Binding 0
+               OpMemberDecorate %23 0 Offset 0
+               OpDecorate %23 BufferBlock
+               OpDecorate %25 DescriptorSet 0
+               OpDecorate %25 Binding 1
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeInt 32 0
+          %7 = OpTypeStruct %6
+          %8 = OpTypePointer Uniform %7
+          %9 = OpVariable %8 Uniform
+         %10 = OpTypeInt 32 1
+         %11 = OpConstant %10 0
+         %12 = OpTypePointer Uniform %6
+         %23 = OpTypeStruct %6
+         %24 = OpTypePointer Uniform %23
+         %25 = OpVariable %24 Uniform
+         %28 = OpConstant %10 1
+         %34 = OpConstant %6 2
+         %52 = OpConstant %6 1
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+         %13 = OpAccessChain %12 %9 %11
+         %14 = OpLoad %6 %13
+               OpSelectionMerge %22 None
+               OpSwitch %14 %21 0 %15 1 %16 2 %17 3 %18 4 %19 5 %20
+         %21 = OpLabel
+         %54 = OpAccessChain %12 %25 %11
+         %55 = OpLoad %6 %54
+         %56 = OpIAdd %6 %55 %34
+         %57 = OpAccessChain %12 %25 %11
+               OpStore %57 %56
+               OpBranch %22
+         %15 = OpLabel
+         %26 = OpAccessChain %12 %25 %11
+         %27 = OpLoad %6 %26
+         %29 = OpIAdd %6 %27 %28
+               OpStore %26 %29
+               OpBranch %22
+         %16 = OpLabel
+         %31 = OpAccessChain %12 %25 %11
+         %32 = OpLoad %6 %31
+         %33 = OpISub %6 %32 %28
+               OpStore %31 %33
+               OpBranch %17
+         %17 = OpLabel
+         %35 = OpAccessChain %12 %25 %11
+         %36 = OpLoad %6 %35
+         %37 = OpIMul %6 %36 %34
+         %38 = OpAccessChain %12 %25 %11
+               OpStore %38 %37
+               OpBranch %22
+         %18 = OpLabel
+         %40 = OpAccessChain %12 %25 %11
+         %41 = OpLoad %6 %40
+         %42 = OpUDiv %6 %41 %34
+         %43 = OpAccessChain %12 %25 %11
+               OpStore %43 %42
+               OpBranch %22
+         %19 = OpLabel
+         %45 = OpAccessChain %12 %25 %11
+         %46 = OpLoad %6 %45
+         %47 = OpAccessChain %12 %25 %11
+         %48 = OpLoad %6 %47
+         %49 = OpIMul %6 %46 %48
+         %50 = OpAccessChain %12 %25 %11
+               OpStore %50 %49
+               OpBranch %22
+         %20 = OpLabel
+         %53 = OpAccessChain %12 %25 %11
+               OpStore %53 %52
+               OpBranch %21
+         %22 = OpLabel
+               OpReturn
+               OpFunctionEnd)";
+constexpr char kDst[] = R"(               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %4 "main"
+               OpExecutionMode %4 LocalSize 1 1 1
+               OpSource ESSL 310
+               OpName %4 "main"
+               OpName %7 "BufferIn"
+               OpMemberName %7 0 "i"
+               OpName %9 ""
+               OpName %23 "BufferOut"
+               OpMemberName %23 0 "o"
+               OpName %25 ""
+               OpMemberDecorate %7 0 Offset 0
+               OpDecorate %7 Block
+               OpDecorate %9 DescriptorSet 0
+               OpDecorate %9 Binding 0
+               OpMemberDecorate %23 0 Offset 0
+               OpDecorate %23 BufferBlock
+               OpDecorate %25 DescriptorSet 0
+               OpDecorate %25 Binding 1
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeInt 32 0
+          %7 = OpTypeStruct %6
+          %8 = OpTypePointer Uniform %7
+          %9 = OpVariable %8 Uniform
+         %10 = OpTypeInt 32 1
+         %11 = OpConstant %10 0
+         %12 = OpTypePointer Uniform %6
+         %23 = OpTypeStruct %6
+         %24 = OpTypePointer Uniform %23
+         %25 = OpVariable %24 Uniform
+         %28 = OpConstant %10 1
+         %34 = OpConstant %6 2
+         %52 = OpConstant %6 1
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+         %13 = OpAccessChain %12 %9 %11
+         %14 = OpLoad %6 %13
+               OpSelectionMerge %22 None
+               OpSwitch %14 %21 0 %15 1 %16 2 %17 3 %18 4 %19 5 %20
+         %17 = OpLabel
+         %35 = OpAccessChain %12 %25 %11
+         %36 = OpLoad %6 %35
+         %37 = OpIMul %6 %36 %34
+         %38 = OpAccessChain %12 %25 %11
+               OpStore %38 %37
+               OpBranch %22
+         %18 = OpLabel
+         %40 = OpAccessChain %12 %25 %11
+         %41 = OpLoad %6 %40
+         %42 = OpUDiv %6 %41 %34
+         %43 = OpAccessChain %12 %25 %11
+               OpStore %43 %42
+               OpBranch %22
+         %21 = OpLabel
+         %54 = OpAccessChain %12 %25 %11
+         %55 = OpLoad %6 %54
+         %56 = OpIAdd %6 %55 %34
+         %57 = OpAccessChain %12 %25 %11
+               OpStore %57 %56
+               OpBranch %22
+         %20 = OpLabel
+         %53 = OpAccessChain %12 %25 %11
+               OpStore %53 %52
+               OpBranch %21
+         %15 = OpLabel
+         %26 = OpAccessChain %12 %25 %11
+         %27 = OpLoad %6 %26
+         %29 = OpIAdd %6 %27 %28
+               OpStore %26 %29
+               OpBranch %22
+         %19 = OpLabel
+         %45 = OpAccessChain %12 %25 %11
+         %46 = OpLoad %6 %45
+         %47 = OpAccessChain %12 %25 %11
+         %48 = OpLoad %6 %47
+         %49 = OpIMul %6 %46 %48
+         %50 = OpAccessChain %12 %25 %11
+               OpStore %50 %49
+               OpBranch %22
+         %16 = OpLabel
+         %31 = OpAccessChain %12 %25 %11
+         %32 = OpLoad %6 %31
+         %33 = OpISub %6 %32 %28
+               OpStore %31 %33
+               OpBranch %17
+         %22 = OpLabel
+               OpReturn
+               OpFunctionEnd
+)";
+
+TEST(DiffTest, ReorderedSwitchBlocks) {
+  constexpr char kDiff[] = R"( ; SPIR-V
+ ; Version: 1.6
+ ; Generator: Khronos SPIR-V Tools Assembler; 0
+-; Bound: 58
++; Bound: 62
+ ; Schema: 0
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %4 "main"
+ OpExecutionMode %4 LocalSize 1 1 1
+ OpSource ESSL 310
+ OpName %4 "main"
+ OpName %7 "BufferIn"
+ OpMemberName %7 0 "i"
+ OpName %9 ""
+ OpName %23 "BufferOut"
+ OpMemberName %23 0 "o"
+ OpName %25 ""
+ OpMemberDecorate %7 0 Offset 0
+ OpDecorate %7 Block
+ OpDecorate %9 DescriptorSet 0
+ OpDecorate %9 Binding 0
+ OpMemberDecorate %23 0 Offset 0
+ OpDecorate %23 BufferBlock
+ OpDecorate %25 DescriptorSet 0
+ OpDecorate %25 Binding 1
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %6 = OpTypeInt 32 0
+ %7 = OpTypeStruct %6
+ %8 = OpTypePointer Uniform %7
+ %9 = OpVariable %8 Uniform
+ %10 = OpTypeInt 32 1
+ %11 = OpConstant %10 0
+ %12 = OpTypePointer Uniform %6
+ %23 = OpTypeStruct %6
+ %24 = OpTypePointer Uniform %23
+ %25 = OpVariable %24 Uniform
+ %28 = OpConstant %10 1
+ %34 = OpConstant %6 2
+ %52 = OpConstant %6 1
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ %13 = OpAccessChain %12 %9 %11
+ %14 = OpLoad %6 %13
+ OpSelectionMerge %22 None
+ OpSwitch %14 %21 0 %15 1 %16 2 %17 3 %18 4 %19 5 %20
+ %20 = OpLabel
+ %53 = OpAccessChain %12 %25 %11
+ OpStore %53 %52
+ OpBranch %21
+ %19 = OpLabel
+ %45 = OpAccessChain %12 %25 %11
+ %46 = OpLoad %6 %45
+ %47 = OpAccessChain %12 %25 %11
+ %48 = OpLoad %6 %47
+ %49 = OpIMul %6 %46 %48
+ %50 = OpAccessChain %12 %25 %11
+ OpStore %50 %49
+ OpBranch %22
+ %18 = OpLabel
+ %40 = OpAccessChain %12 %25 %11
+ %41 = OpLoad %6 %40
+ %42 = OpUDiv %6 %41 %34
+ %43 = OpAccessChain %12 %25 %11
+ OpStore %43 %42
+ OpBranch %22
+ %16 = OpLabel
+ %31 = OpAccessChain %12 %25 %11
+ %32 = OpLoad %6 %31
+ %33 = OpISub %6 %32 %28
+ OpStore %31 %33
+ OpBranch %17
+ %17 = OpLabel
+ %35 = OpAccessChain %12 %25 %11
+ %36 = OpLoad %6 %35
+ %37 = OpIMul %6 %36 %34
+ %38 = OpAccessChain %12 %25 %11
+ OpStore %38 %37
+ OpBranch %22
+ %15 = OpLabel
+ %26 = OpAccessChain %12 %25 %11
+ %27 = OpLoad %6 %26
+ %29 = OpIAdd %6 %27 %28
+ OpStore %26 %29
+ OpBranch %22
+ %21 = OpLabel
+ %54 = OpAccessChain %12 %25 %11
+ %55 = OpLoad %6 %54
+ %56 = OpIAdd %6 %55 %34
+ %57 = OpAccessChain %12 %25 %11
+ OpStore %57 %56
+ OpBranch %22
+ %22 = OpLabel
+ OpReturn
+ OpFunctionEnd
+)";
+  Options options;
+  DoStringDiffTest(kSrc, kDst, kDiff, options);
+}
+
+TEST(DiffTest, ReorderedSwitchBlocksNoDebug) {
+  constexpr char kSrcNoDebug[] = R"(               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %4 "main"
+               OpExecutionMode %4 LocalSize 1 1 1
+               OpSource ESSL 310
+               OpMemberDecorate %7 0 Offset 0
+               OpDecorate %7 Block
+               OpDecorate %9 DescriptorSet 0
+               OpDecorate %9 Binding 0
+               OpMemberDecorate %23 0 Offset 0
+               OpDecorate %23 BufferBlock
+               OpDecorate %25 DescriptorSet 0
+               OpDecorate %25 Binding 1
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeInt 32 0
+          %7 = OpTypeStruct %6
+          %8 = OpTypePointer Uniform %7
+          %9 = OpVariable %8 Uniform
+         %10 = OpTypeInt 32 1
+         %11 = OpConstant %10 0
+         %12 = OpTypePointer Uniform %6
+         %23 = OpTypeStruct %6
+         %24 = OpTypePointer Uniform %23
+         %25 = OpVariable %24 Uniform
+         %28 = OpConstant %10 1
+         %34 = OpConstant %6 2
+         %52 = OpConstant %6 1
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+         %13 = OpAccessChain %12 %9 %11
+         %14 = OpLoad %6 %13
+               OpSelectionMerge %22 None
+               OpSwitch %14 %21 0 %15 1 %16 2 %17 3 %18 4 %19 5 %20
+         %21 = OpLabel
+         %54 = OpAccessChain %12 %25 %11
+         %55 = OpLoad %6 %54
+         %56 = OpIAdd %6 %55 %34
+         %57 = OpAccessChain %12 %25 %11
+               OpStore %57 %56
+               OpBranch %22
+         %15 = OpLabel
+         %26 = OpAccessChain %12 %25 %11
+         %27 = OpLoad %6 %26
+         %29 = OpIAdd %6 %27 %28
+               OpStore %26 %29
+               OpBranch %22
+         %16 = OpLabel
+         %31 = OpAccessChain %12 %25 %11
+         %32 = OpLoad %6 %31
+         %33 = OpISub %6 %32 %28
+               OpStore %31 %33
+               OpBranch %17
+         %17 = OpLabel
+         %35 = OpAccessChain %12 %25 %11
+         %36 = OpLoad %6 %35
+         %37 = OpIMul %6 %36 %34
+         %38 = OpAccessChain %12 %25 %11
+               OpStore %38 %37
+               OpBranch %22
+         %18 = OpLabel
+         %40 = OpAccessChain %12 %25 %11
+         %41 = OpLoad %6 %40
+         %42 = OpUDiv %6 %41 %34
+         %43 = OpAccessChain %12 %25 %11
+               OpStore %43 %42
+               OpBranch %22
+         %19 = OpLabel
+         %45 = OpAccessChain %12 %25 %11
+         %46 = OpLoad %6 %45
+         %47 = OpAccessChain %12 %25 %11
+         %48 = OpLoad %6 %47
+         %49 = OpIMul %6 %46 %48
+         %50 = OpAccessChain %12 %25 %11
+               OpStore %50 %49
+               OpBranch %22
+         %20 = OpLabel
+         %53 = OpAccessChain %12 %25 %11
+               OpStore %53 %52
+               OpBranch %21
+         %22 = OpLabel
+               OpReturn
+               OpFunctionEnd
+)";
+  constexpr char kDstNoDebug[] = R"(               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %4 "main"
+               OpExecutionMode %4 LocalSize 1 1 1
+               OpSource ESSL 310
+               OpMemberDecorate %7 0 Offset 0
+               OpDecorate %7 Block
+               OpDecorate %9 DescriptorSet 0
+               OpDecorate %9 Binding 0
+               OpMemberDecorate %23 0 Offset 0
+               OpDecorate %23 BufferBlock
+               OpDecorate %25 DescriptorSet 0
+               OpDecorate %25 Binding 1
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeInt 32 0
+          %7 = OpTypeStruct %6
+          %8 = OpTypePointer Uniform %7
+          %9 = OpVariable %8 Uniform
+         %10 = OpTypeInt 32 1
+         %11 = OpConstant %10 0
+         %12 = OpTypePointer Uniform %6
+         %23 = OpTypeStruct %6
+         %24 = OpTypePointer Uniform %23
+         %25 = OpVariable %24 Uniform
+         %28 = OpConstant %10 1
+         %34 = OpConstant %6 2
+         %52 = OpConstant %6 1
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+         %13 = OpAccessChain %12 %9 %11
+         %14 = OpLoad %6 %13
+               OpSelectionMerge %22 None
+               OpSwitch %14 %21 0 %15 1 %16 2 %17 3 %18 4 %19 5 %20
+         %17 = OpLabel
+         %35 = OpAccessChain %12 %25 %11
+         %36 = OpLoad %6 %35
+         %37 = OpIMul %6 %36 %34
+         %38 = OpAccessChain %12 %25 %11
+               OpStore %38 %37
+               OpBranch %22
+         %18 = OpLabel
+         %40 = OpAccessChain %12 %25 %11
+         %41 = OpLoad %6 %40
+         %42 = OpUDiv %6 %41 %34
+         %43 = OpAccessChain %12 %25 %11
+               OpStore %43 %42
+               OpBranch %22
+         %21 = OpLabel
+         %54 = OpAccessChain %12 %25 %11
+         %55 = OpLoad %6 %54
+         %56 = OpIAdd %6 %55 %34
+         %57 = OpAccessChain %12 %25 %11
+               OpStore %57 %56
+               OpBranch %22
+         %20 = OpLabel
+         %53 = OpAccessChain %12 %25 %11
+               OpStore %53 %52
+               OpBranch %21
+         %15 = OpLabel
+         %26 = OpAccessChain %12 %25 %11
+         %27 = OpLoad %6 %26
+         %29 = OpIAdd %6 %27 %28
+               OpStore %26 %29
+               OpBranch %22
+         %19 = OpLabel
+         %45 = OpAccessChain %12 %25 %11
+         %46 = OpLoad %6 %45
+         %47 = OpAccessChain %12 %25 %11
+         %48 = OpLoad %6 %47
+         %49 = OpIMul %6 %46 %48
+         %50 = OpAccessChain %12 %25 %11
+               OpStore %50 %49
+               OpBranch %22
+         %16 = OpLabel
+         %31 = OpAccessChain %12 %25 %11
+         %32 = OpLoad %6 %31
+         %33 = OpISub %6 %32 %28
+               OpStore %31 %33
+               OpBranch %17
+         %22 = OpLabel
+               OpReturn
+               OpFunctionEnd
+)";
+  constexpr char kDiff[] = R"( ; SPIR-V
+ ; Version: 1.6
+ ; Generator: Khronos SPIR-V Tools Assembler; 0
+-; Bound: 58
++; Bound: 62
+ ; Schema: 0
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %4 "main"
+ OpExecutionMode %4 LocalSize 1 1 1
+ OpSource ESSL 310
+ OpMemberDecorate %7 0 Offset 0
+ OpDecorate %7 Block
+ OpDecorate %9 DescriptorSet 0
+ OpDecorate %9 Binding 0
+ OpMemberDecorate %23 0 Offset 0
+ OpDecorate %23 BufferBlock
+ OpDecorate %25 DescriptorSet 0
+ OpDecorate %25 Binding 1
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %6 = OpTypeInt 32 0
+ %7 = OpTypeStruct %6
+ %8 = OpTypePointer Uniform %7
+ %9 = OpVariable %8 Uniform
+ %10 = OpTypeInt 32 1
+ %11 = OpConstant %10 0
+ %12 = OpTypePointer Uniform %6
+ %23 = OpTypeStruct %6
+ %24 = OpTypePointer Uniform %23
+ %25 = OpVariable %24 Uniform
+ %28 = OpConstant %10 1
+ %34 = OpConstant %6 2
+ %52 = OpConstant %6 1
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ %13 = OpAccessChain %12 %9 %11
+ %14 = OpLoad %6 %13
+ OpSelectionMerge %22 None
+ OpSwitch %14 %21 0 %15 1 %16 2 %17 3 %18 4 %19 5 %20
+ %20 = OpLabel
+ %53 = OpAccessChain %12 %25 %11
+ OpStore %53 %52
+ OpBranch %21
+ %19 = OpLabel
+ %45 = OpAccessChain %12 %25 %11
+ %46 = OpLoad %6 %45
+ %47 = OpAccessChain %12 %25 %11
+ %48 = OpLoad %6 %47
+ %49 = OpIMul %6 %46 %48
+ %50 = OpAccessChain %12 %25 %11
+ OpStore %50 %49
+ OpBranch %22
+ %18 = OpLabel
+ %40 = OpAccessChain %12 %25 %11
+ %41 = OpLoad %6 %40
+ %42 = OpUDiv %6 %41 %34
+ %43 = OpAccessChain %12 %25 %11
+ OpStore %43 %42
+ OpBranch %22
+ %16 = OpLabel
+ %31 = OpAccessChain %12 %25 %11
+ %32 = OpLoad %6 %31
+ %33 = OpISub %6 %32 %28
+ OpStore %31 %33
+ OpBranch %17
+ %17 = OpLabel
+ %35 = OpAccessChain %12 %25 %11
+ %36 = OpLoad %6 %35
+ %37 = OpIMul %6 %36 %34
+ %38 = OpAccessChain %12 %25 %11
+ OpStore %38 %37
+ OpBranch %22
+ %15 = OpLabel
+ %26 = OpAccessChain %12 %25 %11
+ %27 = OpLoad %6 %26
+ %29 = OpIAdd %6 %27 %28
+ OpStore %26 %29
+ OpBranch %22
+ %21 = OpLabel
+ %54 = OpAccessChain %12 %25 %11
+ %55 = OpLoad %6 %54
+ %56 = OpIAdd %6 %55 %34
+ %57 = OpAccessChain %12 %25 %11
+ OpStore %57 %56
+ OpBranch %22
+ %22 = OpLabel
+ OpReturn
+ OpFunctionEnd
+)";
+  Options options;
+  DoStringDiffTest(kSrcNoDebug, kDstNoDebug, kDiff, options);
+}
+
+}  // namespace
+}  // namespace diff
+}  // namespace spvtools

+ 91 - 0
ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/reordered_switch_blocks_dst.spvasm

@@ -0,0 +1,91 @@
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %4 "main"
+               OpExecutionMode %4 LocalSize 1 1 1
+               OpSource ESSL 310
+               OpName %4 "main"
+               OpName %7 "BufferIn"
+               OpMemberName %7 0 "i"
+               OpName %9 ""
+               OpName %23 "BufferOut"
+               OpMemberName %23 0 "o"
+               OpName %25 ""
+               OpMemberDecorate %7 0 Offset 0
+               OpDecorate %7 Block
+               OpDecorate %9 DescriptorSet 0
+               OpDecorate %9 Binding 0
+               OpMemberDecorate %23 0 Offset 0
+               OpDecorate %23 BufferBlock
+               OpDecorate %25 DescriptorSet 0
+               OpDecorate %25 Binding 1
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeInt 32 0
+          %7 = OpTypeStruct %6
+          %8 = OpTypePointer Uniform %7
+          %9 = OpVariable %8 Uniform
+         %10 = OpTypeInt 32 1
+         %11 = OpConstant %10 0
+         %12 = OpTypePointer Uniform %6
+         %23 = OpTypeStruct %6
+         %24 = OpTypePointer Uniform %23
+         %25 = OpVariable %24 Uniform
+         %28 = OpConstant %10 1
+         %34 = OpConstant %6 2
+         %52 = OpConstant %6 1
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+         %13 = OpAccessChain %12 %9 %11
+         %14 = OpLoad %6 %13
+               OpSelectionMerge %22 None
+               OpSwitch %14 %21 0 %15 1 %16 2 %17 3 %18 4 %19 5 %20
+         %17 = OpLabel
+         %35 = OpAccessChain %12 %25 %11
+         %36 = OpLoad %6 %35
+         %37 = OpIMul %6 %36 %34
+         %38 = OpAccessChain %12 %25 %11
+               OpStore %38 %37
+               OpBranch %22
+         %18 = OpLabel
+         %40 = OpAccessChain %12 %25 %11
+         %41 = OpLoad %6 %40
+         %42 = OpUDiv %6 %41 %34
+         %43 = OpAccessChain %12 %25 %11
+               OpStore %43 %42
+               OpBranch %22
+         %21 = OpLabel
+         %54 = OpAccessChain %12 %25 %11
+         %55 = OpLoad %6 %54
+         %56 = OpIAdd %6 %55 %34
+         %57 = OpAccessChain %12 %25 %11
+               OpStore %57 %56
+               OpBranch %22
+         %20 = OpLabel
+         %53 = OpAccessChain %12 %25 %11
+               OpStore %53 %52
+               OpBranch %21
+         %15 = OpLabel
+         %26 = OpAccessChain %12 %25 %11
+         %27 = OpLoad %6 %26
+         %29 = OpIAdd %6 %27 %28
+               OpStore %26 %29
+               OpBranch %22
+         %19 = OpLabel
+         %45 = OpAccessChain %12 %25 %11
+         %46 = OpLoad %6 %45
+         %47 = OpAccessChain %12 %25 %11
+         %48 = OpLoad %6 %47
+         %49 = OpIMul %6 %46 %48
+         %50 = OpAccessChain %12 %25 %11
+               OpStore %50 %49
+               OpBranch %22
+         %16 = OpLabel
+         %31 = OpAccessChain %12 %25 %11
+         %32 = OpLoad %6 %31
+         %33 = OpISub %6 %32 %28
+               OpStore %31 %33
+               OpBranch %17
+         %22 = OpLabel
+               OpReturn
+               OpFunctionEnd

+ 92 - 0
ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/reordered_switch_blocks_src.spvasm

@@ -0,0 +1,92 @@
+;; Test where src and dst have cases of a switch in different order.
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %4 "main"
+               OpExecutionMode %4 LocalSize 1 1 1
+               OpSource ESSL 310
+               OpName %4 "main"
+               OpName %7 "BufferIn"
+               OpMemberName %7 0 "i"
+               OpName %9 ""
+               OpName %23 "BufferOut"
+               OpMemberName %23 0 "o"
+               OpName %25 ""
+               OpMemberDecorate %7 0 Offset 0
+               OpDecorate %7 Block
+               OpDecorate %9 DescriptorSet 0
+               OpDecorate %9 Binding 0
+               OpMemberDecorate %23 0 Offset 0
+               OpDecorate %23 BufferBlock
+               OpDecorate %25 DescriptorSet 0
+               OpDecorate %25 Binding 1
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeInt 32 0
+          %7 = OpTypeStruct %6
+          %8 = OpTypePointer Uniform %7
+          %9 = OpVariable %8 Uniform
+         %10 = OpTypeInt 32 1
+         %11 = OpConstant %10 0
+         %12 = OpTypePointer Uniform %6
+         %23 = OpTypeStruct %6
+         %24 = OpTypePointer Uniform %23
+         %25 = OpVariable %24 Uniform
+         %28 = OpConstant %10 1
+         %34 = OpConstant %6 2
+         %52 = OpConstant %6 1
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+         %13 = OpAccessChain %12 %9 %11
+         %14 = OpLoad %6 %13
+               OpSelectionMerge %22 None
+               OpSwitch %14 %21 0 %15 1 %16 2 %17 3 %18 4 %19 5 %20
+         %21 = OpLabel
+         %54 = OpAccessChain %12 %25 %11
+         %55 = OpLoad %6 %54
+         %56 = OpIAdd %6 %55 %34
+         %57 = OpAccessChain %12 %25 %11
+               OpStore %57 %56
+               OpBranch %22
+         %15 = OpLabel
+         %26 = OpAccessChain %12 %25 %11
+         %27 = OpLoad %6 %26
+         %29 = OpIAdd %6 %27 %28
+               OpStore %26 %29
+               OpBranch %22
+         %16 = OpLabel
+         %31 = OpAccessChain %12 %25 %11
+         %32 = OpLoad %6 %31
+         %33 = OpISub %6 %32 %28
+               OpStore %31 %33
+               OpBranch %17
+         %17 = OpLabel
+         %35 = OpAccessChain %12 %25 %11
+         %36 = OpLoad %6 %35
+         %37 = OpIMul %6 %36 %34
+         %38 = OpAccessChain %12 %25 %11
+               OpStore %38 %37
+               OpBranch %22
+         %18 = OpLabel
+         %40 = OpAccessChain %12 %25 %11
+         %41 = OpLoad %6 %40
+         %42 = OpUDiv %6 %41 %34
+         %43 = OpAccessChain %12 %25 %11
+               OpStore %43 %42
+               OpBranch %22
+         %19 = OpLabel
+         %45 = OpAccessChain %12 %25 %11
+         %46 = OpLoad %6 %45
+         %47 = OpAccessChain %12 %25 %11
+         %48 = OpLoad %6 %47
+         %49 = OpIMul %6 %46 %48
+         %50 = OpAccessChain %12 %25 %11
+               OpStore %50 %49
+               OpBranch %22
+         %20 = OpLabel
+         %53 = OpAccessChain %12 %25 %11
+               OpStore %53 %52
+               OpBranch %21
+         %22 = OpLabel
+               OpReturn
+               OpFunctionEnd

+ 747 - 0
ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/small_functions_small_diffs_autogen.cpp

@@ -0,0 +1,747 @@
+// GENERATED FILE - DO NOT EDIT.
+// Generated by generate_tests.py
+//
+// 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 "../diff_test_utils.h"
+
+#include "gtest/gtest.h"
+
+namespace spvtools {
+namespace diff {
+namespace {
+
+// Test where src and dst have many small functions with small differences.
+constexpr char kSrc[] = R"(               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %4 "main"
+               OpExecutionMode %4 LocalSize 1 1 1
+               OpSource ESSL 310
+               OpName %4 "main"
+               OpName %6 "f1("
+               OpName %8 "f2("
+               OpName %10 "f3("
+               OpName %12 "f4("
+               OpName %14 "f5("
+               OpName %17 "BufferOut"
+               OpMemberName %17 0 "o"
+               OpName %19 ""
+               OpName %22 "BufferIn"
+               OpMemberName %22 0 "i"
+               OpName %24 ""
+               OpMemberDecorate %17 0 Offset 0
+               OpDecorate %17 BufferBlock
+               OpDecorate %19 DescriptorSet 0
+               OpDecorate %19 Binding 1
+               OpMemberDecorate %22 0 Offset 0
+               OpDecorate %22 Block
+               OpDecorate %24 DescriptorSet 0
+               OpDecorate %24 Binding 0
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+         %16 = OpTypeInt 32 0
+         %17 = OpTypeStruct %16
+         %18 = OpTypePointer Uniform %17
+         %19 = OpVariable %18 Uniform
+         %20 = OpTypeInt 32 1
+         %21 = OpConstant %20 0
+         %22 = OpTypeStruct %16
+         %23 = OpTypePointer Uniform %22
+         %24 = OpVariable %23 Uniform
+         %25 = OpTypePointer Uniform %16
+         %31 = OpConstant %20 1
+         %36 = OpConstant %16 2
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+         %45 = OpFunctionCall %2 %6
+         %46 = OpFunctionCall %2 %8
+         %47 = OpFunctionCall %2 %10
+         %48 = OpFunctionCall %2 %12
+         %49 = OpFunctionCall %2 %14
+               OpReturn
+               OpFunctionEnd
+          %6 = OpFunction %2 None %3
+          %7 = OpLabel
+         %26 = OpAccessChain %25 %24 %21
+         %27 = OpLoad %16 %26
+         %28 = OpAccessChain %25 %19 %21
+               OpStore %28 %27
+               OpReturn
+               OpFunctionEnd
+          %8 = OpFunction %2 None %3
+          %9 = OpLabel
+         %29 = OpAccessChain %25 %19 %21
+         %30 = OpLoad %16 %29
+         %32 = OpIAdd %16 %30 %31
+               OpStore %29 %32
+               OpReturn
+               OpFunctionEnd
+         %10 = OpFunction %2 None %3
+         %11 = OpLabel
+         %33 = OpAccessChain %25 %19 %21
+         %34 = OpLoad %16 %33
+         %35 = OpISub %16 %34 %31
+               OpStore %33 %35
+               OpReturn
+               OpFunctionEnd
+         %12 = OpFunction %2 None %3
+         %13 = OpLabel
+         %37 = OpAccessChain %25 %19 %21
+         %38 = OpLoad %16 %37
+         %39 = OpIMul %16 %38 %36
+         %40 = OpAccessChain %25 %19 %21
+               OpStore %40 %39
+               OpReturn
+               OpFunctionEnd
+         %14 = OpFunction %2 None %3
+         %15 = OpLabel
+         %41 = OpAccessChain %25 %19 %21
+         %42 = OpLoad %16 %41
+         %43 = OpUDiv %16 %42 %36
+         %44 = OpAccessChain %25 %19 %21
+               OpStore %44 %43
+               OpReturn
+               OpFunctionEnd
+)";
+constexpr char kDst[] = R"(               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %4 "main"
+               OpExecutionMode %4 LocalSize 1 1 1
+               OpSource ESSL 310
+               OpName %4 "main"
+               OpName %6 "f1("
+               OpName %8 "f2("
+               OpName %10 "f3("
+               OpName %12 "f4("
+               OpName %14 "f5("
+               OpName %17 "BufferOut"
+               OpMemberName %17 0 "o"
+               OpName %19 ""
+               OpName %22 "BufferIn"
+               OpMemberName %22 0 "i"
+               OpName %24 ""
+               OpMemberDecorate %17 0 Offset 0
+               OpDecorate %17 BufferBlock
+               OpDecorate %19 DescriptorSet 0
+               OpDecorate %19 Binding 1
+               OpMemberDecorate %22 0 Offset 0
+               OpDecorate %22 Block
+               OpDecorate %24 DescriptorSet 0
+               OpDecorate %24 Binding 0
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+         %16 = OpTypeInt 32 0
+         %17 = OpTypeStruct %16
+         %18 = OpTypePointer Uniform %17
+         %19 = OpVariable %18 Uniform
+         %20 = OpTypeInt 32 1
+         %21 = OpConstant %20 0
+         %22 = OpTypeStruct %16
+         %23 = OpTypePointer Uniform %22
+         %24 = OpVariable %23 Uniform
+         %25 = OpTypePointer Uniform %16
+         %31 = OpConstant %20 1
+         %36 = OpConstant %16 2
+          %6 = OpFunction %2 None %3
+          %7 = OpLabel
+         %26 = OpAccessChain %25 %24 %21
+         %27 = OpLoad %16 %26
+         %28 = OpAccessChain %25 %19 %21
+               OpStore %28 %27
+               OpReturn
+               OpFunctionEnd
+         %14 = OpFunction %2 None %3
+         %15 = OpLabel
+         %41 = OpAccessChain %25 %19 %21
+         %42 = OpLoad %16 %41
+         %43 = OpIAdd %16 %42 %36
+         %44 = OpAccessChain %25 %19 %21
+               OpStore %44 %43
+               OpReturn
+               OpFunctionEnd
+          %8 = OpFunction %2 None %3
+          %9 = OpLabel
+         %29 = OpAccessChain %25 %19 %21
+         %30 = OpLoad %16 %29
+         %32 = OpISub %16 %30 %31
+               OpStore %29 %32
+               OpReturn
+               OpFunctionEnd
+         %10 = OpFunction %2 None %3
+         %11 = OpLabel
+         %33 = OpAccessChain %25 %19 %21
+         %34 = OpLoad %16 %33
+         %35 = OpIAdd %16 %34 %31
+               OpStore %33 %35
+               OpReturn
+               OpFunctionEnd
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+         %45 = OpFunctionCall %2 %6
+         %46 = OpFunctionCall %2 %8
+         %47 = OpFunctionCall %2 %10
+         %48 = OpFunctionCall %2 %12
+         %49 = OpFunctionCall %2 %14
+               OpReturn
+               OpFunctionEnd
+         %12 = OpFunction %2 None %3
+         %13 = OpLabel
+         %37 = OpAccessChain %25 %19 %21
+         %38 = OpLoad %16 %37
+         %39 = OpISub %16 %38 %36
+         %40 = OpAccessChain %25 %19 %21
+               OpStore %40 %39
+               OpReturn
+               OpFunctionEnd
+
+)";
+
+TEST(DiffTest, SmallFunctionsSmallDiffs) {
+  constexpr char kDiff[] = R"( ; SPIR-V
+ ; Version: 1.6
+ ; Generator: Khronos SPIR-V Tools Assembler; 0
+-; Bound: 50
++; Bound: 54
+ ; Schema: 0
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %4 "main"
+ OpExecutionMode %4 LocalSize 1 1 1
+ OpSource ESSL 310
+ OpName %4 "main"
+ OpName %6 "f1("
+ OpName %8 "f2("
+ OpName %10 "f3("
+ OpName %12 "f4("
+ OpName %14 "f5("
+ OpName %17 "BufferOut"
+ OpMemberName %17 0 "o"
+ OpName %19 ""
+ OpName %22 "BufferIn"
+ OpMemberName %22 0 "i"
+ OpName %24 ""
+ OpMemberDecorate %17 0 Offset 0
+ OpDecorate %17 BufferBlock
+ OpDecorate %19 DescriptorSet 0
+ OpDecorate %19 Binding 1
+ OpMemberDecorate %22 0 Offset 0
+ OpDecorate %22 Block
+ OpDecorate %24 DescriptorSet 0
+ OpDecorate %24 Binding 0
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %16 = OpTypeInt 32 0
+ %17 = OpTypeStruct %16
+ %18 = OpTypePointer Uniform %17
+ %19 = OpVariable %18 Uniform
+ %20 = OpTypeInt 32 1
+ %21 = OpConstant %20 0
+ %22 = OpTypeStruct %16
+ %23 = OpTypePointer Uniform %22
+ %24 = OpVariable %23 Uniform
+ %25 = OpTypePointer Uniform %16
+ %31 = OpConstant %20 1
+ %36 = OpConstant %16 2
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ %45 = OpFunctionCall %2 %6
+ %46 = OpFunctionCall %2 %8
+ %47 = OpFunctionCall %2 %10
+ %48 = OpFunctionCall %2 %12
+ %49 = OpFunctionCall %2 %14
+ OpReturn
+ OpFunctionEnd
+ %6 = OpFunction %2 None %3
+ %7 = OpLabel
+ %26 = OpAccessChain %25 %24 %21
+ %27 = OpLoad %16 %26
+ %28 = OpAccessChain %25 %19 %21
+ OpStore %28 %27
+ OpReturn
+ OpFunctionEnd
+ %8 = OpFunction %2 None %3
+ %9 = OpLabel
+ %29 = OpAccessChain %25 %19 %21
+ %30 = OpLoad %16 %29
+-%32 = OpIAdd %16 %30 %31
++%50 = OpISub %16 %30 %31
+-OpStore %29 %32
++OpStore %29 %50
+ OpReturn
+ OpFunctionEnd
+ %10 = OpFunction %2 None %3
+ %11 = OpLabel
+ %33 = OpAccessChain %25 %19 %21
+ %34 = OpLoad %16 %33
+-%35 = OpISub %16 %34 %31
++%51 = OpIAdd %16 %34 %31
+-OpStore %33 %35
++OpStore %33 %51
+ OpReturn
+ OpFunctionEnd
+ %12 = OpFunction %2 None %3
+ %13 = OpLabel
+ %37 = OpAccessChain %25 %19 %21
+ %38 = OpLoad %16 %37
+-%39 = OpIMul %16 %38 %36
++%52 = OpISub %16 %38 %36
+ %40 = OpAccessChain %25 %19 %21
+-OpStore %40 %39
++OpStore %40 %52
+ OpReturn
+ OpFunctionEnd
+ %14 = OpFunction %2 None %3
+ %15 = OpLabel
+ %41 = OpAccessChain %25 %19 %21
+ %42 = OpLoad %16 %41
+-%43 = OpUDiv %16 %42 %36
++%53 = OpIAdd %16 %42 %36
+ %44 = OpAccessChain %25 %19 %21
+-OpStore %44 %43
++OpStore %44 %53
+ OpReturn
+ OpFunctionEnd
+)";
+  Options options;
+  DoStringDiffTest(kSrc, kDst, kDiff, options);
+}
+
+TEST(DiffTest, SmallFunctionsSmallDiffsNoDebug) {
+  constexpr char kSrcNoDebug[] = R"(               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %4 "main"
+               OpExecutionMode %4 LocalSize 1 1 1
+               OpSource ESSL 310
+               OpMemberDecorate %17 0 Offset 0
+               OpDecorate %17 BufferBlock
+               OpDecorate %19 DescriptorSet 0
+               OpDecorate %19 Binding 1
+               OpMemberDecorate %22 0 Offset 0
+               OpDecorate %22 Block
+               OpDecorate %24 DescriptorSet 0
+               OpDecorate %24 Binding 0
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+         %16 = OpTypeInt 32 0
+         %17 = OpTypeStruct %16
+         %18 = OpTypePointer Uniform %17
+         %19 = OpVariable %18 Uniform
+         %20 = OpTypeInt 32 1
+         %21 = OpConstant %20 0
+         %22 = OpTypeStruct %16
+         %23 = OpTypePointer Uniform %22
+         %24 = OpVariable %23 Uniform
+         %25 = OpTypePointer Uniform %16
+         %31 = OpConstant %20 1
+         %36 = OpConstant %16 2
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+         %45 = OpFunctionCall %2 %6
+         %46 = OpFunctionCall %2 %8
+         %47 = OpFunctionCall %2 %10
+         %48 = OpFunctionCall %2 %12
+         %49 = OpFunctionCall %2 %14
+               OpReturn
+               OpFunctionEnd
+          %6 = OpFunction %2 None %3
+          %7 = OpLabel
+         %26 = OpAccessChain %25 %24 %21
+         %27 = OpLoad %16 %26
+         %28 = OpAccessChain %25 %19 %21
+               OpStore %28 %27
+               OpReturn
+               OpFunctionEnd
+          %8 = OpFunction %2 None %3
+          %9 = OpLabel
+         %29 = OpAccessChain %25 %19 %21
+         %30 = OpLoad %16 %29
+         %32 = OpIAdd %16 %30 %31
+               OpStore %29 %32
+               OpReturn
+               OpFunctionEnd
+         %10 = OpFunction %2 None %3
+         %11 = OpLabel
+         %33 = OpAccessChain %25 %19 %21
+         %34 = OpLoad %16 %33
+         %35 = OpISub %16 %34 %31
+               OpStore %33 %35
+               OpReturn
+               OpFunctionEnd
+         %12 = OpFunction %2 None %3
+         %13 = OpLabel
+         %37 = OpAccessChain %25 %19 %21
+         %38 = OpLoad %16 %37
+         %39 = OpIMul %16 %38 %36
+         %40 = OpAccessChain %25 %19 %21
+               OpStore %40 %39
+               OpReturn
+               OpFunctionEnd
+         %14 = OpFunction %2 None %3
+         %15 = OpLabel
+         %41 = OpAccessChain %25 %19 %21
+         %42 = OpLoad %16 %41
+         %43 = OpUDiv %16 %42 %36
+         %44 = OpAccessChain %25 %19 %21
+               OpStore %44 %43
+               OpReturn
+               OpFunctionEnd
+
+)";
+  constexpr char kDstNoDebug[] = R"(               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %4 "main"
+               OpExecutionMode %4 LocalSize 1 1 1
+               OpSource ESSL 310
+               OpMemberDecorate %17 0 Offset 0
+               OpDecorate %17 BufferBlock
+               OpDecorate %19 DescriptorSet 0
+               OpDecorate %19 Binding 1
+               OpMemberDecorate %22 0 Offset 0
+               OpDecorate %22 Block
+               OpDecorate %24 DescriptorSet 0
+               OpDecorate %24 Binding 0
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+         %16 = OpTypeInt 32 0
+         %17 = OpTypeStruct %16
+         %18 = OpTypePointer Uniform %17
+         %19 = OpVariable %18 Uniform
+         %20 = OpTypeInt 32 1
+         %21 = OpConstant %20 0
+         %22 = OpTypeStruct %16
+         %23 = OpTypePointer Uniform %22
+         %24 = OpVariable %23 Uniform
+         %25 = OpTypePointer Uniform %16
+         %31 = OpConstant %20 1
+         %36 = OpConstant %16 2
+          %6 = OpFunction %2 None %3
+          %7 = OpLabel
+         %26 = OpAccessChain %25 %24 %21
+         %27 = OpLoad %16 %26
+         %28 = OpAccessChain %25 %19 %21
+               OpStore %28 %27
+               OpReturn
+               OpFunctionEnd
+         %14 = OpFunction %2 None %3
+         %15 = OpLabel
+         %41 = OpAccessChain %25 %19 %21
+         %42 = OpLoad %16 %41
+         %43 = OpIAdd %16 %42 %36
+         %44 = OpAccessChain %25 %19 %21
+               OpStore %44 %43
+               OpReturn
+               OpFunctionEnd
+          %8 = OpFunction %2 None %3
+          %9 = OpLabel
+         %29 = OpAccessChain %25 %19 %21
+         %30 = OpLoad %16 %29
+         %32 = OpISub %16 %30 %31
+               OpStore %29 %32
+               OpReturn
+               OpFunctionEnd
+         %10 = OpFunction %2 None %3
+         %11 = OpLabel
+         %33 = OpAccessChain %25 %19 %21
+         %34 = OpLoad %16 %33
+         %35 = OpIAdd %16 %34 %31
+               OpStore %33 %35
+               OpReturn
+               OpFunctionEnd
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+         %45 = OpFunctionCall %2 %6
+         %46 = OpFunctionCall %2 %8
+         %47 = OpFunctionCall %2 %10
+         %48 = OpFunctionCall %2 %12
+         %49 = OpFunctionCall %2 %14
+               OpReturn
+               OpFunctionEnd
+         %12 = OpFunction %2 None %3
+         %13 = OpLabel
+         %37 = OpAccessChain %25 %19 %21
+         %38 = OpLoad %16 %37
+         %39 = OpISub %16 %38 %36
+         %40 = OpAccessChain %25 %19 %21
+               OpStore %40 %39
+               OpReturn
+               OpFunctionEnd
+
+)";
+  constexpr char kDiff[] = R"( ; SPIR-V
+ ; Version: 1.6
+ ; Generator: Khronos SPIR-V Tools Assembler; 0
+-; Bound: 50
++; Bound: 52
+ ; Schema: 0
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %4 "main"
+ OpExecutionMode %4 LocalSize 1 1 1
+ OpSource ESSL 310
+ OpMemberDecorate %17 0 Offset 0
+ OpDecorate %17 BufferBlock
+ OpDecorate %19 DescriptorSet 0
+ OpDecorate %19 Binding 1
+ OpMemberDecorate %22 0 Offset 0
+ OpDecorate %22 Block
+ OpDecorate %24 DescriptorSet 0
+ OpDecorate %24 Binding 0
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %16 = OpTypeInt 32 0
+ %17 = OpTypeStruct %16
+ %18 = OpTypePointer Uniform %17
+ %19 = OpVariable %18 Uniform
+ %20 = OpTypeInt 32 1
+ %21 = OpConstant %20 0
+ %22 = OpTypeStruct %16
+ %23 = OpTypePointer Uniform %22
+ %24 = OpVariable %23 Uniform
+ %25 = OpTypePointer Uniform %16
+ %31 = OpConstant %20 1
+ %36 = OpConstant %16 2
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ %45 = OpFunctionCall %2 %6
+-%46 = OpFunctionCall %2 %8
++%46 = OpFunctionCall %2 %10
+-%47 = OpFunctionCall %2 %10
++%47 = OpFunctionCall %2 %8
+ %48 = OpFunctionCall %2 %12
+ %49 = OpFunctionCall %2 %14
+ OpReturn
+ OpFunctionEnd
+ %6 = OpFunction %2 None %3
+ %7 = OpLabel
+ %26 = OpAccessChain %25 %24 %21
+ %27 = OpLoad %16 %26
+ %28 = OpAccessChain %25 %19 %21
+ OpStore %28 %27
+ OpReturn
+ OpFunctionEnd
+ %8 = OpFunction %2 None %3
+ %9 = OpLabel
+ %29 = OpAccessChain %25 %19 %21
+ %30 = OpLoad %16 %29
+ %32 = OpIAdd %16 %30 %31
+ OpStore %29 %32
+ OpReturn
+ OpFunctionEnd
+ %10 = OpFunction %2 None %3
+ %11 = OpLabel
+ %33 = OpAccessChain %25 %19 %21
+ %34 = OpLoad %16 %33
+ %35 = OpISub %16 %34 %31
+ OpStore %33 %35
+ OpReturn
+ OpFunctionEnd
+ %12 = OpFunction %2 None %3
+ %13 = OpLabel
+ %37 = OpAccessChain %25 %19 %21
+ %38 = OpLoad %16 %37
+-%39 = OpIMul %16 %38 %36
++%50 = OpISub %16 %38 %36
+ %40 = OpAccessChain %25 %19 %21
+-OpStore %40 %39
++OpStore %40 %50
+ OpReturn
+ OpFunctionEnd
+ %14 = OpFunction %2 None %3
+ %15 = OpLabel
+ %41 = OpAccessChain %25 %19 %21
+ %42 = OpLoad %16 %41
+-%43 = OpUDiv %16 %42 %36
++%51 = OpIAdd %16 %42 %36
+ %44 = OpAccessChain %25 %19 %21
+-OpStore %44 %43
++OpStore %44 %51
+ OpReturn
+ OpFunctionEnd
+)";
+  Options options;
+  DoStringDiffTest(kSrcNoDebug, kDstNoDebug, kDiff, options);
+}
+
+TEST(DiffTest, SmallFunctionsSmallDiffsDumpIds) {
+  constexpr char kDiff[] = R"( ; SPIR-V
+ ; Version: 1.6
+ ; Generator: Khronos SPIR-V Tools Assembler; 0
+-; Bound: 50
++; Bound: 54
+ ; Schema: 0
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %4 "main"
+ OpExecutionMode %4 LocalSize 1 1 1
+ OpSource ESSL 310
+ OpName %4 "main"
+ OpName %6 "f1("
+ OpName %8 "f2("
+ OpName %10 "f3("
+ OpName %12 "f4("
+ OpName %14 "f5("
+ OpName %17 "BufferOut"
+ OpMemberName %17 0 "o"
+ OpName %19 ""
+ OpName %22 "BufferIn"
+ OpMemberName %22 0 "i"
+ OpName %24 ""
+ OpMemberDecorate %17 0 Offset 0
+ OpDecorate %17 BufferBlock
+ OpDecorate %19 DescriptorSet 0
+ OpDecorate %19 Binding 1
+ OpMemberDecorate %22 0 Offset 0
+ OpDecorate %22 Block
+ OpDecorate %24 DescriptorSet 0
+ OpDecorate %24 Binding 0
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %16 = OpTypeInt 32 0
+ %17 = OpTypeStruct %16
+ %18 = OpTypePointer Uniform %17
+ %19 = OpVariable %18 Uniform
+ %20 = OpTypeInt 32 1
+ %21 = OpConstant %20 0
+ %22 = OpTypeStruct %16
+ %23 = OpTypePointer Uniform %22
+ %24 = OpVariable %23 Uniform
+ %25 = OpTypePointer Uniform %16
+ %31 = OpConstant %20 1
+ %36 = OpConstant %16 2
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ %45 = OpFunctionCall %2 %6
+ %46 = OpFunctionCall %2 %8
+ %47 = OpFunctionCall %2 %10
+ %48 = OpFunctionCall %2 %12
+ %49 = OpFunctionCall %2 %14
+ OpReturn
+ OpFunctionEnd
+ %6 = OpFunction %2 None %3
+ %7 = OpLabel
+ %26 = OpAccessChain %25 %24 %21
+ %27 = OpLoad %16 %26
+ %28 = OpAccessChain %25 %19 %21
+ OpStore %28 %27
+ OpReturn
+ OpFunctionEnd
+ %8 = OpFunction %2 None %3
+ %9 = OpLabel
+ %29 = OpAccessChain %25 %19 %21
+ %30 = OpLoad %16 %29
+-%32 = OpIAdd %16 %30 %31
++%50 = OpISub %16 %30 %31
+-OpStore %29 %32
++OpStore %29 %50
+ OpReturn
+ OpFunctionEnd
+ %10 = OpFunction %2 None %3
+ %11 = OpLabel
+ %33 = OpAccessChain %25 %19 %21
+ %34 = OpLoad %16 %33
+-%35 = OpISub %16 %34 %31
++%51 = OpIAdd %16 %34 %31
+-OpStore %33 %35
++OpStore %33 %51
+ OpReturn
+ OpFunctionEnd
+ %12 = OpFunction %2 None %3
+ %13 = OpLabel
+ %37 = OpAccessChain %25 %19 %21
+ %38 = OpLoad %16 %37
+-%39 = OpIMul %16 %38 %36
++%52 = OpISub %16 %38 %36
+ %40 = OpAccessChain %25 %19 %21
+-OpStore %40 %39
++OpStore %40 %52
+ OpReturn
+ OpFunctionEnd
+ %14 = OpFunction %2 None %3
+ %15 = OpLabel
+ %41 = OpAccessChain %25 %19 %21
+ %42 = OpLoad %16 %41
+-%43 = OpUDiv %16 %42 %36
++%53 = OpIAdd %16 %42 %36
+ %44 = OpAccessChain %25 %19 %21
+-OpStore %44 %43
++OpStore %44 %53
+ OpReturn
+ OpFunctionEnd
+ Src ->  Dst
+   1 ->    1 [ExtInstImport]
+   2 ->    2 [TypeVoid]
+   3 ->    3 [TypeFunction]
+   4 ->    4 [Function]
+   5 ->    5 [Label]
+   6 ->    6 [Function]
+   7 ->    7 [Label]
+   8 ->    8 [Function]
+   9 ->    9 [Label]
+  10 ->   10 [Function]
+  11 ->   11 [Label]
+  12 ->   12 [Function]
+  13 ->   13 [Label]
+  14 ->   14 [Function]
+  15 ->   15 [Label]
+  16 ->   16 [TypeInt]
+  17 ->   17 [TypeStruct]
+  18 ->   18 [TypePointer]
+  19 ->   19 [Variable]
+  20 ->   20 [TypeInt]
+  21 ->   21 [Constant]
+  22 ->   22 [TypeStruct]
+  23 ->   23 [TypePointer]
+  24 ->   24 [Variable]
+  25 ->   25 [TypePointer]
+  26 ->   26 [AccessChain]
+  27 ->   27 [Load]
+  28 ->   28 [AccessChain]
+  29 ->   29 [AccessChain]
+  30 ->   30 [Load]
+  31 ->   31 [Constant]
+  32 ->   50 [IAdd]
+  33 ->   33 [AccessChain]
+  34 ->   34 [Load]
+  35 ->   51 [ISub]
+  36 ->   36 [Constant]
+  37 ->   37 [AccessChain]
+  38 ->   38 [Load]
+  39 ->   52 [IMul]
+  40 ->   40 [AccessChain]
+  41 ->   41 [AccessChain]
+  42 ->   42 [Load]
+  43 ->   53 [UDiv]
+  44 ->   44 [AccessChain]
+  45 ->   45 [FunctionCall]
+  46 ->   46 [FunctionCall]
+  47 ->   47 [FunctionCall]
+  48 ->   48 [FunctionCall]
+  49 ->   49 [FunctionCall]
+)";
+  Options options;
+  options.dump_id_map = true;
+  DoStringDiffTest(kSrc, kDst, kDiff, options);
+}
+
+}  // namespace
+}  // namespace diff
+}  // namespace spvtools

+ 92 - 0
ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/small_functions_small_diffs_dst.spvasm

@@ -0,0 +1,92 @@
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %4 "main"
+               OpExecutionMode %4 LocalSize 1 1 1
+               OpSource ESSL 310
+               OpName %4 "main"
+               OpName %6 "f1("
+               OpName %8 "f2("
+               OpName %10 "f3("
+               OpName %12 "f4("
+               OpName %14 "f5("
+               OpName %17 "BufferOut"
+               OpMemberName %17 0 "o"
+               OpName %19 ""
+               OpName %22 "BufferIn"
+               OpMemberName %22 0 "i"
+               OpName %24 ""
+               OpMemberDecorate %17 0 Offset 0
+               OpDecorate %17 BufferBlock
+               OpDecorate %19 DescriptorSet 0
+               OpDecorate %19 Binding 1
+               OpMemberDecorate %22 0 Offset 0
+               OpDecorate %22 Block
+               OpDecorate %24 DescriptorSet 0
+               OpDecorate %24 Binding 0
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+         %16 = OpTypeInt 32 0
+         %17 = OpTypeStruct %16
+         %18 = OpTypePointer Uniform %17
+         %19 = OpVariable %18 Uniform
+         %20 = OpTypeInt 32 1
+         %21 = OpConstant %20 0
+         %22 = OpTypeStruct %16
+         %23 = OpTypePointer Uniform %22
+         %24 = OpVariable %23 Uniform
+         %25 = OpTypePointer Uniform %16
+         %31 = OpConstant %20 1
+         %36 = OpConstant %16 2
+          %6 = OpFunction %2 None %3
+          %7 = OpLabel
+         %26 = OpAccessChain %25 %24 %21
+         %27 = OpLoad %16 %26
+         %28 = OpAccessChain %25 %19 %21
+               OpStore %28 %27
+               OpReturn
+               OpFunctionEnd
+         %14 = OpFunction %2 None %3
+         %15 = OpLabel
+         %41 = OpAccessChain %25 %19 %21
+         %42 = OpLoad %16 %41
+         %43 = OpIAdd %16 %42 %36
+         %44 = OpAccessChain %25 %19 %21
+               OpStore %44 %43
+               OpReturn
+               OpFunctionEnd
+          %8 = OpFunction %2 None %3
+          %9 = OpLabel
+         %29 = OpAccessChain %25 %19 %21
+         %30 = OpLoad %16 %29
+         %32 = OpISub %16 %30 %31
+               OpStore %29 %32
+               OpReturn
+               OpFunctionEnd
+         %10 = OpFunction %2 None %3
+         %11 = OpLabel
+         %33 = OpAccessChain %25 %19 %21
+         %34 = OpLoad %16 %33
+         %35 = OpIAdd %16 %34 %31
+               OpStore %33 %35
+               OpReturn
+               OpFunctionEnd
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+         %45 = OpFunctionCall %2 %6
+         %46 = OpFunctionCall %2 %8
+         %47 = OpFunctionCall %2 %10
+         %48 = OpFunctionCall %2 %12
+         %49 = OpFunctionCall %2 %14
+               OpReturn
+               OpFunctionEnd
+         %12 = OpFunction %2 None %3
+         %13 = OpLabel
+         %37 = OpAccessChain %25 %19 %21
+         %38 = OpLoad %16 %37
+         %39 = OpISub %16 %38 %36
+         %40 = OpAccessChain %25 %19 %21
+               OpStore %40 %39
+               OpReturn
+               OpFunctionEnd
+

+ 93 - 0
ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/small_functions_small_diffs_src.spvasm

@@ -0,0 +1,93 @@
+;; Test where src and dst have many small functions with small differences.
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %4 "main"
+               OpExecutionMode %4 LocalSize 1 1 1
+               OpSource ESSL 310
+               OpName %4 "main"
+               OpName %6 "f1("
+               OpName %8 "f2("
+               OpName %10 "f3("
+               OpName %12 "f4("
+               OpName %14 "f5("
+               OpName %17 "BufferOut"
+               OpMemberName %17 0 "o"
+               OpName %19 ""
+               OpName %22 "BufferIn"
+               OpMemberName %22 0 "i"
+               OpName %24 ""
+               OpMemberDecorate %17 0 Offset 0
+               OpDecorate %17 BufferBlock
+               OpDecorate %19 DescriptorSet 0
+               OpDecorate %19 Binding 1
+               OpMemberDecorate %22 0 Offset 0
+               OpDecorate %22 Block
+               OpDecorate %24 DescriptorSet 0
+               OpDecorate %24 Binding 0
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+         %16 = OpTypeInt 32 0
+         %17 = OpTypeStruct %16
+         %18 = OpTypePointer Uniform %17
+         %19 = OpVariable %18 Uniform
+         %20 = OpTypeInt 32 1
+         %21 = OpConstant %20 0
+         %22 = OpTypeStruct %16
+         %23 = OpTypePointer Uniform %22
+         %24 = OpVariable %23 Uniform
+         %25 = OpTypePointer Uniform %16
+         %31 = OpConstant %20 1
+         %36 = OpConstant %16 2
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+         %45 = OpFunctionCall %2 %6
+         %46 = OpFunctionCall %2 %8
+         %47 = OpFunctionCall %2 %10
+         %48 = OpFunctionCall %2 %12
+         %49 = OpFunctionCall %2 %14
+               OpReturn
+               OpFunctionEnd
+          %6 = OpFunction %2 None %3
+          %7 = OpLabel
+         %26 = OpAccessChain %25 %24 %21
+         %27 = OpLoad %16 %26
+         %28 = OpAccessChain %25 %19 %21
+               OpStore %28 %27
+               OpReturn
+               OpFunctionEnd
+          %8 = OpFunction %2 None %3
+          %9 = OpLabel
+         %29 = OpAccessChain %25 %19 %21
+         %30 = OpLoad %16 %29
+         %32 = OpIAdd %16 %30 %31
+               OpStore %29 %32
+               OpReturn
+               OpFunctionEnd
+         %10 = OpFunction %2 None %3
+         %11 = OpLabel
+         %33 = OpAccessChain %25 %19 %21
+         %34 = OpLoad %16 %33
+         %35 = OpISub %16 %34 %31
+               OpStore %33 %35
+               OpReturn
+               OpFunctionEnd
+         %12 = OpFunction %2 None %3
+         %13 = OpLabel
+         %37 = OpAccessChain %25 %19 %21
+         %38 = OpLoad %16 %37
+         %39 = OpIMul %16 %38 %36
+         %40 = OpAccessChain %25 %19 %21
+               OpStore %40 %39
+               OpReturn
+               OpFunctionEnd
+         %14 = OpFunction %2 None %3
+         %15 = OpLabel
+         %41 = OpAccessChain %25 %19 %21
+         %42 = OpLoad %16 %41
+         %43 = OpUDiv %16 %42 %36
+         %44 = OpAccessChain %25 %19 %21
+               OpStore %44 %43
+               OpReturn
+               OpFunctionEnd
+

+ 310 - 0
ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/spec_constant_array_size_autogen.cpp

@@ -0,0 +1,310 @@
+// GENERATED FILE - DO NOT EDIT.
+// Generated by generate_tests.py
+//
+// 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 "../diff_test_utils.h"
+
+#include "gtest/gtest.h"
+
+namespace spvtools {
+namespace diff {
+namespace {
+
+// Tests that identical specialization constants are not matched with constants
+// when used as array size.
+constexpr char kSrc[] = R"(; SPIR-V
+; Version: 1.0
+; Generator: Google ANGLE Shader Compiler; 0
+; Bound: 27
+; Schema: 0
+OpCapability Shader
+OpMemoryModel Logical GLSL450
+OpEntryPoint Vertex %22 "main" %4 %19
+OpSource GLSL 450
+OpName %4 "_ua_position"
+OpName %17 "gl_PerVertex"
+OpMemberName %17 0 "gl_Position"
+OpMemberName %17 1 "gl_PointSize"
+OpMemberName %17 2 "gl_ClipDistance"
+OpMemberName %17 3 "gl_CullDistance"
+OpName %19 ""
+OpName %22 "main"
+OpDecorate %4 Location 0
+OpMemberDecorate %17 1 RelaxedPrecision
+OpMemberDecorate %17 0 BuiltIn Position
+OpMemberDecorate %17 1 BuiltIn PointSize
+OpMemberDecorate %17 2 BuiltIn ClipDistance
+OpMemberDecorate %17 3 BuiltIn CullDistance
+OpDecorate %17 Block
+%1 = OpTypeFloat 32
+%2 = OpTypeVector %1 4
+%5 = OpTypeInt 32 0
+%8 = OpTypeVector %5 4
+%15 = OpConstant %5 8
+%16 = OpTypeArray %1 %15
+%17 = OpTypeStruct %2 %1 %16 %16
+%20 = OpTypeVoid
+%25 = OpConstant %5 0
+%3 = OpTypePointer Input %2
+%13 = OpTypePointer Output %2
+%18 = OpTypePointer Output %17
+%21 = OpTypeFunction %20
+%4 = OpVariable %3 Input
+%19 = OpVariable %18 Output
+%22 = OpFunction %20 None %21
+%23 = OpLabel
+%24 = OpLoad %2 %4
+%26 = OpAccessChain %13 %19 %25
+OpStore %26 %24
+OpReturn
+OpFunctionEnd)";
+constexpr char kDst[] = R"(; SPIR-V
+; Version: 1.0
+; Generator: Google ANGLE Shader Compiler; 0
+; Bound: 27
+; Schema: 0
+OpCapability Shader
+OpMemoryModel Logical GLSL450
+OpEntryPoint Vertex %22 "main" %4 %19
+OpSource GLSL 450
+OpName %4 "_ua_position"
+OpName %17 "gl_PerVertex"
+OpMemberName %17 0 "gl_Position"
+OpMemberName %17 1 "gl_PointSize"
+OpMemberName %17 2 "gl_ClipDistance"
+OpMemberName %17 3 "gl_CullDistance"
+OpName %19 ""
+OpName %22 "main"
+OpDecorate %4 Location 0
+OpDecorate %15 SpecId 4
+OpMemberDecorate %17 1 RelaxedPrecision
+OpMemberDecorate %17 0 BuiltIn Position
+OpMemberDecorate %17 1 BuiltIn PointSize
+OpMemberDecorate %17 2 BuiltIn ClipDistance
+OpMemberDecorate %17 3 BuiltIn CullDistance
+OpDecorate %17 Block
+%1 = OpTypeFloat 32
+%2 = OpTypeVector %1 4
+%5 = OpTypeInt 32 0
+%8 = OpTypeVector %5 4
+%15 = OpSpecConstant %5 8
+%16 = OpTypeArray %1 %15
+%17 = OpTypeStruct %2 %1 %16 %16
+%20 = OpTypeVoid
+%25 = OpConstant %5 0
+%3 = OpTypePointer Input %2
+%13 = OpTypePointer Output %2
+%18 = OpTypePointer Output %17
+%21 = OpTypeFunction %20
+%4 = OpVariable %3 Input
+%19 = OpVariable %18 Output
+%22 = OpFunction %20 None %21
+%23 = OpLabel
+%24 = OpLoad %2 %4
+%26 = OpAccessChain %13 %19 %25
+OpStore %26 %24
+OpReturn
+OpFunctionEnd
+)";
+
+TEST(DiffTest, SpecConstantArraySize) {
+  constexpr char kDiff[] = R"( ; SPIR-V
+ ; Version: 1.6
+ ; Generator: Khronos SPIR-V Tools Assembler; 0
+-; Bound: 27
++; Bound: 36
+ ; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Vertex %22 "main" %4 %19
+ OpSource GLSL 450
+ OpName %4 "_ua_position"
+ OpName %17 "gl_PerVertex"
+ OpMemberName %17 0 "gl_Position"
+ OpMemberName %17 1 "gl_PointSize"
+ OpMemberName %17 2 "gl_ClipDistance"
+ OpMemberName %17 3 "gl_CullDistance"
+ OpName %19 ""
+ OpName %22 "main"
+ OpDecorate %4 Location 0
++OpDecorate %34 SpecId 4
+ OpMemberDecorate %17 1 RelaxedPrecision
+ OpMemberDecorate %17 0 BuiltIn Position
+ OpMemberDecorate %17 1 BuiltIn PointSize
+ OpMemberDecorate %17 2 BuiltIn ClipDistance
+ OpMemberDecorate %17 3 BuiltIn CullDistance
+ OpDecorate %17 Block
+ %1 = OpTypeFloat 32
+ %2 = OpTypeVector %1 4
+ %5 = OpTypeInt 32 0
+ %8 = OpTypeVector %5 4
+-%15 = OpConstant %5 8
+-%16 = OpTypeArray %1 %15
++%34 = OpSpecConstant %5 8
++%35 = OpTypeArray %1 %34
+-%17 = OpTypeStruct %2 %1 %16 %16
++%17 = OpTypeStruct %2 %1 %35 %35
+ %20 = OpTypeVoid
+ %25 = OpConstant %5 0
+ %3 = OpTypePointer Input %2
+ %13 = OpTypePointer Output %2
+ %18 = OpTypePointer Output %17
+ %21 = OpTypeFunction %20
+ %4 = OpVariable %3 Input
+ %19 = OpVariable %18 Output
+ %22 = OpFunction %20 None %21
+ %23 = OpLabel
+ %24 = OpLoad %2 %4
+ %26 = OpAccessChain %13 %19 %25
+ OpStore %26 %24
+ OpReturn
+ OpFunctionEnd
+)";
+  Options options;
+  DoStringDiffTest(kSrc, kDst, kDiff, options);
+}
+
+TEST(DiffTest, SpecConstantArraySizeNoDebug) {
+  constexpr char kSrcNoDebug[] = R"(; SPIR-V
+; Version: 1.0
+; Generator: Google ANGLE Shader Compiler; 0
+; Bound: 27
+; Schema: 0
+OpCapability Shader
+OpMemoryModel Logical GLSL450
+OpEntryPoint Vertex %22 "main" %4 %19
+OpSource GLSL 450
+OpDecorate %4 Location 0
+OpMemberDecorate %17 1 RelaxedPrecision
+OpMemberDecorate %17 0 BuiltIn Position
+OpMemberDecorate %17 1 BuiltIn PointSize
+OpMemberDecorate %17 2 BuiltIn ClipDistance
+OpMemberDecorate %17 3 BuiltIn CullDistance
+OpDecorate %17 Block
+%1 = OpTypeFloat 32
+%2 = OpTypeVector %1 4
+%5 = OpTypeInt 32 0
+%8 = OpTypeVector %5 4
+%15 = OpConstant %5 8
+%16 = OpTypeArray %1 %15
+%17 = OpTypeStruct %2 %1 %16 %16
+%20 = OpTypeVoid
+%25 = OpConstant %5 0
+%3 = OpTypePointer Input %2
+%13 = OpTypePointer Output %2
+%18 = OpTypePointer Output %17
+%21 = OpTypeFunction %20
+%4 = OpVariable %3 Input
+%19 = OpVariable %18 Output
+%22 = OpFunction %20 None %21
+%23 = OpLabel
+%24 = OpLoad %2 %4
+%26 = OpAccessChain %13 %19 %25
+OpStore %26 %24
+OpReturn
+OpFunctionEnd
+)";
+  constexpr char kDstNoDebug[] = R"(; SPIR-V
+; Version: 1.0
+; Generator: Google ANGLE Shader Compiler; 0
+; Bound: 27
+; Schema: 0
+OpCapability Shader
+OpMemoryModel Logical GLSL450
+OpEntryPoint Vertex %22 "main" %4 %19
+OpSource GLSL 450
+OpDecorate %4 Location 0
+OpDecorate %15 SpecId 4
+OpMemberDecorate %17 1 RelaxedPrecision
+OpMemberDecorate %17 0 BuiltIn Position
+OpMemberDecorate %17 1 BuiltIn PointSize
+OpMemberDecorate %17 2 BuiltIn ClipDistance
+OpMemberDecorate %17 3 BuiltIn CullDistance
+OpDecorate %17 Block
+%1 = OpTypeFloat 32
+%2 = OpTypeVector %1 4
+%5 = OpTypeInt 32 0
+%8 = OpTypeVector %5 4
+%15 = OpSpecConstant %5 8
+%16 = OpTypeArray %1 %15
+%17 = OpTypeStruct %2 %1 %16 %16
+%20 = OpTypeVoid
+%25 = OpConstant %5 0
+%3 = OpTypePointer Input %2
+%13 = OpTypePointer Output %2
+%18 = OpTypePointer Output %17
+%21 = OpTypeFunction %20
+%4 = OpVariable %3 Input
+%19 = OpVariable %18 Output
+%22 = OpFunction %20 None %21
+%23 = OpLabel
+%24 = OpLoad %2 %4
+%26 = OpAccessChain %13 %19 %25
+OpStore %26 %24
+OpReturn
+OpFunctionEnd
+)";
+  constexpr char kDiff[] = R"( ; SPIR-V
+ ; Version: 1.6
+ ; Generator: Khronos SPIR-V Tools Assembler; 0
+-; Bound: 27
++; Bound: 36
+ ; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Vertex %22 "main" %4 %19
+ OpSource GLSL 450
+ OpDecorate %4 Location 0
++OpDecorate %34 SpecId 4
+ OpMemberDecorate %17 1 RelaxedPrecision
+ OpMemberDecorate %17 0 BuiltIn Position
+ OpMemberDecorate %17 1 BuiltIn PointSize
+ OpMemberDecorate %17 2 BuiltIn ClipDistance
+ OpMemberDecorate %17 3 BuiltIn CullDistance
+ OpDecorate %17 Block
+ %1 = OpTypeFloat 32
+ %2 = OpTypeVector %1 4
+ %5 = OpTypeInt 32 0
+ %8 = OpTypeVector %5 4
+-%15 = OpConstant %5 8
+-%16 = OpTypeArray %1 %15
++%34 = OpSpecConstant %5 8
++%35 = OpTypeArray %1 %34
+-%17 = OpTypeStruct %2 %1 %16 %16
++%17 = OpTypeStruct %2 %1 %35 %35
+ %20 = OpTypeVoid
+ %25 = OpConstant %5 0
+ %3 = OpTypePointer Input %2
+ %13 = OpTypePointer Output %2
+ %18 = OpTypePointer Output %17
+ %21 = OpTypeFunction %20
+ %4 = OpVariable %3 Input
+ %19 = OpVariable %18 Output
+ %22 = OpFunction %20 None %21
+ %23 = OpLabel
+ %24 = OpLoad %2 %4
+ %26 = OpAccessChain %13 %19 %25
+ OpStore %26 %24
+ OpReturn
+ OpFunctionEnd
+)";
+  Options options;
+  DoStringDiffTest(kSrcNoDebug, kDstNoDebug, kDiff, options);
+}
+
+}  // namespace
+}  // namespace diff
+}  // namespace spvtools

+ 47 - 0
ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/spec_constant_array_size_dst.spvasm

@@ -0,0 +1,47 @@
+; SPIR-V
+; Version: 1.0
+; Generator: Google ANGLE Shader Compiler; 0
+; Bound: 27
+; Schema: 0
+OpCapability Shader
+OpMemoryModel Logical GLSL450
+OpEntryPoint Vertex %22 "main" %4 %19
+OpSource GLSL 450
+OpName %4 "_ua_position"
+OpName %17 "gl_PerVertex"
+OpMemberName %17 0 "gl_Position"
+OpMemberName %17 1 "gl_PointSize"
+OpMemberName %17 2 "gl_ClipDistance"
+OpMemberName %17 3 "gl_CullDistance"
+OpName %19 ""
+OpName %22 "main"
+OpDecorate %4 Location 0
+OpDecorate %15 SpecId 4
+OpMemberDecorate %17 1 RelaxedPrecision
+OpMemberDecorate %17 0 BuiltIn Position
+OpMemberDecorate %17 1 BuiltIn PointSize
+OpMemberDecorate %17 2 BuiltIn ClipDistance
+OpMemberDecorate %17 3 BuiltIn CullDistance
+OpDecorate %17 Block
+%1 = OpTypeFloat 32
+%2 = OpTypeVector %1 4
+%5 = OpTypeInt 32 0
+%8 = OpTypeVector %5 4
+%15 = OpSpecConstant %5 8
+%16 = OpTypeArray %1 %15
+%17 = OpTypeStruct %2 %1 %16 %16
+%20 = OpTypeVoid
+%25 = OpConstant %5 0
+%3 = OpTypePointer Input %2
+%13 = OpTypePointer Output %2
+%18 = OpTypePointer Output %17
+%21 = OpTypeFunction %20
+%4 = OpVariable %3 Input
+%19 = OpVariable %18 Output
+%22 = OpFunction %20 None %21
+%23 = OpLabel
+%24 = OpLoad %2 %4
+%26 = OpAccessChain %13 %19 %25
+OpStore %26 %24
+OpReturn
+OpFunctionEnd

+ 48 - 0
ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/spec_constant_array_size_src.spvasm

@@ -0,0 +1,48 @@
+;; Tests that identical specialization constants are not matched with constants
+;; when used as array size.
+; SPIR-V
+; Version: 1.0
+; Generator: Google ANGLE Shader Compiler; 0
+; Bound: 27
+; Schema: 0
+OpCapability Shader
+OpMemoryModel Logical GLSL450
+OpEntryPoint Vertex %22 "main" %4 %19
+OpSource GLSL 450
+OpName %4 "_ua_position"
+OpName %17 "gl_PerVertex"
+OpMemberName %17 0 "gl_Position"
+OpMemberName %17 1 "gl_PointSize"
+OpMemberName %17 2 "gl_ClipDistance"
+OpMemberName %17 3 "gl_CullDistance"
+OpName %19 ""
+OpName %22 "main"
+OpDecorate %4 Location 0
+OpMemberDecorate %17 1 RelaxedPrecision
+OpMemberDecorate %17 0 BuiltIn Position
+OpMemberDecorate %17 1 BuiltIn PointSize
+OpMemberDecorate %17 2 BuiltIn ClipDistance
+OpMemberDecorate %17 3 BuiltIn CullDistance
+OpDecorate %17 Block
+%1 = OpTypeFloat 32
+%2 = OpTypeVector %1 4
+%5 = OpTypeInt 32 0
+%8 = OpTypeVector %5 4
+%15 = OpConstant %5 8
+%16 = OpTypeArray %1 %15
+%17 = OpTypeStruct %2 %1 %16 %16
+%20 = OpTypeVoid
+%25 = OpConstant %5 0
+%3 = OpTypePointer Input %2
+%13 = OpTypePointer Output %2
+%18 = OpTypePointer Output %17
+%21 = OpTypeFunction %20
+%4 = OpVariable %3 Input
+%19 = OpVariable %18 Output
+%22 = OpFunction %20 None %21
+%23 = OpLabel
+%24 = OpLoad %2 %4
+%26 = OpAccessChain %13 %19 %25
+OpStore %26 %24
+OpReturn
+OpFunctionEnd

+ 186 - 0
ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/spec_constant_composite_autogen.cpp

@@ -0,0 +1,186 @@
+// GENERATED FILE - DO NOT EDIT.
+// Generated by generate_tests.py
+//
+// 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 "../diff_test_utils.h"
+
+#include "gtest/gtest.h"
+
+namespace spvtools {
+namespace diff {
+namespace {
+
+// Tests OpSpecConstantComposite matching.
+constexpr char kSrc[] = R"(               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main"
+               OpExecutionMode %main LocalSize 1 1 1
+               OpSource GLSL 450
+               OpName %main "main"
+               OpDecorate %7 SpecId 3
+               OpDecorate %8 SpecId 4
+               OpDecorate %gl_WorkGroupSize BuiltIn WorkgroupSize
+       %void = OpTypeVoid
+          %3 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+          %7 = OpSpecConstant %uint 1
+          %8 = OpSpecConstant %uint 1
+     %uint_1 = OpConstant %uint 1
+     %v3uint = OpTypeVector %uint 3
+%gl_WorkGroupSize = OpSpecConstantComposite %v3uint %7 %8 %uint_1
+       %main = OpFunction %void None %3
+          %5 = OpLabel
+               OpReturn
+               OpFunctionEnd)";
+constexpr char kDst[] = R"(               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main"
+               OpExecutionMode %main LocalSize 1 1 1
+               OpSource GLSL 450
+               OpName %main "main"
+               OpDecorate %7 SpecId 3
+               OpDecorate %8 SpecId 4
+               OpDecorate %gl_WorkGroupSize BuiltIn WorkgroupSize
+       %void = OpTypeVoid
+          %3 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+          %7 = OpSpecConstant %uint 2048
+          %8 = OpSpecConstant %uint 1
+     %uint_1 = OpConstant %uint 1
+     %v3uint = OpTypeVector %uint 3
+%gl_WorkGroupSize = OpSpecConstantComposite %v3uint %7 %8 %uint_1
+       %main = OpFunction %void None %3
+          %5 = OpLabel
+               OpReturn
+               OpFunctionEnd
+)";
+
+TEST(DiffTest, SpecConstantComposite) {
+  constexpr char kDiff[] = R"( ; SPIR-V
+ ; Version: 1.6
+ ; Generator: Khronos SPIR-V Tools Assembler; 0
+ ; Bound: 12
+ ; Schema: 0
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %2 "main"
+ OpExecutionMode %2 LocalSize 1 1 1
+ OpSource GLSL 450
+ OpName %2 "main"
+ OpDecorate %7 SpecId 3
+ OpDecorate %8 SpecId 4
+ OpDecorate %4 BuiltIn WorkgroupSize
+ %6 = OpTypeVoid
+ %3 = OpTypeFunction %6
+ %9 = OpTypeInt 32 0
+-%7 = OpSpecConstant %9 1
++%7 = OpSpecConstant %9 2048
+ %8 = OpSpecConstant %9 1
+ %10 = OpConstant %9 1
+ %11 = OpTypeVector %9 3
+ %4 = OpSpecConstantComposite %11 %7 %8 %10
+ %2 = OpFunction %6 None %3
+ %5 = OpLabel
+ OpReturn
+ OpFunctionEnd
+)";
+  Options options;
+  DoStringDiffTest(kSrc, kDst, kDiff, options);
+}
+
+TEST(DiffTest, SpecConstantCompositeNoDebug) {
+  constexpr char kSrcNoDebug[] = R"(               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main"
+               OpExecutionMode %main LocalSize 1 1 1
+               OpSource GLSL 450
+               OpDecorate %7 SpecId 3
+               OpDecorate %8 SpecId 4
+               OpDecorate %gl_WorkGroupSize BuiltIn WorkgroupSize
+       %void = OpTypeVoid
+          %3 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+          %7 = OpSpecConstant %uint 1
+          %8 = OpSpecConstant %uint 1
+     %uint_1 = OpConstant %uint 1
+     %v3uint = OpTypeVector %uint 3
+%gl_WorkGroupSize = OpSpecConstantComposite %v3uint %7 %8 %uint_1
+       %main = OpFunction %void None %3
+          %5 = OpLabel
+               OpReturn
+               OpFunctionEnd
+)";
+  constexpr char kDstNoDebug[] = R"(               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main"
+               OpExecutionMode %main LocalSize 1 1 1
+               OpSource GLSL 450
+               OpDecorate %7 SpecId 3
+               OpDecorate %8 SpecId 4
+               OpDecorate %gl_WorkGroupSize BuiltIn WorkgroupSize
+       %void = OpTypeVoid
+          %3 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+          %7 = OpSpecConstant %uint 2048
+          %8 = OpSpecConstant %uint 1
+     %uint_1 = OpConstant %uint 1
+     %v3uint = OpTypeVector %uint 3
+%gl_WorkGroupSize = OpSpecConstantComposite %v3uint %7 %8 %uint_1
+       %main = OpFunction %void None %3
+          %5 = OpLabel
+               OpReturn
+               OpFunctionEnd
+)";
+  constexpr char kDiff[] = R"( ; SPIR-V
+ ; Version: 1.6
+ ; Generator: Khronos SPIR-V Tools Assembler; 0
+ ; Bound: 12
+ ; Schema: 0
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %2 "main"
+ OpExecutionMode %2 LocalSize 1 1 1
+ OpSource GLSL 450
+ OpDecorate %7 SpecId 3
+ OpDecorate %8 SpecId 4
+ OpDecorate %4 BuiltIn WorkgroupSize
+ %6 = OpTypeVoid
+ %3 = OpTypeFunction %6
+ %9 = OpTypeInt 32 0
+-%7 = OpSpecConstant %9 1
++%7 = OpSpecConstant %9 2048
+ %8 = OpSpecConstant %9 1
+ %10 = OpConstant %9 1
+ %11 = OpTypeVector %9 3
+ %4 = OpSpecConstantComposite %11 %7 %8 %10
+ %2 = OpFunction %6 None %3
+ %5 = OpLabel
+ OpReturn
+ OpFunctionEnd
+)";
+  Options options;
+  DoStringDiffTest(kSrcNoDebug, kDstNoDebug, kDiff, options);
+}
+
+}  // namespace
+}  // namespace diff
+}  // namespace spvtools

+ 22 - 0
ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/spec_constant_composite_dst.spvasm

@@ -0,0 +1,22 @@
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main"
+               OpExecutionMode %main LocalSize 1 1 1
+               OpSource GLSL 450
+               OpName %main "main"
+               OpDecorate %7 SpecId 3
+               OpDecorate %8 SpecId 4
+               OpDecorate %gl_WorkGroupSize BuiltIn WorkgroupSize
+       %void = OpTypeVoid
+          %3 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+          %7 = OpSpecConstant %uint 2048
+          %8 = OpSpecConstant %uint 1
+     %uint_1 = OpConstant %uint 1
+     %v3uint = OpTypeVector %uint 3
+%gl_WorkGroupSize = OpSpecConstantComposite %v3uint %7 %8 %uint_1
+       %main = OpFunction %void None %3
+          %5 = OpLabel
+               OpReturn
+               OpFunctionEnd

+ 23 - 0
ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/spec_constant_composite_src.spvasm

@@ -0,0 +1,23 @@
+;; Tests OpSpecConstantComposite matching.
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main"
+               OpExecutionMode %main LocalSize 1 1 1
+               OpSource GLSL 450
+               OpName %main "main"
+               OpDecorate %7 SpecId 3
+               OpDecorate %8 SpecId 4
+               OpDecorate %gl_WorkGroupSize BuiltIn WorkgroupSize
+       %void = OpTypeVoid
+          %3 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+          %7 = OpSpecConstant %uint 1
+          %8 = OpSpecConstant %uint 1
+     %uint_1 = OpConstant %uint 1
+     %v3uint = OpTypeVector %uint 3
+%gl_WorkGroupSize = OpSpecConstantComposite %v3uint %7 %8 %uint_1
+       %main = OpFunction %void None %3
+          %5 = OpLabel
+               OpReturn
+               OpFunctionEnd

+ 230 - 0
ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/unrelated_shaders_autogen.cpp

@@ -0,0 +1,230 @@
+// GENERATED FILE - DO NOT EDIT.
+// Generated by generate_tests.py
+//
+// 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 "../diff_test_utils.h"
+
+#include "gtest/gtest.h"
+
+namespace spvtools {
+namespace diff {
+namespace {
+
+// Tests diff of unrelated shaders (with different execution models).
+constexpr char kSrc[] = R"(               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Vertex %4 "main" %8 %10
+               OpSource ESSL 310
+               OpName %4 "main"
+               OpName %8 "v"
+               OpName %10 "a"
+               OpDecorate %8 Location 0
+               OpDecorate %10 Location 0
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeFloat 32
+          %7 = OpTypePointer Output %6
+          %8 = OpVariable %7 Output
+          %9 = OpTypePointer Input %6
+         %10 = OpVariable %9 Input
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+         %11 = OpLoad %6 %10
+               OpStore %8 %11
+               OpReturn
+               OpFunctionEnd
+)";
+constexpr char kDst[] = R"(               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %4 "main" %9 %11
+               OpExecutionMode %4 OriginUpperLeft
+               OpSource ESSL 310
+               OpName %4 "main"
+               OpName %9 "color"
+               OpName %11 "v"
+               OpDecorate %9 RelaxedPrecision
+               OpDecorate %9 Location 0
+               OpDecorate %11 RelaxedPrecision
+               OpDecorate %11 Location 0
+               OpDecorate %12 RelaxedPrecision
+               OpDecorate %13 RelaxedPrecision
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeFloat 32
+          %7 = OpTypeVector %6 4
+          %8 = OpTypePointer Output %7
+          %9 = OpVariable %8 Output
+         %10 = OpTypePointer Input %6
+         %11 = OpVariable %10 Input
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+         %12 = OpLoad %6 %11
+         %13 = OpCompositeConstruct %7 %12 %12 %12 %12
+               OpStore %9 %13
+               OpReturn
+               OpFunctionEnd
+
+)";
+
+TEST(DiffTest, UnrelatedShaders) {
+  constexpr char kDiff[] = R"( ; SPIR-V
+ ; Version: 1.6
+ ; Generator: Khronos SPIR-V Tools Assembler; 0
+-; Bound: 12
++; Bound: 16
+ ; Schema: 0
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+-OpEntryPoint Vertex %4 "main" %8 %10
++OpEntryPoint Fragment %4 "main" %14 %8
++OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 310
+ OpName %4 "main"
++OpName %14 "color"
+ OpName %8 "v"
+-OpName %10 "a"
++OpDecorate %14 RelaxedPrecision
++OpDecorate %14 Location 0
++OpDecorate %8 RelaxedPrecision
+ OpDecorate %8 Location 0
+-OpDecorate %10 Location 0
++OpDecorate %11 RelaxedPrecision
++OpDecorate %15 RelaxedPrecision
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %6 = OpTypeFloat 32
+-%7 = OpTypePointer Output %6
++%12 = OpTypeVector %6 4
++%13 = OpTypePointer Output %12
++%14 = OpVariable %13 Output
+-%8 = OpVariable %7 Output
++%8 = OpVariable %9 Input
+ %9 = OpTypePointer Input %6
+-%10 = OpVariable %9 Input
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+-%11 = OpLoad %6 %10
++%11 = OpLoad %6 %8
+-OpStore %8 %11
++%15 = OpCompositeConstruct %12 %11 %11 %11 %11
++OpStore %14 %15
+ OpReturn
+ OpFunctionEnd
+)";
+  Options options;
+  DoStringDiffTest(kSrc, kDst, kDiff, options);
+}
+
+TEST(DiffTest, UnrelatedShadersNoDebug) {
+  constexpr char kSrcNoDebug[] = R"(               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Vertex %4 "main" %8 %10
+               OpSource ESSL 310
+               OpDecorate %8 Location 0
+               OpDecorate %10 Location 0
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeFloat 32
+          %7 = OpTypePointer Output %6
+          %8 = OpVariable %7 Output
+          %9 = OpTypePointer Input %6
+         %10 = OpVariable %9 Input
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+         %11 = OpLoad %6 %10
+               OpStore %8 %11
+               OpReturn
+               OpFunctionEnd
+
+)";
+  constexpr char kDstNoDebug[] = R"(               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %4 "main" %9 %11
+               OpExecutionMode %4 OriginUpperLeft
+               OpSource ESSL 310
+               OpDecorate %9 RelaxedPrecision
+               OpDecorate %9 Location 0
+               OpDecorate %11 RelaxedPrecision
+               OpDecorate %11 Location 0
+               OpDecorate %12 RelaxedPrecision
+               OpDecorate %13 RelaxedPrecision
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeFloat 32
+          %7 = OpTypeVector %6 4
+          %8 = OpTypePointer Output %7
+          %9 = OpVariable %8 Output
+         %10 = OpTypePointer Input %6
+         %11 = OpVariable %10 Input
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+         %12 = OpLoad %6 %11
+         %13 = OpCompositeConstruct %7 %12 %12 %12 %12
+               OpStore %9 %13
+               OpReturn
+               OpFunctionEnd
+
+)";
+  constexpr char kDiff[] = R"( ; SPIR-V
+ ; Version: 1.6
+ ; Generator: Khronos SPIR-V Tools Assembler; 0
+-; Bound: 12
++; Bound: 15
+ ; Schema: 0
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+-OpEntryPoint Vertex %4 "main" %8 %10
++OpEntryPoint Fragment %4 "main" %8 %10
++OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 310
++OpDecorate %8 RelaxedPrecision
+ OpDecorate %8 Location 0
++OpDecorate %10 RelaxedPrecision
+ OpDecorate %10 Location 0
++OpDecorate %11 RelaxedPrecision
++OpDecorate %14 RelaxedPrecision
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %6 = OpTypeFloat 32
+-%7 = OpTypePointer Output %6
++%12 = OpTypeVector %6 4
++%13 = OpTypePointer Output %12
+-%8 = OpVariable %7 Output
++%8 = OpVariable %13 Output
+ %9 = OpTypePointer Input %6
+ %10 = OpVariable %9 Input
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ %11 = OpLoad %6 %10
++%14 = OpCompositeConstruct %12 %11 %11 %11 %11
+-OpStore %8 %11
++OpStore %8 %14
+ OpReturn
+ OpFunctionEnd
+)";
+  Options options;
+  DoStringDiffTest(kSrcNoDebug, kDstNoDebug, kDiff, options);
+}
+
+}  // namespace
+}  // namespace diff
+}  // namespace spvtools

+ 31 - 0
ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/unrelated_shaders_dst.spvasm

@@ -0,0 +1,31 @@
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %4 "main" %9 %11
+               OpExecutionMode %4 OriginUpperLeft
+               OpSource ESSL 310
+               OpName %4 "main"
+               OpName %9 "color"
+               OpName %11 "v"
+               OpDecorate %9 RelaxedPrecision
+               OpDecorate %9 Location 0
+               OpDecorate %11 RelaxedPrecision
+               OpDecorate %11 Location 0
+               OpDecorate %12 RelaxedPrecision
+               OpDecorate %13 RelaxedPrecision
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeFloat 32
+          %7 = OpTypeVector %6 4
+          %8 = OpTypePointer Output %7
+          %9 = OpVariable %8 Output
+         %10 = OpTypePointer Input %6
+         %11 = OpVariable %10 Input
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+         %12 = OpLoad %6 %11
+         %13 = OpCompositeConstruct %7 %12 %12 %12 %12
+               OpStore %9 %13
+               OpReturn
+               OpFunctionEnd
+

+ 25 - 0
ThirdParty/Glslang/External/spirv-tools/test/diff/diff_files/unrelated_shaders_src.spvasm

@@ -0,0 +1,25 @@
+;; Tests diff of unrelated shaders (with different execution models).
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Vertex %4 "main" %8 %10
+               OpSource ESSL 310
+               OpName %4 "main"
+               OpName %8 "v"
+               OpName %10 "a"
+               OpDecorate %8 Location 0
+               OpDecorate %10 Location 0
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeFloat 32
+          %7 = OpTypePointer Output %6
+          %8 = OpVariable %7 Output
+          %9 = OpTypePointer Input %6
+         %10 = OpVariable %9 Input
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+         %11 = OpLoad %6 %10
+               OpStore %8 %11
+               OpReturn
+               OpFunctionEnd
+

+ 228 - 0
ThirdParty/Glslang/External/spirv-tools/test/diff/diff_test.cpp

@@ -0,0 +1,228 @@
+// 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/diff/diff.h"
+
+#include "diff_test_utils.h"
+
+#include "source/opt/build_module.h"
+#include "source/opt/ir_context.h"
+#include "source/spirv_constant.h"
+#include "spirv-tools/libspirv.hpp"
+#include "tools/io.h"
+#include "tools/util/cli_consumer.h"
+
+#include <fstream>
+#include <string>
+
+#include "gtest/gtest.h"
+
+namespace spvtools {
+namespace diff {
+namespace {
+
+constexpr auto kDefaultEnvironment = SPV_ENV_UNIVERSAL_1_6;
+
+std::unique_ptr<spvtools::opt::IRContext> Assemble(const std::string& spirv) {
+  spvtools::SpirvTools t(kDefaultEnvironment);
+  t.SetMessageConsumer(spvtools::utils::CLIMessageConsumer);
+  std::vector<uint32_t> binary;
+  if (!t.Assemble(spirv, &binary,
+                  spvtools::SpirvTools::kDefaultAssembleOption |
+                      SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS))
+    return nullptr;
+  return spvtools::BuildModule(kDefaultEnvironment,
+                               spvtools::utils::CLIMessageConsumer,
+                               binary.data(), binary.size());
+}
+
+TEST(DiffIndentTest, Diff) {
+  const std::string src = R"(OpCapability Shader
+    %ext_inst = OpExtInstImport "GLSL.std.450"
+    OpMemoryModel Logical GLSL450
+    OpEntryPoint Fragment %main "main"
+    OpExecutionMode %main OriginUpperLeft
+    %void = OpTypeVoid
+    %func = OpTypeFunction %void
+
+    %main = OpFunction %void None %func
+    %main_entry = OpLabel
+    OpReturn
+    OpFunctionEnd;)";
+
+  const std::string dst = R"(OpCapability Shader
+    OpMemoryModel Logical GLSL450
+    OpEntryPoint Fragment %main "main"
+    OpExecutionMode %main OriginUpperLeft
+    %void = OpTypeVoid
+    %func = OpTypeFunction %void
+
+    %main = OpFunction %void None %func
+    %main_entry = OpLabel
+    OpReturn
+    OpFunctionEnd;)";
+
+  const std::string diff = R"( ; SPIR-V
+ ; Version: 1.6
+ ; Generator: Khronos SPIR-V Tools Assembler; 0
+ ; Bound: 6
+ ; Schema: 0
+                OpCapability Shader
+-          %1 = OpExtInstImport "GLSL.std.450"
+                OpMemoryModel Logical GLSL450
+                OpEntryPoint Fragment %2 "main"
+                OpExecutionMode %2 OriginUpperLeft
+           %3 = OpTypeVoid
+           %4 = OpTypeFunction %3
+           %2 = OpFunction %3 None %4
+           %5 = OpLabel
+                OpReturn
+                OpFunctionEnd
+)";
+
+  Options options;
+  options.indent = true;
+  DoStringDiffTest(src, dst, diff, options);
+}
+
+TEST(DiffNoHeaderTest, Diff) {
+  const std::string src = R"(OpCapability Shader
+    %ext_inst = OpExtInstImport "GLSL.std.450"
+    OpMemoryModel Logical GLSL450
+    OpEntryPoint Fragment %main "main"
+    OpExecutionMode %main OriginUpperLeft
+    %void = OpTypeVoid
+    %func = OpTypeFunction %void
+
+    %main = OpFunction %void None %func
+    %main_entry = OpLabel
+    OpReturn
+    OpFunctionEnd;)";
+
+  const std::string dst = R"(OpCapability Shader
+    OpMemoryModel Logical GLSL450
+    OpEntryPoint Fragment %main "main"
+    OpExecutionMode %main OriginUpperLeft
+    %void = OpTypeVoid
+    %func = OpTypeFunction %void
+
+    %main = OpFunction %void None %func
+    %main_entry = OpLabel
+    OpReturn
+    OpFunctionEnd;)";
+
+  const std::string diff = R"( OpCapability Shader
+-%1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %2 "main"
+ OpExecutionMode %2 OriginUpperLeft
+ %3 = OpTypeVoid
+ %4 = OpTypeFunction %3
+ %2 = OpFunction %3 None %4
+ %5 = OpLabel
+ OpReturn
+ OpFunctionEnd
+)";
+
+  Options options;
+  options.no_header = true;
+  DoStringDiffTest(src, dst, diff, options);
+}
+
+TEST(DiffHeaderTest, Diff) {
+  const std::string src_spirv = R"(OpCapability Shader
+    %ext_inst = OpExtInstImport "GLSL.std.450"
+    OpMemoryModel Logical GLSL450
+    OpEntryPoint Fragment %main "main"
+    OpExecutionMode %main OriginUpperLeft
+    %void = OpTypeVoid
+    %func = OpTypeFunction %void
+
+    %main = OpFunction %void None %func
+    %main_entry = OpLabel
+    OpReturn
+    OpFunctionEnd;)";
+
+  const std::string dst_spirv = R"(OpCapability Shader
+    OpMemoryModel Logical GLSL450
+    OpEntryPoint Fragment %main "main"
+    OpExecutionMode %main OriginUpperLeft
+    %void = OpTypeVoid
+    %func = OpTypeFunction %void
+
+    %main = OpFunction %void None %func
+    %main_entry = OpLabel
+    OpReturn
+    OpFunctionEnd;)";
+
+  const std::string diff = R"( ; SPIR-V
+-; Version: 1.3
++; Version: 1.2
+-; Generator: Khronos SPIR-V Tools Assembler; 3
++; Generator: Khronos Glslang Reference Front End; 10
+ ; Bound: 6
+ ; Schema: 0
+ OpCapability Shader
+-%1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %2 "main"
+ OpExecutionMode %2 OriginUpperLeft
+ %3 = OpTypeVoid
+ %4 = OpTypeFunction %3
+ %2 = OpFunction %3 None %4
+ %5 = OpLabel
+ OpReturn
+ OpFunctionEnd
+)";
+
+  // Load the src and dst modules
+  std::unique_ptr<spvtools::opt::IRContext> src = Assemble(src_spirv);
+  ASSERT_TRUE(src);
+
+  std::unique_ptr<spvtools::opt::IRContext> dst = Assemble(dst_spirv);
+  ASSERT_TRUE(dst);
+
+  // Differentiate them in the header.
+  const spvtools::opt::ModuleHeader src_header = {
+      SpvMagicNumber,
+      SPV_SPIRV_VERSION_WORD(1, 3),
+      SPV_GENERATOR_WORD(SPV_GENERATOR_KHRONOS_ASSEMBLER, 3),
+      src->module()->IdBound(),
+      src->module()->schema(),
+  };
+  const spvtools::opt::ModuleHeader dst_header = {
+      SpvMagicNumber,
+      SPV_SPIRV_VERSION_WORD(1, 2),
+      SPV_GENERATOR_WORD(SPV_GENERATOR_KHRONOS_GLSLANG, 10),
+      dst->module()->IdBound(),
+      dst->module()->schema(),
+  };
+
+  src->module()->SetHeader(src_header);
+  dst->module()->SetHeader(dst_header);
+
+  // Take the diff
+  Options options;
+  std::ostringstream diff_result;
+  spv_result_t result =
+      spvtools::diff::Diff(src.get(), dst.get(), diff_result, options);
+  ASSERT_EQ(result, SPV_SUCCESS);
+
+  // Expect they match
+  EXPECT_EQ(diff_result.str(), diff);
+}
+
+}  // namespace
+}  // namespace diff
+}  // namespace spvtools

+ 58 - 0
ThirdParty/Glslang/External/spirv-tools/test/diff/diff_test_utils.cpp

@@ -0,0 +1,58 @@
+// 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 "diff_test_utils.h"
+
+#include "source/opt/build_module.h"
+#include "source/opt/ir_context.h"
+
+#include "spirv-tools/libspirv.hpp"
+#include "tools/io.h"
+#include "tools/util/cli_consumer.h"
+
+#include "gtest/gtest.h"
+
+namespace spvtools {
+namespace diff {
+
+static constexpr auto kDefaultEnvironment = SPV_ENV_UNIVERSAL_1_6;
+
+void DoStringDiffTest(const std::string& src_spirv,
+                      const std::string& dst_spirv,
+                      const std::string& expected_diff, Options options) {
+  // Load the src and dst modules
+  std::unique_ptr<spvtools::opt::IRContext> src = spvtools::BuildModule(
+      kDefaultEnvironment, spvtools::utils::CLIMessageConsumer, src_spirv,
+      spvtools::SpirvTools::kDefaultAssembleOption |
+          SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
+  ASSERT_TRUE(src);
+
+  std::unique_ptr<spvtools::opt::IRContext> dst = spvtools::BuildModule(
+      kDefaultEnvironment, spvtools::utils::CLIMessageConsumer, dst_spirv,
+      spvtools::SpirvTools::kDefaultAssembleOption |
+          SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
+  ASSERT_TRUE(dst);
+
+  // Take the diff
+  std::ostringstream diff_result;
+  spv_result_t result =
+      spvtools::diff::Diff(src.get(), dst.get(), diff_result, options);
+  ASSERT_EQ(result, SPV_SUCCESS);
+
+  // Expect they match
+  EXPECT_EQ(diff_result.str(), expected_diff);
+}
+
+}  // namespace diff
+}  // namespace spvtools

+ 30 - 0
ThirdParty/Glslang/External/spirv-tools/test/diff/diff_test_utils.h

@@ -0,0 +1,30 @@
+// 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 TEST_DIFF_DIFF_TEST_UTILS_H_
+#define TEST_DIFF_DIFF_TEST_UTILS_H_
+
+#include "source/diff/diff.h"
+
+namespace spvtools {
+namespace diff {
+
+void DoStringDiffTest(const std::string& src_spirv,
+                      const std::string& dst_spirv,
+                      const std::string& expected_diff, Options options);
+
+}  // namespace diff
+}  // namespace spvtools
+
+#endif  // TEST_DIFF_DIFF_TEST_UTILS_H_

+ 329 - 0
ThirdParty/Glslang/External/spirv-tools/test/diff/lcs_test.cpp

@@ -0,0 +1,329 @@
+// 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/diff/lcs.h"
+
+#include <string>
+
+#include "gtest/gtest.h"
+
+namespace spvtools {
+namespace diff {
+namespace {
+
+using Sequence = std::vector<int>;
+using LCS = LongestCommonSubsequence<Sequence>;
+
+void VerifyMatch(const Sequence& src, const Sequence& dst,
+                 size_t expected_match_count) {
+  DiffMatch src_match, dst_match;
+
+  LCS lcs(src, dst);
+  size_t match_count =
+      lcs.Get<int>([](int s, int d) { return s == d; }, &src_match, &dst_match);
+
+  EXPECT_EQ(match_count, expected_match_count);
+
+  size_t src_cur = 0;
+  size_t dst_cur = 0;
+  size_t matches_seen = 0;
+
+  while (src_cur < src.size() && dst_cur < dst.size()) {
+    if (src_match[src_cur] && dst_match[dst_cur]) {
+      EXPECT_EQ(src[src_cur], dst[dst_cur])
+          << "Src: " << src_cur << " Dst: " << dst_cur;
+      ++src_cur;
+      ++dst_cur;
+      ++matches_seen;
+      continue;
+    }
+    if (!src_match[src_cur]) {
+      ++src_cur;
+    }
+    if (!dst_match[dst_cur]) {
+      ++dst_cur;
+    }
+  }
+
+  EXPECT_EQ(matches_seen, expected_match_count);
+}
+
+TEST(LCSTest, EmptySequences) {
+  Sequence src, dst;
+
+  DiffMatch src_match, dst_match;
+
+  LCS lcs(src, dst);
+  size_t match_count =
+      lcs.Get<int>([](int s, int d) { return s == d; }, &src_match, &dst_match);
+
+  EXPECT_EQ(match_count, 0u);
+  EXPECT_TRUE(src_match.empty());
+  EXPECT_TRUE(dst_match.empty());
+}
+
+TEST(LCSTest, EmptySrc) {
+  Sequence src, dst = {1, 2, 3};
+
+  DiffMatch src_match, dst_match;
+
+  LCS lcs(src, dst);
+  size_t match_count =
+      lcs.Get<int>([](int s, int d) { return s == d; }, &src_match, &dst_match);
+
+  EXPECT_EQ(match_count, 0u);
+  EXPECT_TRUE(src_match.empty());
+  EXPECT_EQ(dst_match, DiffMatch(3, false));
+}
+
+TEST(LCSTest, EmptyDst) {
+  Sequence src = {1, 2, 3}, dst;
+
+  DiffMatch src_match, dst_match;
+
+  LCS lcs(src, dst);
+  size_t match_count =
+      lcs.Get<int>([](int s, int d) { return s == d; }, &src_match, &dst_match);
+
+  EXPECT_EQ(match_count, 0u);
+  EXPECT_EQ(src_match, DiffMatch(3, false));
+  EXPECT_TRUE(dst_match.empty());
+}
+
+TEST(LCSTest, Identical) {
+  Sequence src = {1, 2, 3, 4, 5, 6}, dst = {1, 2, 3, 4, 5, 6};
+
+  DiffMatch src_match, dst_match;
+
+  LCS lcs(src, dst);
+  size_t match_count =
+      lcs.Get<int>([](int s, int d) { return s == d; }, &src_match, &dst_match);
+
+  EXPECT_EQ(match_count, 6u);
+  EXPECT_EQ(src_match, DiffMatch(6, true));
+  EXPECT_EQ(dst_match, DiffMatch(6, true));
+}
+
+TEST(LCSTest, SrcPrefix) {
+  Sequence src = {1, 2, 3, 4}, dst = {1, 2, 3, 4, 5, 6};
+
+  DiffMatch src_match, dst_match;
+
+  LCS lcs(src, dst);
+  size_t match_count =
+      lcs.Get<int>([](int s, int d) { return s == d; }, &src_match, &dst_match);
+
+  const DiffMatch src_expect = {true, true, true, true};
+  const DiffMatch dst_expect = {true, true, true, true, false, false};
+
+  EXPECT_EQ(match_count, 4u);
+  EXPECT_EQ(src_match, src_expect);
+  EXPECT_EQ(dst_match, dst_expect);
+}
+
+TEST(LCSTest, DstPrefix) {
+  Sequence src = {1, 2, 3, 4, 5, 6}, dst = {1, 2, 3, 4, 5};
+
+  DiffMatch src_match, dst_match;
+
+  LCS lcs(src, dst);
+  size_t match_count =
+      lcs.Get<int>([](int s, int d) { return s == d; }, &src_match, &dst_match);
+
+  const DiffMatch src_expect = {true, true, true, true, true, false};
+  const DiffMatch dst_expect = {true, true, true, true, true};
+
+  EXPECT_EQ(match_count, 5u);
+  EXPECT_EQ(src_match, src_expect);
+  EXPECT_EQ(dst_match, dst_expect);
+}
+
+TEST(LCSTest, SrcSuffix) {
+  Sequence src = {3, 4, 5, 6}, dst = {1, 2, 3, 4, 5, 6};
+
+  DiffMatch src_match, dst_match;
+
+  LCS lcs(src, dst);
+  size_t match_count =
+      lcs.Get<int>([](int s, int d) { return s == d; }, &src_match, &dst_match);
+
+  const DiffMatch src_expect = {true, true, true, true};
+  const DiffMatch dst_expect = {false, false, true, true, true, true};
+
+  EXPECT_EQ(match_count, 4u);
+  EXPECT_EQ(src_match, src_expect);
+  EXPECT_EQ(dst_match, dst_expect);
+}
+
+TEST(LCSTest, DstSuffix) {
+  Sequence src = {1, 2, 3, 4, 5, 6}, dst = {5, 6};
+
+  DiffMatch src_match, dst_match;
+
+  LCS lcs(src, dst);
+  size_t match_count =
+      lcs.Get<int>([](int s, int d) { return s == d; }, &src_match, &dst_match);
+
+  const DiffMatch src_expect = {false, false, false, false, true, true};
+  const DiffMatch dst_expect = {true, true};
+
+  EXPECT_EQ(match_count, 2u);
+  EXPECT_EQ(src_match, src_expect);
+  EXPECT_EQ(dst_match, dst_expect);
+}
+
+TEST(LCSTest, None) {
+  Sequence src = {1, 3, 5, 7, 9}, dst = {2, 4, 6, 8, 10, 12};
+
+  DiffMatch src_match, dst_match;
+
+  LCS lcs(src, dst);
+  size_t match_count =
+      lcs.Get<int>([](int s, int d) { return s == d; }, &src_match, &dst_match);
+
+  EXPECT_EQ(match_count, 0u);
+  EXPECT_EQ(src_match, DiffMatch(5, false));
+  EXPECT_EQ(dst_match, DiffMatch(6, false));
+}
+
+TEST(LCSTest, NonContiguous) {
+  Sequence src = {1, 2, 3, 4, 5, 6, 10}, dst = {2, 4, 5, 8, 9, 10, 12};
+
+  DiffMatch src_match, dst_match;
+
+  LCS lcs(src, dst);
+  size_t match_count =
+      lcs.Get<int>([](int s, int d) { return s == d; }, &src_match, &dst_match);
+
+  const DiffMatch src_expect = {false, true, false, true, true, false, true};
+  const DiffMatch dst_expect = {true, true, true, false, false, true, false};
+
+  EXPECT_EQ(match_count, 4u);
+  EXPECT_EQ(src_match, src_expect);
+  EXPECT_EQ(dst_match, dst_expect);
+}
+
+TEST(LCSTest, WithDuplicates) {
+  Sequence src = {1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4},
+           dst = {1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4};
+  VerifyMatch(src, dst, 6);
+}
+
+TEST(LCSTest, Large) {
+  const std::string src_str =
+      "GUJwrJSlkKJXxCVIAxlVgnUyOrdyRyFtlZwWMmFhYGfkFTNnhiBmClgHyrcXMVwfrRxNUfQk"
+      "qaoGvCbPZHAzXsaZpXHPfJxOMCUtRDmIQpfiXKbHQbhTfPqhxBDWvmTQAqwsWTLajZYtMUnf"
+      "hNNCfkuAXkZsaebwEbIZOxTDZsqSMUfCMoGeKJGVSNFgLTiBMbdvchHGfFRkHKcYCDjBfIcj"
+      "todPnvDjzQYWBcvIfVvyBzHikrwpDORaGEZLhmyztIFCLJOqeLhOzERYmVqzlsoUzruTXTXq"
+      "DLTxQRakOCMRrgRzCDTXfwwfDcKMBVnxRZemjcwcEsOVxwtwdBCWJycsDcZKlvrCvZaenKlv"
+      "vyByDQeLdxAyBnPkIMQlMQwqjUfRLybeoaOanlbFkpTPPZdHelQrIvucTHzMpWWQTbuANwvN"
+      "OVhCGGoIcGNDpfIsaBexlMMdHsxMGerTngmjpdPeQQJHfvKZkdYqAzrtDohqtDsaFMxQViVQ"
+      "YszDVgyoSHZdOXAvXkJidojLvGZOzhRajVPhWDwKuGqdaympELxHsrXAJYufdCPwJdGJfWqq"
+      "yvTWpcrFHOIuCEmNLnSCDsxQGRVDwyCykBJazhApfCnrOadnafvqfVuFqEXMSrYbHTfTnzbz"
+      "MhISyOtMUITaurCXvanCbuOXBhHyCjOhVbxnMvhlPmZBMQgEHCghtAJVMXGPNRtszVZlPxVl"
+      "QIPTBnPUPejlyZGPqeICyNngdQGkvKbIoWlTLBtVhMdBeUMozNlKQTIPYBeImVcMdLafuxUf"
+      "TIXysmcTrUTcspOSKBxhdhLwiRnREGFWJTfUKsgGOAQeYojXdrqsGjMJfiKalyoiqrgLnlij"
+      "CtOapoxDGVOOBalNYGzCtBlxbvaAzxipGnJpOEbmXcpeoIsAdxspKBzBDgoPVxnuRBUwmTSr"
+      "CRpWhxikgUYQVCwalLUIeBPRyhhsECGCXJmGDZSCIUaBwROkigzdeVPOXhgCGBEprWtNdYfL"
+      "tOUYJHQXxiIJgSGmWntezJFpNQoTPbRRYAGhtYvAechvBcYWocLkYFxsDAuszvQNLXdhmAHw"
+      "DErcjbtCdQllnKcDADVNWVezljjLrAuyGHetINMgAvJZwOEYakihYVUbZGCsHEufluLNyNHy"
+      "gqtSTSFFjBHiIqQejTPWybLdpWNwZrWvIWnlzUcGNQPEYHVPCbteWknjAnWrdTBeCbHUDBoK"
+      "aHvDStmpNRGIjvlumiZTbdZNAzUeSFnFChCsSExwXeEfDJfjyOoSBofHzJqJErvHLNyUJTjX"
+      "qmtgKPpMKohUPBMhtCteQFcNEpWrUVGbibMOpvBwdiWYXNissArpSasVJFgDzrqTyGkerTMX"
+      "gcrzFUGFZRhNdekaJeKYPogsofJaRsUQmIRyYdkrxKeMgLPpwOfSKJOqzXDoeHljTzhOwEVy"
+      "krOEnACFrWhufajsMitjOWdLOHHchQDddGPzxknEgdwmZepKDvRZGCuPqzeQkjOPqUBKpKLJ"
+      "eKieSsRXkaqxSPGajfvPKmwFWdLByEcLgvrmteazgFjmMGrLYqRRxzUOfOCokenqHVYstBHf"
+      "AwsWsqPTvqsRJUfGGTaYiylZMGbQqTzINhFHvdlRQvvYKBcuAHdBeKlHSxVrSsEKbcAvnIcf"
+      "xzdVDdwQPHMCHeZZRpGHWvKzgTGzSTbYTeOPyKvvYWmQToTpsjAtKUJUjcEHWhmdBLDTBMHJ"
+      "ivBXcLGtCsumNNVFyGbVviGmqHTdyBlkneibXBesKJGOUzOtIwXCPJggqBekSzNQYkALlItk"
+      "cbEhbdXAIKVHYpInLwxXalKZrkrpxtfuagqMGmRJnJbFQaEoYMoqPsxZpocddPXXPyvxVkaF"
+      "qdKISejWDhBImnEEOPDcyWTubbfVfwUztciaFJcsPLhgYVfhqlOfoNjKbmTFptFttYuyBrUI"
+      "zzmZypOqrjQHTGFwlHStpIwxPtMvtsEDpsmWIgwzYgwmdpbMOnfElZMYpVIcvzSWejeJcdUB"
+      "QUoBRUmGQVVWvEDseuozrDjgdXFScPwwsgaUPwSzScfBNrkpmEFDSZLKfNjMqvOmUtocUkbo"
+      "VGFEKgGLbNruwLgXHTloWDrnqymPVAtzjWPutonIsMDPeeCmTjYWAFXcyTAlBeiJTIRkZxiM"
+      "kLjMnAflSNJzmZkatXkYiPEMYSmzHbLKEizHbEjQOxBDzpRHiFjhedqiyMiUMvThjaRFmwll"
+      "aMGgwKBIKepwyoEdnuhtzJzboiNEAFKiqiWxxmkRFRoTiFWXLPAWLuzSCrajgkQhDxAQDqyM"
+      "VwZlhZicQLEDYYisEalesDWZAYzcvENuHUwRutIsGgsdoYwOZiURhcgdbTGWBNqhrFjvTQCj"
+      "VlTPNlRdRLaaqzUBBwbdtyXFkCBUYYMbmRrkFxfxbCqkgZNGyHPKLkOPnezfVTRmRQgCgHbx"
+      "wcZlInVOwmFePnSIbThMJosimzkhfuiqYEpwHQiemqsSDNNdbNhBLzbsPZBJZujSHJGtYKGb"
+      "HaAYGJZxBumsKUrATwPuqXFLfwNyImLQbchBKiJAYRZhkcrKCHXBEGYyBhBGvSqvabcRUrfq"
+      "AbPiMzjHAehGYjDEmxAnYLyoSFdeWVrfJUCuYZPluhXEBuyUpKaRXDKXeiCvGidpvATwMbcz"
+      "DZpzxrhTZYyrFORFQWTbPLCBjMKMhlRMFEiarDgGPttjmkrQVlujztMSkxXffXFNqLWOLThI"
+      "KBoyMHoFTEPCdUAZjLTifAdjjUehyDLEGKlRTFoLpjalziRSUjZfRYbNzhiHgTHowMMkKTwE"
+      "ZgnqiirMtnNpaBJqhcIVrWXPpcPWZfRpsPstHleFJDZYAsxYhOREVbFtebXTZRAIjGgWeoiN"
+      "qPLCCAVadqmUrjOcqIbdCTpcDRWuDVbHrZOQRPhqbyvOWwxAWJphjLiDgoAybcjzgfVktPlj"
+      "kNBCjelpuQfnYsiTgPpCNKYtOrxGaLEEtAuLdGdDsONHNhSn";
+  const std::string dst_str =
+      "KzitfifORCbGhfNEbnbObUdFLLaAsLOpMkOeKupjCoatzqfHBkNJfSgqSMYouswfNMnoQngK"
+      "jWwyPKmEnoZWyPBUdQRmKUNudUclueKXKQefUdXWUyyqtumzsFKznrLVLwfvPZpLChNYrrHK"
+      "AtpfOuVHiUKyeRCrktJAhkyFKmPWrASEMvBLNOzuGlvinZjvZUUXazNEkyMPiOLdqXvCIroC"
+      "MeWsvjHShlLhDwLZrVlpYBnDJmILcsNFDSoaLWOKNNkNGBgNBvVjPCJXAuKfsrKZhYcdEpxK"
+      "UihiRkYvMiLyOUvaqBMklLDwEhvQBfCXHSRoqsLsSCzLZQhIYMhBapvHaPbDoRrHoJXZsNXc"
+      "rxZYCrOMIzYcVPwDCFiHBFnPNTTeAeKEMGeVUeCaAeuWZmngyPWlQBcgWumSUIfbhjVYdnpV"
+      "hRSJXrIoFZubBXfNOMhilAkVPixrhILZKgDoFTvytPFPfBLMnbhSOBmLWCbJsLQxrCrMAlOw"
+      "RmfSQyGhrjhzYVqFSBHeoQBagFwyxIjcHFZngntpVHbSwqhwHeMnWSsISPljTxSNXfCxLebW"
+      "GhMdlphtJbdvhEcjNpwPCFqhdquxCyOxkjsDUPNgjpDcpIMhMwMclNhfESTrroJaoyeGQclV"
+      "gonnhuQRmXcBwcsWeLqjNngZOlyMyfeQBwnwMVJEvGqknDyzSApniRTPgJpFoDkJJhXQFuFB"
+      "VqhuEPMRGCeTDOSEFmXeIHOnDxaJacvnmORwVpmrRhGjDpUCkuODNPdZMdupYExDEDnDLdNF"
+      "iObKBaVWpGVMKdgNLgsNxcpypBPPKKoaajeSGPZQJWSOKrkLjiFexYVmUGxJnbTNsCXXLfZp"
+      "jfxQAEVYvqKehBzMsVHVGWmTshWFAoCNDkNppzzjHBZWckrzSTANICioCJSpLwPwQvtXVxst"
+      "nTRBAboPFREEUFazibpFesCsjzUOnECwoPCOFiwGORlIZVLpUkJyhYXCENmzTBLVigOFuCWO"
+      "IiXBYmiMtsxnUdoqSTTGyEFFrQsNAjcDdOKDtHwlANWoUVwiJCMCQFILdGqzEePuSXFbOEOz"
+      "dLlEnTJbKRSTfAFToOZNtDXTfFgvQiefAKbSUWUXFcpCjRYCBNXCCcLMjjuUDXErpiNsRuIx"
+      "mgHsrObTEXcnmjdqxTGhTjTeYizNnkrJRhNQIqDXmZMwArBccnixpcuiGOOexjgkpcEyGAnz"
+      "UbgiBfflTUyJfZeFFLrZVueFkSRosebnnwAnakIrywTGByhQKWvmNQJsWQezqLhHQzXnEpeD"
+      "rFRTSQSpVxPzSeEzfWYzfpcenxsUyzOMLxhNEhfcuprDtqubsXehuqKqZlLQeSclvoGjuKJK"
+      "XoWrazsgjXXnkWHdqFESZdMGDYldyYdbpSZcgBPgEKLWZHfBirNPLUadmajYkiEzmGuWGELB"
+      "WLiSrMdaGSbptKmgYVqMGcQaaATStiZYteGAPxSEBHuAzzjlRHYsrdDkaGNXmzRGoalJMiCC"
+      "GMtWSDMhgvRSEgKnywbRgnqWXFlwrhXbbvcgLGtWSuKQBiqIlWkfPMozOTWgVoLHavDJGRYI"
+      "YerrmZnTMtuuxmZALWakfzUbksTwoetqkOiRPGqGZepcVXHoZyOaaaijjZWQLlIhYwiQNbfc"
+      "KCwhhFaMQBoaCnOecJEdKzdsMPFEYQuJNPYiiNtsYxaWBRuWjlLqGokHMNtyTQfSJKbgGdol"
+      "fWlOZdupouQMfUWXIYHzyJHefMDnqxxasDxtgArvDqtwjDBaVEMACPkLFpiDOoKCHqkWVizh"
+      "lKqbOHpsPKkhjRQRNGYRYEfxtBjYvlCvHBNUwVuIwDJYMqHxEFtwdLqYWvjdOfQmNiviDfUq"
+      "pbucbNwjNQfMYgwUuPnQWIPOlqHcbjtuDXvTzLtkdBQanJbrmLSyFqSapZCSPMDOrxWVYzyO"
+      "lwDTTJFmKxoyfPunadkHcrcSQaQsAbrQtbhqwSTXGTPURYTCbNozjAVwbmcyVxIbZudBZWYm"
+      "rnSDyelGCRRWYtrUxvOVWlTLHHdYuAmVMGnGbHscbjmjmAzmYLaCxNNwhmMYdExKvySxuYpE"
+      "rVGwfqMngBCHnZodotNaNJZiNRFWubuPDfiywXPiyVWoQMeOlSuWmpilLTIFOvfpjmJTgrWa"
+      "dgoxYeyPyOaglOvZVGdFOBSeqEcGXBwjoeUAXqkpvOxEpSXhmklKZydTvRVYVvfQdRNNDkCT"
+      "dLNfcZCFQbZORdcDOhwotoyccrSbWvlqYMoiAYeEpDzZTvkamapzZMmCpEutZFCcHBWGIIkr"
+      "urwDNHrobaErPpclyEegLJDtkfUWSNWZosWSbBGAHIvJsFNUlJXbnkSVycLkOVQVcNcUtiBy"
+      "djLDIFsycbPBEWaMvCbntNtJlOeCttvXypGnHAQFnFSiXFWWqonWuVIKmVPpKXuJtFguXCWC"
+      "rNExYYvxLGEmuZJLJDjHgjlQyOzeieCpizJxkrdqKCgomyEkvsyVYSsLeyLvOZQrrgEJgRFK"
+      "CjYtoOfluNrLdRMTRkQXmAiMRFwloYECpXCReAMxOkNiwCtutsrqWoMHsrogRqPoUCueonvW"
+      "MTwmkAkajfGJkhnQidwpwIMEttQkzIMOPvvyWZHpqkMHWlNTeSKibfRfwDyxveKENZhtlPwP"
+      "dfAjwegjRcavtFnkkTNVYdCdCrgdUvzsIcqmUjwGmVvuuQvjVrWWIDBmAzQtiZPYvCOEWjce"
+      "rWzeqVKeiYTJBOedmQCVidOgUIEjfRnbGvUbctYxfRybJkdmeAkLZQMRMGPOnsPbFswXAoCK"
+      "IxWGwohoPpEJxslbqHFKSwknxTmrDCITRZWEDkGQeucPxHBdYkduwbYhKnoxCKhgjBFiFawC"
+      "QtgTDldTQmlOsBiGLquMjuecAbrUJJvNtXbFNGjWxaZPimSRXUJWgRbydpsczOqSFIeEtuKA"
+      "ZpRhmLtPdVNKdSDQZeeImUFmUwXApRTUNHItyvFyJtNtn";
+
+  Sequence src;
+  Sequence dst;
+
+  src.reserve(src_str.length());
+  dst.reserve(dst_str.length());
+
+  for (char c : src_str) {
+    src.push_back(c);
+  }
+  for (char c : dst_str) {
+    dst.push_back(c);
+  }
+
+  VerifyMatch(src, dst, 723);
+}
+
+}  // namespace
+}  // namespace diff
+}  // namespace spvtools

+ 201 - 0
ThirdParty/Glslang/External/spirv-tools/tools/diff/diff.cpp

@@ -0,0 +1,201 @@
+// 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.
+
+#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
+#include <unistd.h>
+#endif
+
+#include "source/diff/diff.h"
+
+#include "source/opt/build_module.h"
+#include "source/opt/ir_context.h"
+#include "spirv-tools/libspirv.hpp"
+#include "tools/io.h"
+#include "tools/util/cli_consumer.h"
+
+static void print_usage(char* argv0) {
+  printf(R"(%s - Compare two SPIR-V files
+
+Usage: %s <src_filename> <dst_filename>
+
+The SPIR-V binary is read from <src_filename> and <dst_filename>.  If either
+file ends in .spvasm, the SPIR-V is read as text and disassembled.
+
+The contents of the SPIR-V modules are analyzed and a diff is produced showing a
+logical transformation from src to dst, in src's id-space.
+
+  -h, --help      Print this help.
+  --version       Display diff version information.
+
+  --color         Force color output.  The default when printing to a terminal.
+                  Overrides a previous --no-color option.
+  --no-color      Don't print in color.  Overrides a previous --color option.
+                  The default when output goes to something other than a
+                  terminal (e.g. a pipe, or a shell redirection).
+
+  --no-indent     Don't indent instructions.
+
+  --no-header     Don't output the header as leading comments.
+
+  --with-id-map   Also output the mapping between src and dst outputs.
+
+  --ignore-set-binding
+                  Don't use set/binding decorations for variable matching.
+  --ignore-location
+                  Don't use location decorations for variable matching.
+)",
+         argv0, argv0);
+}
+
+static const auto kDefaultEnvironment = SPV_ENV_UNIVERSAL_1_6;
+
+static bool is_assembly(const char* path) {
+  const char* suffix = strrchr(path, '.');
+  if (suffix == nullptr) {
+    return false;
+  }
+
+  return strcmp(suffix, ".spvasm") == 0;
+}
+
+static std::unique_ptr<spvtools::opt::IRContext> load_module(const char* path) {
+  if (is_assembly(path)) {
+    std::vector<char> contents;
+    if (!ReadTextFile<char>(path, &contents)) return {};
+
+    return spvtools::BuildModule(
+        kDefaultEnvironment, spvtools::utils::CLIMessageConsumer,
+        std::string(contents.begin(), contents.end()),
+        spvtools::SpirvTools::kDefaultAssembleOption |
+            SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
+  }
+
+  std::vector<uint32_t> contents;
+  if (!ReadBinaryFile<uint32_t>(path, &contents)) return {};
+
+  return spvtools::BuildModule(kDefaultEnvironment,
+                               spvtools::utils::CLIMessageConsumer,
+                               contents.data(), contents.size());
+}
+
+int main(int argc, char** argv) {
+  const char* src_file = nullptr;
+  const char* dst_file = nullptr;
+  bool color_is_possible =
+#if SPIRV_COLOR_TERMINAL
+      true;
+#else
+      false;
+#endif
+  bool force_color = false;
+  bool force_no_color = false;
+  bool allow_indent = true;
+  bool no_header = false;
+  bool dump_id_map = false;
+  bool ignore_set_binding = false;
+  bool ignore_location = false;
+
+  for (int argi = 1; argi < argc; ++argi) {
+    if ('-' == argv[argi][0]) {
+      switch (argv[argi][1]) {
+        case 'h':
+          print_usage(argv[0]);
+          return 0;
+        case '-': {
+          // Long options
+          if (strcmp(argv[argi], "--no-color") == 0) {
+            force_no_color = true;
+            force_color = false;
+          } else if (strcmp(argv[argi], "--color") == 0) {
+            force_no_color = false;
+            force_color = true;
+          } else if (strcmp(argv[argi], "--no-indent") == 0) {
+            allow_indent = false;
+          } else if (strcmp(argv[argi], "--no-header") == 0) {
+            no_header = true;
+          } else if (strcmp(argv[argi], "--with-id-map") == 0) {
+            dump_id_map = true;
+          } else if (strcmp(argv[argi], "--ignore-set-binding") == 0) {
+            ignore_set_binding = true;
+          } else if (strcmp(argv[argi], "--ignore-location") == 0) {
+            ignore_location = true;
+          } else if (strcmp(argv[argi], "--help") == 0) {
+            print_usage(argv[0]);
+            return 0;
+          } else if (strcmp(argv[argi], "--version") == 0) {
+            printf("%s\n", spvSoftwareVersionDetailsString());
+            printf("Target: %s\n",
+                   spvTargetEnvDescription(kDefaultEnvironment));
+            return 0;
+          } else {
+            print_usage(argv[0]);
+            return 1;
+          }
+        } break;
+        default:
+          print_usage(argv[0]);
+          return 1;
+      }
+    } else {
+      if (src_file == nullptr) {
+        src_file = argv[argi];
+      } else if (dst_file == nullptr) {
+        dst_file = argv[argi];
+      } else {
+        fprintf(stderr, "error: More than two input files specified\n");
+        return 1;
+      }
+    }
+  }
+
+  if (src_file == nullptr || dst_file == nullptr) {
+    print_usage(argv[0]);
+    return 1;
+  }
+
+  spvtools::diff::Options options;
+
+  if (allow_indent) options.indent = true;
+  if (no_header) options.no_header = true;
+  if (dump_id_map) options.dump_id_map = true;
+  if (ignore_set_binding) options.ignore_set_binding = true;
+  if (ignore_location) options.ignore_location = true;
+
+  if (color_is_possible && !force_no_color) {
+    bool output_is_tty = true;
+#if defined(_POSIX_VERSION)
+    output_is_tty = isatty(fileno(stdout));
+#endif
+    if (output_is_tty || force_color) {
+      options.color_output = true;
+    }
+  }
+
+  std::unique_ptr<spvtools::opt::IRContext> src = load_module(src_file);
+  std::unique_ptr<spvtools::opt::IRContext> dst = load_module(dst_file);
+
+  if (!src) {
+    fprintf(stderr, "error: Loading src file\n");
+  }
+  if (!dst) {
+    fprintf(stderr, "error: Loading dst file\n");
+  }
+  if (!src || !dst) {
+    return 1;
+  }
+
+  spvtools::diff::Diff(src.get(), dst.get(), std::cout, options);
+
+  return 0;
+}