Update SPIR-V Tools to d18d0d92e
Changes:
d18d0d92e Optimize DefUseManager allocations (#4709)
a123632ed Optimize Type::HashValue (#4707)
471428a04 spirv-opt: Add OpExecutionModeId support (#4719)
72e4475b4 Handle propagation of arrays with decorations (#4717)
899e53a1d Bump pathval from 1.1.0 to 1.1.1 in /tools/sva (#4716)
53078eec1 Add OpModuleProcessed to debug opcode (#4694)
0ad83f913 spirv-diff: Match OpSpecConstantComposite correctly (#4704)
940127a77 avoid unnecessary reallocations in GetOperandConstants (#4708)
44923beb5 Optimize Instruction::Instruction (#4705)
a383c476e Remove reference to protobuf internals from fuzzers (#4701)
ff91f9449 [spirv-val] Allow 0 Component Count for DebugTypeArray for Shader (#4706)
f182d0205 Generalize the copyright check (#4702)
9fe41e60d Update test for parsing memory access masks (#4703)
332475dbc spirv-diff: Handle OpSpecConstant array sizes (#4700)
9beb54513 Stabilize the output of spirv-diff (#4698)
845f3efb8 Disable spirv-diff tests. (#4695)
5b371918b Have scalar replacement use undef instead of null (#4691)
7fa9e746e Introduce spirv-diff (#4611)
b846f8f1d Complete handling of RayQueryKHR type (#4690)
20b122b2e Fix handling of Nontemporal image operand (#4692)
a73e72435 Fix typo in comment: SPIR-V section for debug instructions (#4683)
65ecfd109 Fix various source comment (doxygen) typos (#4680)
ff91b1c27 Start SPIRV-Tools v2022.2
b1877de5c Finalize SPIRV-Tools v2022.1
73735db94 Update CHANGES
d492ebded Update DEPS file (#4688)
5003644f5 Fix roll_deps.sh (#4687)
fb9a10cd4 spirv-opt: add pass to Spread Volatile semantics (#4667)
6938af7f8 Vulkan 1.3 (#4686)
e8439c1c9 Avoid infinite recursion in comparison operators on SmallVector (#4681)
58d8b4e29 linker: Address conversion error introduced in earlier rework (#4685)
c38495656 Linker improvements (#4679)
8a40f6de5 Add SPIR-V 1.6 support to wasm build (#4674)
42dc67891 Remove duplicated "the" from comments (#4666)
8fda47ca0 Disable a codepage warning on non-English OS (#4668)
05c839ca0 Improvements to disassembly within PassManager (#4677)
b9e0e13d1 Remove misleading comment. (#4676)
c5ee1bc7b Fix opt fuzzer test harness (#4670)
75e53b9f6 Avoid uninitialized access to instruction opcode (#4673)
df2aad68b val: interface struct with builtins must be Block (#4665)
5d0e3240f Patch location validation VUIDs (#4664)
7d768812e Basic support for SPIR-V 1.6 (#4663)
b7251d4fb reflect debug (#4662)
354a46a2a Rename strip reflect to strip nonsemantic (#4661)
4322c4b5a Refactor the disassembler code for reuse (#4616)
f0351b7bc Avoid id bound errors during opt fuzzing (#4658)
ff07cfd86 CMake iOS fixes: rely on CMAKE_SYSTEM_NAME and handle bundle installation (#4619)
e45279259 Simplify the as fuzzer target (#4647)
315615887 optimizer: restore previous ABI. (#4653)
a2260d3b1 Fix compilation (#4656)
d240d0db9 fix file encoding (#4654)
6926c3d9a treat google user type as normal semantic google. It's a backport from diligent fork (#4632)
b9e255b36 DefUseManager: rename comparison operators to 'CompareAndPrintDifferences' (#4624)
f37551d2b Use a struct (instead of tuple), with explicit member names. (#4621)
438096e0c Fix kokoro asan run (#4655)
64328e94d Avoid an extra map lookup (#4623)
1ed847f43 Fix endianness of string literals (#4622)
b162ede0d Use schema instead of reserved in header description (#4615)
1f3f0f185 Avoid uninitialised read when parsing hex float (#4646)
f9bcc82ec Exit when ID overflow occurs in a fuzzing build (#4652)
Commands:
./third_party/update-spirvtools.sh
Bug: b/123642959
diff --git a/third_party/SPIRV-Tools/BUILD.gn b/third_party/SPIRV-Tools/BUILD.gn
index 309d513..b2cc934 100644
--- a/third_party/SPIRV-Tools/BUILD.gn
+++ b/third_party/SPIRV-Tools/BUILD.gn
@@ -448,12 +448,14 @@
"source/util/bit_vector.cpp",
"source/util/bit_vector.h",
"source/util/bitutils.h",
+ "source/util/hash_combine.h",
"source/util/hex_float.h",
"source/util/ilist.h",
"source/util/ilist_node.h",
"source/util/make_unique.h",
"source/util/parse_number.cpp",
"source/util/parse_number.h",
+ "source/util/pooled_linked_list.h",
"source/util/small_vector.h",
"source/util/string_utils.cpp",
"source/util/string_utils.h",
@@ -732,14 +734,16 @@
"source/opt/set_spec_constant_default_value_pass.h",
"source/opt/simplification_pass.cpp",
"source/opt/simplification_pass.h",
+ "source/opt/spread_volatile_semantics.cpp",
+ "source/opt/spread_volatile_semantics.h",
"source/opt/ssa_rewrite_pass.cpp",
"source/opt/ssa_rewrite_pass.h",
"source/opt/strength_reduction_pass.cpp",
"source/opt/strength_reduction_pass.h",
"source/opt/strip_debug_info_pass.cpp",
"source/opt/strip_debug_info_pass.h",
- "source/opt/strip_reflect_info_pass.cpp",
- "source/opt/strip_reflect_info_pass.h",
+ "source/opt/strip_nonsemantic_info_pass.cpp",
+ "source/opt/strip_nonsemantic_info_pass.h",
"source/opt/struct_cfg_analysis.cpp",
"source/opt/struct_cfg_analysis.h",
"source/opt/tree_iterator.h",
diff --git a/third_party/SPIRV-Tools/CHANGES b/third_party/SPIRV-Tools/CHANGES
index 4afd14a..246e483 100644
--- a/third_party/SPIRV-Tools/CHANGES
+++ b/third_party/SPIRV-Tools/CHANGES
@@ -1,7 +1,29 @@
Revision history for SPIRV-Tools
-v2021.5-dev 2021-11-11
- - Start v2021.5-dev
+v2022.2-dev 2022-01-26
+ - Start v2022.2-dev
+
+v2022.1 2022-01-26
+ - General
+ - Add SPIR-V 1.6 support to wasm build (#4674)
+ - Improvements to disassembly within PassManager (#4677)
+ - Basic support for SPIR-V 1.6 (#4663)
+ - reflect debug (#4662)
+ - Fix endianness of string literals (#4622)
+ - Optimizer
+ - spirv-opt: add pass to Spread Volatile semantics (#4667)
+ - Fix constant propagation and folding of FClamp instructions (#4651)
+ - Manually fold floating point division by zero (#4637)
+ - Allow ADCE to remove dead inputs (#4629)
+ - Linker
+ - Linker improvements (#4679)
+ * test/linker: Code factorisation and small tweaks
+ * linker: Do not fail when going over limits
+ - Validator
+ - val: interface struct with builtins must be Block (#4665)
+ - Fuzzer
+ - Avoid id bound errors during opt fuzzing (#4658)
+ - Avoid uninitialised read when parsing hex float (#4646)
v2021.4 2021-11-11
- General
diff --git a/third_party/SPIRV-Tools/CMakeLists.txt b/third_party/SPIRV-Tools/CMakeLists.txt
index 70caf85..76b87d8 100644
--- a/third_party/SPIRV-Tools/CMakeLists.txt
+++ b/third_party/SPIRV-Tools/CMakeLists.txt
@@ -116,7 +116,7 @@
set(SPIRV_WARNINGS ${SPIRV_WARNINGS} -Werror)
endif()
elseif(MSVC)
- set(SPIRV_WARNINGS -D_CRT_SECURE_NO_WARNINGS -D_SCL_SECURE_NO_WARNINGS /wd4800)
+ set(SPIRV_WARNINGS -D_CRT_SECURE_NO_WARNINGS -D_SCL_SECURE_NO_WARNINGS /wd4800 /wd4819)
if(${SPIRV_WERROR})
set(SPIRV_WARNINGS ${SPIRV_WARNINGS} /WX)
diff --git a/third_party/SPIRV-Tools/DEPS b/third_party/SPIRV-Tools/DEPS
index 2aaf11f..5ae4a2c 100644
--- a/third_party/SPIRV-Tools/DEPS
+++ b/third_party/SPIRV-Tools/DEPS
@@ -4,9 +4,9 @@
'github': 'https://github.com',
'effcee_revision': 'ddf5e2bb92957dc8a12c5392f8495333d6844133',
- 'googletest_revision': 'bf0701daa9f5b30e5882e2f8f9a5280bcba87e77',
- 're2_revision': '4244cd1cb492fa1d10986ec67f862964c073f844',
- 'spirv_headers_revision': '814e728b30ddd0f4509233099a3ad96fd4318c07',
+ 'googletest_revision': 'f45d5865ed0b2b8912244627cdf508a24cc6ccb4',
+ 're2_revision': '611baecbcedc9cec1f46e38616b6d8880b676c03',
+ 'spirv_headers_revision': '6a55fade62dec6a406a5a721148f88a2211cbefa',
}
deps = {
diff --git a/third_party/SPIRV-Tools/README.md b/third_party/SPIRV-Tools/README.md
index 14db1e7..ad2af49 100644
--- a/third_party/SPIRV-Tools/README.md
+++ b/third_party/SPIRV-Tools/README.md
@@ -212,6 +212,24 @@
"Fuzzer:" as the start of its title.
+### Diff
+
+*Note:* The diff tool is still under development.
+
+The diff tool takes two SPIR-V files, either in binary or text format and
+produces a diff-style comparison between the two. The instructions between the
+src and dst modules are matched as best as the tool can, and output is produced
+(in src id-space) that shows which instructions are removed in src, added in dst
+or modified between them. The order of instructions are not retained.
+
+Matching instructions between two SPIR-V modules is not trivial, and thus a
+number of heuristics are applied in this tool. In particular, without debug
+information, match functions is nontrivial as they can be reordered. As such,
+this tool is primarily useful to produce the diff of two SPIR-V modules derived
+from the same source, for example before and after a modification to the shader,
+before and after a transformation, or SPIR-V produced from different tools.
+
+
### Extras
* [Utility filters](#utility-filters)
@@ -624,6 +642,15 @@
* `spirv-cfg` - the control flow graph dumper
* `<spirv-dir>/tools/cfg`
+### Diff tool
+
+*Warning:* This functionality is under development, and is incomplete.
+
+The diff tool produces a diff-style comparison between two SPIR-V modules.
+
+* `spirv-diff` - the standalone diff tool
+ * `<spirv-dir>`/tools/diff`
+
### Utility filters
* `spirv-lesspipe.sh` - Automatically disassembles `.spv` binary files for the
diff --git a/third_party/SPIRV-Tools/include/spirv-tools/libspirv.h b/third_party/SPIRV-Tools/include/spirv-tools/libspirv.h
index 8df14f5..e1b8890 100644
--- a/third_party/SPIRV-Tools/include/spirv-tools/libspirv.h
+++ b/third_party/SPIRV-Tools/include/spirv-tools/libspirv.h
@@ -482,6 +482,7 @@
// SPV_ENV_VULKAN_1_1 -> SPIR-V 1.3
// SPV_ENV_VULKAN_1_1_SPIRV_1_4 -> SPIR-V 1.4
// SPV_ENV_VULKAN_1_2 -> SPIR-V 1.5
+// SPV_ENV_VULKAN_1_3 -> SPIR-V 1.6
// Consult the description of API entry points for specific rules.
typedef enum {
SPV_ENV_UNIVERSAL_1_0, // SPIR-V 1.0 latest revision, no other restrictions.
@@ -516,7 +517,11 @@
SPV_ENV_UNIVERSAL_1_5, // SPIR-V 1.5 latest revision, no other restrictions.
SPV_ENV_VULKAN_1_2, // Vulkan 1.2 latest revision.
- SPV_ENV_MAX // Keep this as the last enum value.
+
+ SPV_ENV_UNIVERSAL_1_6, // SPIR-V 1.6 latest revision, no other restrictions.
+ SPV_ENV_VULKAN_1_3, // Vulkan 1.3 latest revision.
+
+ SPV_ENV_MAX // Keep this as the last enum value.
} spv_target_env;
// SPIR-V Validator can be parameterized with the following Universal Limits.
@@ -555,7 +560,7 @@
// Creates a context object for most of the SPIRV-Tools API.
// Returns null if env is invalid.
//
-// See specific API calls for how the target environment is interpeted
+// See specific API calls for how the target environment is interpreted
// (particularly assembly and validation).
SPIRV_TOOLS_EXPORT spv_context spvContextCreate(spv_target_env env);
@@ -607,7 +612,7 @@
// set that option.
// 2) Pointers that are pass as parameters to function calls do not have to
// match the storage class of the formal parameter.
-// 3) Pointers that are actaul parameters on function calls do not have to point
+// 3) Pointers that are actual parameters on function calls do not have to point
// to the same type pointed as the formal parameter. The types just need to
// logically match.
// 4) GLSLstd450 Interpolate* instructions can have a load of an interpolant
@@ -633,7 +638,7 @@
// Records whether the validator should use "scalar" block layout rules.
// Scalar layout rules are more permissive than relaxed block layout.
//
-// See Vulkan extnesion VK_EXT_scalar_block_layout. The scalar alignment is
+// See Vulkan extension VK_EXT_scalar_block_layout. The scalar alignment is
// defined as follows:
// - scalar alignment of a scalar is the scalar size
// - scalar alignment of a vector is the scalar alignment of its component
diff --git a/third_party/SPIRV-Tools/include/spirv-tools/libspirv.hpp b/third_party/SPIRV-Tools/include/spirv-tools/libspirv.hpp
index 8dfb46b..25eb8a1 100644
--- a/third_party/SPIRV-Tools/include/spirv-tools/libspirv.hpp
+++ b/third_party/SPIRV-Tools/include/spirv-tools/libspirv.hpp
@@ -36,7 +36,7 @@
public:
// Constructs a context targeting the given environment |env|.
//
- // See specific API calls for how the target environment is interpeted
+ // See specific API calls for how the target environment is interpreted
// (particularly assembly and validation).
//
// The constructed instance will have an empty message consumer, which just
@@ -139,7 +139,7 @@
// set that option.
// 2) Pointers that are pass as parameters to function calls do not have to
// match the storage class of the formal parameter.
- // 3) Pointers that are actaul parameters on function calls do not have to
+ // 3) Pointers that are actual parameters on function calls do not have to
// point to the same type pointed as the formal parameter. The types just
// need to logically match.
// 4) GLSLstd450 Interpolate* instructions can have a load of an interpolant
diff --git a/third_party/SPIRV-Tools/include/spirv-tools/optimizer.hpp b/third_party/SPIRV-Tools/include/spirv-tools/optimizer.hpp
index 21059cb..fdb2e64 100644
--- a/third_party/SPIRV-Tools/include/spirv-tools/optimizer.hpp
+++ b/third_party/SPIRV-Tools/include/spirv-tools/optimizer.hpp
@@ -43,7 +43,7 @@
// consumed by the RegisterPass() method. Tokens are one-time objects that
// only support move; copying is not allowed.
struct PassToken {
- struct Impl; // Opaque struct for holding inernal data.
+ struct Impl; // Opaque struct for holding internal data.
PassToken(std::unique_ptr<Impl>);
@@ -227,16 +227,17 @@
// Creates a strip-debug-info pass.
// A strip-debug-info pass removes all debug instructions (as documented in
-// Section 3.32.2 of the SPIR-V spec) of the SPIR-V module to be optimized.
+// Section 3.42.2 of the SPIR-V spec) of the SPIR-V module to be optimized.
Optimizer::PassToken CreateStripDebugInfoPass();
-// Creates a strip-reflect-info pass.
-// A strip-reflect-info pass removes all reflections instructions.
-// For now, this is limited to removing decorations defined in
-// SPV_GOOGLE_hlsl_functionality1. The coverage may expand in
-// the future.
+// [Deprecated] This will create a strip-nonsemantic-info pass. See below.
Optimizer::PassToken CreateStripReflectInfoPass();
+// Creates a strip-nonsemantic-info pass.
+// A strip-nonsemantic-info pass removes all reflections and explicitly
+// non-semantic instructions.
+Optimizer::PassToken CreateStripNonSemanticInfoPass();
+
// Creates an eliminate-dead-functions pass.
// An eliminate-dead-functions pass will remove all functions that are not in
// the call trees rooted at entry points and exported functions. These
@@ -295,11 +296,11 @@
// and can be changed in future. A spec constant is foldable if all of its
// value(s) can be determined from the module. E.g., an integer spec constant
// defined with OpSpecConstantOp instruction can be folded if its value won't
-// change later. This pass will replace the original OpSpecContantOp instruction
-// with an OpConstant instruction. When folding composite spec constants,
-// new instructions may be inserted to define the components of the composite
-// constant first, then the original spec constants will be replaced by
-// OpConstantComposite instructions.
+// change later. This pass will replace the original OpSpecConstantOp
+// instruction with an OpConstant instruction. When folding composite spec
+// constants, new instructions may be inserted to define the components of the
+// composite constant first, then the original spec constants will be replaced
+// by OpConstantComposite instructions.
//
// There are some operations not supported yet:
// OpSConvert, OpFConvert, OpQuantizeToF16 and
@@ -325,7 +326,7 @@
// Creates a eliminate-dead-constant pass.
// A eliminate-dead-constant pass removes dead constants, including normal
-// contants defined by OpConstant, OpConstantComposite, OpConstantTrue, or
+// constants defined by OpConstant, OpConstantComposite, OpConstantTrue, or
// OpConstantFalse and spec constants defined by OpSpecConstant,
// OpSpecConstantComposite, OpSpecConstantTrue, OpSpecConstantFalse or
// OpSpecConstantOp.
@@ -389,7 +390,7 @@
// Only modules with relaxed logical addressing (see opt/instruction.h) are
// currently processed.
//
-// This pass is most effective if preceeded by Inlining and
+// This pass is most effective if preceded by Inlining and
// LocalAccessChainConvert. This pass will reduce the work needed to be done
// by LocalSingleStoreElim and LocalMultiStoreElim.
//
@@ -407,7 +408,7 @@
// Note that some branches and blocks may be left to avoid creating invalid
// control flow. Improving this is left to future work.
//
-// This pass is most effective when preceeded by passes which eliminate
+// This pass is most effective when preceded by passes which eliminate
// local loads and stores, effectively propagating constant values where
// possible.
Optimizer::PassToken CreateDeadBranchElimPass();
@@ -424,7 +425,7 @@
// are currently processed. Currently modules with any extensions enabled are
// not processed. This is left for future work.
//
-// This pass is most effective if preceeded by Inlining and
+// This pass is most effective if preceded by Inlining and
// LocalAccessChainConvert. LocalSingleStoreElim and LocalSingleBlockElim
// will reduce the work that this pass has to do.
Optimizer::PassToken CreateLocalMultiStoreElimPass();
@@ -519,7 +520,8 @@
// interface are considered live and are not eliminated. This mode is needed
// by GPU-Assisted validation instrumentation, where a change in the interface
// is not allowed.
-Optimizer::PassToken CreateAggressiveDCEPass(bool preserve_interface = false);
+Optimizer::PassToken CreateAggressiveDCEPass();
+Optimizer::PassToken CreateAggressiveDCEPass(bool preserve_interface);
// Creates a remove-unused-interface-variables pass.
// Removes variables referenced on the |OpEntryPoint| instruction that are not
@@ -628,7 +630,7 @@
Optimizer::PassToken CreateScalarReplacementPass(uint32_t size_limit = 100);
// Create a private to local pass.
-// This pass looks for variables delcared in the private storage class that are
+// This pass looks for variables declared in the private storage class that are
// used in only one function. Those variables are moved to the function storage
// class in the function that they are used.
Optimizer::PassToken CreatePrivateToLocalPass();
@@ -833,6 +835,19 @@
// inclusive.
Optimizer::PassToken CreateGraphicsRobustAccessPass();
+// Create a pass to spread Volatile semantics to variables with SMIDNV,
+// WarpIDNV, SubgroupSize, SubgroupLocalInvocationId, SubgroupEqMask,
+// SubgroupGeMask, SubgroupGtMask, SubgroupLeMask, or SubgroupLtMask BuiltIn
+// decorations or OpLoad for them when the shader model is the ray generation,
+// closest hit, miss, intersection, or callable. This pass can be used for
+// VUID-StandaloneSpirv-VulkanMemoryModel-04678 and
+// VUID-StandaloneSpirv-VulkanMemoryModel-04679 (See "Standalone SPIR-V
+// Validation" section of Vulkan spec "Appendix A: Vulkan Environment for
+// SPIR-V"). When the SPIR-V version is 1.6 or above, the pass also spreads
+// the Volatile semantics to a variable with HelperInvocation BuiltIn decoration
+// in the fragement shader.
+Optimizer::PassToken CreateSpreadVolatileSemanticsPass();
+
// Create a pass to replace a descriptor access using variable index.
// This pass replaces every access using a variable index to array variable
// |desc| that has a DescriptorSet and Binding decorations with a constant
diff --git a/third_party/SPIRV-Tools/kokoro/scripts/linux/build.sh b/third_party/SPIRV-Tools/kokoro/scripts/linux/build.sh
index 4731ebd..85d4b61 100644
--- a/third_party/SPIRV-Tools/kokoro/scripts/linux/build.sh
+++ b/third_party/SPIRV-Tools/kokoro/scripts/linux/build.sh
@@ -26,7 +26,9 @@
TOOL=$3
BUILD_SHA=${KOKORO_GITHUB_COMMIT:-$KOKORO_GITHUB_PULL_REQUEST_COMMIT}
+# "--privileged" is required to run ptrace in the asan builds.
docker run --rm -i \
+ --privileged \
--volume "${ROOT_DIR}:${ROOT_DIR}" \
--volume "${KOKORO_ARTIFACTS_DIR}:${KOKORO_ARTIFACTS_DIR}" \
--workdir "${ROOT_DIR}" \
diff --git a/third_party/SPIRV-Tools/source/CMakeLists.txt b/third_party/SPIRV-Tools/source/CMakeLists.txt
index 331ff67..f0dcadd 100644
--- a/third_party/SPIRV-Tools/source/CMakeLists.txt
+++ b/third_party/SPIRV-Tools/source/CMakeLists.txt
@@ -217,15 +217,18 @@
add_subdirectory(fuzz)
add_subdirectory(link)
add_subdirectory(lint)
+add_subdirectory(diff)
set(SPIRV_SOURCES
${spirv-tools_SOURCE_DIR}/include/spirv-tools/libspirv.h
${CMAKE_CURRENT_SOURCE_DIR}/util/bitutils.h
${CMAKE_CURRENT_SOURCE_DIR}/util/bit_vector.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/util/hash_combine.h
${CMAKE_CURRENT_SOURCE_DIR}/util/hex_float.h
${CMAKE_CURRENT_SOURCE_DIR}/util/make_unique.h
${CMAKE_CURRENT_SOURCE_DIR}/util/parse_number.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/util/pooled_linked_list.h
${CMAKE_CURRENT_SOURCE_DIR}/util/small_vector.h
${CMAKE_CURRENT_SOURCE_DIR}/util/string_utils.h
${CMAKE_CURRENT_SOURCE_DIR}/util/timer.h
diff --git a/third_party/SPIRV-Tools/source/binary.cpp b/third_party/SPIRV-Tools/source/binary.cpp
index 93d5da7..24d32f8 100644
--- a/third_party/SPIRV-Tools/source/binary.cpp
+++ b/third_party/SPIRV-Tools/source/binary.cpp
@@ -33,6 +33,7 @@
#include "source/operand.h"
#include "source/spirv_constant.h"
#include "source/spirv_endian.h"
+#include "source/util/string_utils.h"
spv_result_t spvBinaryHeaderGet(const spv_const_binary binary,
const spv_endianness_t endian,
@@ -62,6 +63,15 @@
return SPV_SUCCESS;
}
+std::string spvDecodeLiteralStringOperand(const spv_parsed_instruction_t& inst,
+ const uint16_t operand_index) {
+ assert(operand_index < inst.num_operands);
+ const spv_parsed_operand_t& operand = inst.operands[operand_index];
+
+ return spvtools::utils::MakeString(inst.words + operand.offset,
+ operand.num_words);
+}
+
namespace {
// A SPIR-V binary parser. A parser instance communicates detailed parse
@@ -205,7 +215,7 @@
size_t word_index; // The current position in words.
size_t instruction_count; // The count of processed instructions
spv_endianness_t endian; // The endianness of the binary.
- // Is the SPIR-V binary in a different endiannes from the host native
+ // Is the SPIR-V binary in a different endianness from the host native
// endianness?
bool requires_endian_conversion;
@@ -290,7 +300,7 @@
const uint32_t first_word = peek();
// If the module's endianness is different from the host native endianness,
- // then converted_words contains the the endian-translated words in the
+ // then converted_words contains the endian-translated words in the
// instruction.
_.endian_converted_words.clear();
_.endian_converted_words.push_back(first_word);
@@ -577,27 +587,18 @@
case SPV_OPERAND_TYPE_LITERAL_STRING:
case SPV_OPERAND_TYPE_OPTIONAL_LITERAL_STRING: {
- convert_operand_endianness = false;
- const char* string =
- reinterpret_cast<const char*>(_.words + _.word_index);
- // Compute the length of the string, but make sure we don't run off the
- // end of the input.
- const size_t remaining_input_bytes =
- sizeof(uint32_t) * (_.num_words - _.word_index);
- const size_t string_num_content_bytes =
- spv_strnlen_s(string, remaining_input_bytes);
- // If there was no terminating null byte, then that's an end-of-input
- // error.
- if (string_num_content_bytes == remaining_input_bytes)
+ const size_t max_words = _.num_words - _.word_index;
+ std::string string =
+ spvtools::utils::MakeString(_.words + _.word_index, max_words, false);
+
+ if (string.length() == max_words * 4)
return exhaustedInputDiagnostic(inst_offset, opcode, type);
- // Account for null in the word length, so add 1 for null, then add 3 to
- // make sure we round up. The following is equivalent to:
- // (string_num_content_bytes + 1 + 3) / 4
- const size_t string_num_words = string_num_content_bytes / 4 + 1;
+
// Make sure we can record the word count without overflow.
//
// This error can't currently be triggered because of validity
// checks elsewhere.
+ const size_t string_num_words = string.length() / 4 + 1;
if (string_num_words > std::numeric_limits<uint16_t>::max()) {
return diagnostic() << "Literal string is longer than "
<< std::numeric_limits<uint16_t>::max()
@@ -611,7 +612,7 @@
// There is only one string literal argument to OpExtInstImport,
// so it's sufficient to guard this just on the opcode.
const spv_ext_inst_type_t ext_inst_type =
- spvExtInstImportTypeGet(string);
+ spvExtInstImportTypeGet(string.c_str());
if (SPV_EXT_INST_TYPE_NONE == ext_inst_type) {
return diagnostic()
<< "Invalid extended instruction import '" << string << "'";
diff --git a/third_party/SPIRV-Tools/source/binary.h b/third_party/SPIRV-Tools/source/binary.h
index 66d24c7..eb3beac 100644
--- a/third_party/SPIRV-Tools/source/binary.h
+++ b/third_party/SPIRV-Tools/source/binary.h
@@ -15,6 +15,8 @@
#ifndef SOURCE_BINARY_H_
#define SOURCE_BINARY_H_
+#include <string>
+
#include "source/spirv_definition.h"
#include "spirv-tools/libspirv.h"
@@ -33,4 +35,9 @@
// replacement for C11's strnlen_s which might not exist in all environments.
size_t spv_strnlen_s(const char* str, size_t strsz);
+// Decode the string literal operand with index operand_index from instruction
+// inst.
+std::string spvDecodeLiteralStringOperand(const spv_parsed_instruction_t& inst,
+ const uint16_t operand_index);
+
#endif // SOURCE_BINARY_H_
diff --git a/third_party/SPIRV-Tools/source/cfa.h b/third_party/SPIRV-Tools/source/cfa.h
index 0d09014..7cadf55 100644
--- a/third_party/SPIRV-Tools/source/cfa.h
+++ b/third_party/SPIRV-Tools/source/cfa.h
@@ -42,7 +42,7 @@
/// Returns true if a block with @p id is found in the @p work_list vector
///
- /// @param[in] work_list Set of blocks visited in the the depth first
+ /// @param[in] work_list Set of blocks visited in the depth first
/// traversal
/// of the CFG
/// @param[in] id The ID of the block being checked
diff --git a/third_party/SPIRV-Tools/source/diff/CMakeLists.txt b/third_party/SPIRV-Tools/source/diff/CMakeLists.txt
new file mode 100644
index 0000000..1328699
--- /dev/null
+++ b/third_party/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)
diff --git a/third_party/SPIRV-Tools/source/diff/diff.cpp b/third_party/SPIRV-Tools/source/diff/diff.cpp
new file mode 100644
index 0000000..12172bf
--- /dev/null
+++ b/third_party/SPIRV-Tools/source/diff/diff.cpp
@@ -0,0 +1,2669 @@
+// 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 function names to function 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>;
+
+// 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()) {
+ // 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());
+ }
+
+ 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_;
+};
+
+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 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,
+ 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);
+
+ // 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 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 GroupIdsByName(const IdGroup& functions, bool is_src,
+ IdGroupMapByName* groups);
+ void GroupIdsByTypeId(const IdGroup& functions, bool is_src,
+ IdGroupMapByTypeId* groups);
+ template <typename T>
+ void GroupIds(const IdGroup& functions, bool is_src,
+ std::map<T, IdGroup>* groups,
+ std::function<T(const IdInstructions, uint32_t)> get_group);
+ 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);
+ std::string GetName(const IdInstructions& id_to, uint32_t id, bool* has_name);
+ std::string GetFunctionName(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);
+ bool IsIntType(const IdInstructions& id_to, uint32_t type_id);
+ // bool IsUintType(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;
+ 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,
+ 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());
+
+ 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->GetOperand(0).AsId());
+ const SpvExecutionModel dst_model =
+ GetExecutionModel(dst_inst_module, b->GetOperand(0).AsId());
+
+ 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;
+ }
+ }
+ }
+}
+
+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->GetInOperand(0).words[0]);
+ SpvStorageClass dst_storage_class =
+ SpvStorageClass(dst_inst->GetInOperand(0).words[0]);
+
+ return src_storage_class == dst_storage_class;
+}
+
+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);
+ }
+}
+
+template <typename T>
+void Differ::GroupIds(
+ const IdGroup& functions, bool is_src, std::map<T, IdGroup>* groups,
+ std::function<T(const IdInstructions, uint32_t)> get_group) {
+ assert(groups->empty());
+
+ const IdInstructions& id_to = is_src ? src_id_to_ : dst_id_to_;
+
+ for (const uint32_t func_id : functions) {
+ // Don't include functions that are already matched, for example through
+ // OpEntryPoint.
+ const bool is_matched =
+ is_src ? id_map_.IsSrcMapped(func_id) : id_map_.IsDstMapped(func_id);
+ if (is_matched) {
+ continue;
+ }
+
+ T group = get_group(id_to, func_id);
+ (*groups)[group].push_back(func_id);
+ }
+}
+
+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 = GetFunctionName(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 = GetFunctionName(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::GroupIdsByName(const IdGroup& functions, bool is_src,
+ IdGroupMapByName* groups) {
+ GroupIds<std::string>(functions, is_src, groups,
+ [this](const IdInstructions& id_to, uint32_t func_id) {
+ return GetFunctionName(id_to, func_id);
+ });
+}
+
+void Differ::GroupIdsByTypeId(const IdGroup& functions, bool is_src,
+ IdGroupMapByTypeId* groups) {
+ GroupIds<uint32_t>(functions, is_src, groups,
+ [this](const IdInstructions& id_to, uint32_t func_id) {
+ return GetInst(id_to, func_id)->type_id();
+ });
+}
+
+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);
+
+ IdGroupMapByName src_param_groups;
+ IdGroupMapByName dst_param_groups;
+
+ GroupIdsByName(src_params, true, &src_param_groups);
+ GroupIdsByName(dst_params, false, &dst_param_groups);
+
+ // Match parameters with identical names.
+ for (const auto& src_param_group : src_param_groups) {
+ const std::string& name = src_param_group.first;
+ const IdGroup& src_group = src_param_group.second;
+
+ if (name == "") {
+ continue;
+ }
+
+ const IdGroup& dst_group = dst_param_groups[name];
+
+ // 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.
+ IdGroupMapByTypeId src_param_groups_by_type_id;
+ IdGroupMapByTypeId dst_param_groups_by_type_id;
+
+ GroupIdsByTypeId(src_params, true, &src_param_groups_by_type_id);
+ GroupIdsByTypeId(dst_params, false, &dst_param_groups_by_type_id);
+
+ for (const auto& src_param_group_by_type_id : src_param_groups_by_type_id) {
+ const uint32_t type_id = src_param_group_by_type_id.first;
+ const IdGroup& src_group_by_type_id = src_param_group_by_type_id.second;
+ const IdGroup& dst_group_by_type_id = dst_param_groups_by_type_id[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->GetInOperand(0).AsId();
+ const uint32_t dst_pointer_id = dst_inst->GetInOperand(0).AsId();
+ 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->GetInOperand(0).words[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.GetOperand(1).AsId() == entry_point_id) {
+ return SpvExecutionModel(inst.GetOperand(0).words[0]);
+ }
+ }
+
+ assert(false && "Unreachable");
+ return SpvExecutionModel(0xFFF);
+}
+
+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::GetFunctionName(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
+ 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->GetInOperand(0).words[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->GetInOperand(1).AsId();
+}
+
+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->GetOperand(0).AsId() == id &&
+ inst->GetOperand(1).words[0] == decoration) {
+ *decoration_value = inst->GetOperand(2).words[0];
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool Differ::IsIntType(const IdInstructions& id_to, uint32_t type_id) {
+ return IsOp(id_to, type_id, SpvOpTypeInt);
+#if 0
+ const opt::Instruction *type_inst = GetInst(id_to, type_id);
+ return type_inst->opcode() == SpvOpTypeInt && type_inst->GetInOperand(1).words[0] != 0;
+#endif
+}
+
+#if 0
+bool Differ::IsUintType(const IdInstructions& id_to, uint32_t type_id) {
+ const opt::Instruction *type_inst = GetInst(id_to, type_id);
+ return type_inst->opcode() == SpvOpTypeInt && type_inst->GetInOperand(1).words[0] == 0;
+}
+#endif
+
+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->GetOperand(0).AsId() == type_id &&
+ inst->GetOperand(2).words[0] == SpvDecorationBuiltIn) {
+ SpvBuiltIn built_in = SpvBuiltIn(inst->GetOperand(3).words[0]);
+
+ // 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->GetInOperand(0).AsId();
+ }
+
+ // 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.GetInOperand(0).AsId() == type_id) {
+ type_id = inst.result_id();
+ }
+ break;
+ case SpvOpTypePointer:
+ // Find the storage class of the pointer to this type.
+ if (inst.GetInOperand(1).AsId() == type_id) {
+ return SpvStorageClass(inst.GetInOperand(0).words[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.GetOperand(0).AsId(),
+ 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->GetOperand(1).words[0];
+ return type_inst->GetOperand(2).words[0] == 0 ? SPV_NUMBER_UNSIGNED_INT
+ : SPV_NUMBER_SIGNED_INT;
+ break;
+ case SpvOpTypeFloat:
+ *number_bit_width = type_inst->GetOperand(1).words[0];
+ 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,
+ accept_all, get_result_id);
+ PoolPotentialIds(dst_->ext_inst_imports(), potential_id_map.dst_ids,
+ 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.GetOperand(0).words[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.GetOperand(0).words[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]->GetOperand(1).AsId();
+ uint32_t dst_id = dst_insts[0]->GetOperand(1).AsId();
+ 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->GetOperand(1).AsId();
+ uint32_t dst_id = dst_inst->GetOperand(1).AsId();
+ 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::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,
+ accept_type_ops, get_result_id);
+ PoolPotentialIds(dst_->types_values(), potential_id_map.dst_ids,
+ 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:
+ case SpvOpTypeFunction:
+ // 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 SpvOpTypeImage:
+ // Match these instructions when all operands match, including the
+ // optional final parameter (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->GetInOperand(1).AsId(),
+ dst_inst->GetInOperand(1).AsId())) {
+ 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,
+ accept_type_ops, get_result_id);
+ PoolPotentialIds(dst_->types_values(), potential_id_map.dst_ids,
+ 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,
+ accept_type_ops, get_result_id);
+ PoolPotentialIds(dst_->types_values(), potential_id_map.dst_ids,
+ 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.
+ IdGroupMapByName src_func_groups;
+ IdGroupMapByName dst_func_groups;
+
+ GroupIdsByName(src_func_ids, true, &src_func_groups);
+ GroupIdsByName(dst_func_ids, false, &dst_func_groups);
+
+ // Match functions with identical names.
+ for (const auto& src_func_group : src_func_groups) {
+ const std::string& name = src_func_group.first;
+ const IdGroup& src_group = src_func_group.second;
+
+ if (name == "") {
+ continue;
+ }
+
+ const IdGroup& dst_group = dst_func_groups[name];
+
+ // 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]);
+ continue;
+ }
+
+ // If there are multiple functions with the same name, group them by type,
+ // and match only if the types match (and are unique).
+ IdGroupMapByTypeId src_func_groups_by_type_id;
+ IdGroupMapByTypeId dst_func_groups_by_type_id;
+
+ GroupIdsByTypeId(src_group, true, &src_func_groups_by_type_id);
+ GroupIdsByTypeId(dst_group, false, &dst_func_groups_by_type_id);
+
+ for (const auto& src_func_group_by_type_id : src_func_groups_by_type_id) {
+ const uint32_t type_id = src_func_group_by_type_id.first;
+ const IdGroup& src_group_by_type_id = src_func_group_by_type_id.second;
+ const IdGroup& dst_group_by_type_id = dst_func_groups_by_type_id[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.
+ IdGroupMapByTypeId src_func_groups_by_type_id;
+ IdGroupMapByTypeId dst_func_groups_by_type_id;
+
+ GroupIdsByTypeId(src_func_ids, true, &src_func_groups_by_type_id);
+ GroupIdsByTypeId(dst_func_ids, false, &dst_func_groups_by_type_id);
+
+ for (const auto& src_func_group_by_type_id : src_func_groups_by_type_id) {
+ const uint32_t type_id = src_func_group_by_type_id.first;
+ const IdGroup& src_group_by_type_id = src_func_group_by_type_id.second;
+ const IdGroup& dst_group_by_type_id = dst_func_groups_by_type_id[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.GetInOperand(0).AsId())
+ : SPV_EXT_INST_TYPE_NONE;
+ parsed_inst->type_id = inst.HasResultType() ? inst.GetOperand(0).AsId() : 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.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
diff --git a/third_party/SPIRV-Tools/source/diff/diff.h b/third_party/SPIRV-Tools/source/diff/diff.h
new file mode 100644
index 0000000..932de9e
--- /dev/null
+++ b/third_party/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_
diff --git a/third_party/SPIRV-Tools/source/diff/lcs.h b/third_party/SPIRV-Tools/source/diff/lcs.h
new file mode 100644
index 0000000..6c00e86
--- /dev/null
+++ b/third_party/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_
diff --git a/third_party/SPIRV-Tools/source/disassemble.cpp b/third_party/SPIRV-Tools/source/disassemble.cpp
index c553988..1d61b9f 100644
--- a/third_party/SPIRV-Tools/source/disassemble.cpp
+++ b/third_party/SPIRV-Tools/source/disassemble.cpp
@@ -17,6 +17,8 @@
// This file contains a disassembler: It converts a SPIR-V binary
// to text.
+#include "source/disassemble.h"
+
#include <algorithm>
#include <cassert>
#include <cstring>
@@ -28,9 +30,7 @@
#include "source/assembly_grammar.h"
#include "source/binary.h"
#include "source/diagnostic.h"
-#include "source/disassemble.h"
#include "source/ext_inst.h"
-#include "source/name_mapper.h"
#include "source/opcode.h"
#include "source/parsed_operand.h"
#include "source/print.h"
@@ -40,29 +40,21 @@
#include "source/util/make_unique.h"
#include "spirv-tools/libspirv.h"
+namespace spvtools {
namespace {
// A Disassembler instance converts a SPIR-V binary to its assembly
// representation.
class Disassembler {
public:
- Disassembler(const spvtools::AssemblyGrammar& grammar, uint32_t options,
- spvtools::NameMapper name_mapper)
- : grammar_(grammar),
- print_(spvIsInBitfield(SPV_BINARY_TO_TEXT_OPTION_PRINT, options)),
- color_(spvIsInBitfield(SPV_BINARY_TO_TEXT_OPTION_COLOR, options)),
- indent_(spvIsInBitfield(SPV_BINARY_TO_TEXT_OPTION_INDENT, options)
- ? kStandardIndent
- : 0),
- comment_(spvIsInBitfield(SPV_BINARY_TO_TEXT_OPTION_COMMENT, options)),
+ Disassembler(const AssemblyGrammar& grammar, uint32_t options,
+ NameMapper name_mapper)
+ : print_(spvIsInBitfield(SPV_BINARY_TO_TEXT_OPTION_PRINT, options)),
text_(),
out_(print_ ? out_stream() : out_stream(text_)),
- stream_(out_.get()),
+ instruction_disassembler_(grammar, out_.get(), options, name_mapper),
header_(!spvIsInBitfield(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER, options)),
- show_byte_offset_(spvIsInBitfield(
- SPV_BINARY_TO_TEXT_OPTION_SHOW_BYTE_OFFSET, options)),
- byte_offset_(0),
- name_mapper_(std::move(name_mapper)) {}
+ byte_offset_(0) {}
// Emits the assembly header for the module, and sets up internal state
// so subsequent callbacks can handle the cases where the entire module
@@ -78,56 +70,13 @@
spv_result_t SaveTextResult(spv_text* text_result) const;
private:
- enum { kStandardIndent = 15 };
-
- using out_stream = spvtools::out_stream;
-
- // Emits an operand for the given instruction, where the instruction
- // is at offset words from the start of the binary.
- void EmitOperand(const spv_parsed_instruction_t& inst,
- const uint16_t operand_index);
-
- // Emits a mask expression for the given mask word of the specified type.
- void EmitMaskOperand(const spv_operand_type_t type, const uint32_t word);
-
- // Resets the output color, if color is turned on.
- void ResetColor() {
- if (color_) out_.get() << spvtools::clr::reset{print_};
- }
- // Sets the output to grey, if color is turned on.
- void SetGrey() {
- if (color_) out_.get() << spvtools::clr::grey{print_};
- }
- // Sets the output to blue, if color is turned on.
- void SetBlue() {
- if (color_) out_.get() << spvtools::clr::blue{print_};
- }
- // Sets the output to yellow, if color is turned on.
- void SetYellow() {
- if (color_) out_.get() << spvtools::clr::yellow{print_};
- }
- // Sets the output to red, if color is turned on.
- void SetRed() {
- if (color_) out_.get() << spvtools::clr::red{print_};
- }
- // Sets the output to green, if color is turned on.
- void SetGreen() {
- if (color_) out_.get() << spvtools::clr::green{print_};
- }
-
- const spvtools::AssemblyGrammar& grammar_;
const bool print_; // Should we also print to the standard output stream?
- const bool color_; // Should we print in colour?
- const int indent_; // How much to indent. 0 means don't indent
- const int comment_; // Should we comment the source
spv_endianness_t endian_; // The detected endianness of the binary.
std::stringstream text_; // Captures the text, if not printing.
out_stream out_; // The Output stream. Either to text_ or standard output.
- std::ostream& stream_; // The output std::stream.
- const bool header_; // Should we output header as the leading comment?
- const bool show_byte_offset_; // Should we print byte offset, in hex?
- size_t byte_offset_; // The number of bytes processed so far.
- spvtools::NameMapper name_mapper_;
+ disassemble::InstructionDisassembler instruction_disassembler_;
+ const bool header_; // Should we output header as the leading comment?
+ size_t byte_offset_; // The number of bytes processed so far.
bool inserted_decoration_space_ = false;
bool inserted_debug_space_ = false;
bool inserted_type_space_ = false;
@@ -139,21 +88,11 @@
endian_ = endian;
if (header_) {
- const char* generator_tool =
- spvGeneratorStr(SPV_GENERATOR_TOOL_PART(generator));
- stream_ << "; SPIR-V\n"
- << "; Version: " << SPV_SPIRV_VERSION_MAJOR_PART(version) << "."
- << SPV_SPIRV_VERSION_MINOR_PART(version) << "\n"
- << "; Generator: " << generator_tool;
- // For unknown tools, print the numeric tool value.
- if (0 == strcmp("Unknown", generator_tool)) {
- stream_ << "(" << SPV_GENERATOR_TOOL_PART(generator) << ")";
- }
- // Print the miscellaneous part of the generator word on the same
- // line as the tool name.
- stream_ << "; " << SPV_GENERATOR_MISC_PART(generator) << "\n"
- << "; Bound: " << id_bound << "\n"
- << "; Schema: " << schema << "\n";
+ instruction_disassembler_.EmitHeaderSpirv();
+ instruction_disassembler_.EmitHeaderVersion(version);
+ instruction_disassembler_.EmitHeaderGenerator(generator);
+ instruction_disassembler_.EmitHeaderIdBound(id_bound);
+ instruction_disassembler_.EmitHeaderSchema(schema);
}
byte_offset_ = SPV_INDEX_INSTRUCTION * sizeof(uint32_t);
@@ -163,232 +102,17 @@
spv_result_t Disassembler::HandleInstruction(
const spv_parsed_instruction_t& inst) {
- auto opcode = static_cast<SpvOp>(inst.opcode);
- if (comment_ && opcode == SpvOpFunction) {
- stream_ << std::endl;
- stream_ << std::string(indent_, ' ');
- stream_ << "; Function " << name_mapper_(inst.result_id) << std::endl;
- }
- if (comment_ && !inserted_decoration_space_ &&
- spvOpcodeIsDecoration(opcode)) {
- inserted_decoration_space_ = true;
- stream_ << std::endl;
- stream_ << std::string(indent_, ' ');
- stream_ << "; Annotations" << std::endl;
- }
- if (comment_ && !inserted_debug_space_ && spvOpcodeIsDebug(opcode)) {
- inserted_debug_space_ = true;
- stream_ << std::endl;
- stream_ << std::string(indent_, ' ');
- stream_ << "; Debug Information" << std::endl;
- }
- if (comment_ && !inserted_type_space_ && spvOpcodeGeneratesType(opcode)) {
- inserted_type_space_ = true;
- stream_ << std::endl;
- stream_ << std::string(indent_, ' ');
- stream_ << "; Types, variables and constants" << std::endl;
- }
+ instruction_disassembler_.EmitSectionComment(inst, inserted_decoration_space_,
+ inserted_debug_space_,
+ inserted_type_space_);
- if (inst.result_id) {
- SetBlue();
- const std::string id_name = name_mapper_(inst.result_id);
- if (indent_)
- stream_ << std::setw(std::max(0, indent_ - 3 - int(id_name.size())));
- stream_ << "%" << id_name;
- ResetColor();
- stream_ << " = ";
- } else {
- stream_ << std::string(indent_, ' ');
- }
-
- stream_ << "Op" << spvOpcodeString(opcode);
-
- for (uint16_t i = 0; i < inst.num_operands; i++) {
- const spv_operand_type_t type = inst.operands[i].type;
- assert(type != SPV_OPERAND_TYPE_NONE);
- if (type == SPV_OPERAND_TYPE_RESULT_ID) continue;
- stream_ << " ";
- EmitOperand(inst, i);
- }
-
- if (comment_ && opcode == SpvOpName) {
- const spv_parsed_operand_t& operand = inst.operands[0];
- const uint32_t word = inst.words[operand.offset];
- stream_ << " ; id %" << word;
- }
-
- if (show_byte_offset_) {
- SetGrey();
- auto saved_flags = stream_.flags();
- auto saved_fill = stream_.fill();
- stream_ << " ; 0x" << std::setw(8) << std::hex << std::setfill('0')
- << byte_offset_;
- stream_.flags(saved_flags);
- stream_.fill(saved_fill);
- ResetColor();
- }
+ instruction_disassembler_.EmitInstruction(inst, byte_offset_);
byte_offset_ += inst.num_words * sizeof(uint32_t);
- stream_ << "\n";
return SPV_SUCCESS;
}
-void Disassembler::EmitOperand(const spv_parsed_instruction_t& inst,
- const uint16_t operand_index) {
- assert(operand_index < inst.num_operands);
- const spv_parsed_operand_t& operand = inst.operands[operand_index];
- const uint32_t word = inst.words[operand.offset];
- switch (operand.type) {
- case SPV_OPERAND_TYPE_RESULT_ID:
- assert(false && "<result-id> is not supposed to be handled here");
- SetBlue();
- stream_ << "%" << name_mapper_(word);
- break;
- case SPV_OPERAND_TYPE_ID:
- case SPV_OPERAND_TYPE_TYPE_ID:
- case SPV_OPERAND_TYPE_SCOPE_ID:
- case SPV_OPERAND_TYPE_MEMORY_SEMANTICS_ID:
- SetYellow();
- stream_ << "%" << name_mapper_(word);
- break;
- case SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER: {
- spv_ext_inst_desc ext_inst;
- SetRed();
- if (grammar_.lookupExtInst(inst.ext_inst_type, word, &ext_inst) ==
- SPV_SUCCESS) {
- stream_ << ext_inst->name;
- } else {
- if (!spvExtInstIsNonSemantic(inst.ext_inst_type)) {
- assert(false && "should have caught this earlier");
- } else {
- // for non-semantic instruction sets we can just print the number
- stream_ << word;
- }
- }
- } break;
- case SPV_OPERAND_TYPE_SPEC_CONSTANT_OP_NUMBER: {
- spv_opcode_desc opcode_desc;
- if (grammar_.lookupOpcode(SpvOp(word), &opcode_desc))
- assert(false && "should have caught this earlier");
- SetRed();
- stream_ << opcode_desc->name;
- } break;
- case SPV_OPERAND_TYPE_LITERAL_INTEGER:
- case SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER: {
- SetRed();
- spvtools::EmitNumericLiteral(&stream_, inst, operand);
- ResetColor();
- } break;
- case SPV_OPERAND_TYPE_LITERAL_STRING: {
- stream_ << "\"";
- SetGreen();
- // Strings are always little-endian, and null-terminated.
- // Write out the characters, escaping as needed, and without copying
- // the entire string.
- auto c_str = reinterpret_cast<const char*>(inst.words + operand.offset);
- for (auto p = c_str; *p; ++p) {
- if (*p == '"' || *p == '\\') stream_ << '\\';
- stream_ << *p;
- }
- ResetColor();
- stream_ << '"';
- } break;
- case SPV_OPERAND_TYPE_CAPABILITY:
- case SPV_OPERAND_TYPE_SOURCE_LANGUAGE:
- case SPV_OPERAND_TYPE_EXECUTION_MODEL:
- case SPV_OPERAND_TYPE_ADDRESSING_MODEL:
- case SPV_OPERAND_TYPE_MEMORY_MODEL:
- case SPV_OPERAND_TYPE_EXECUTION_MODE:
- case SPV_OPERAND_TYPE_STORAGE_CLASS:
- case SPV_OPERAND_TYPE_DIMENSIONALITY:
- case SPV_OPERAND_TYPE_SAMPLER_ADDRESSING_MODE:
- case SPV_OPERAND_TYPE_SAMPLER_FILTER_MODE:
- case SPV_OPERAND_TYPE_SAMPLER_IMAGE_FORMAT:
- case SPV_OPERAND_TYPE_FP_ROUNDING_MODE:
- case SPV_OPERAND_TYPE_LINKAGE_TYPE:
- case SPV_OPERAND_TYPE_ACCESS_QUALIFIER:
- case SPV_OPERAND_TYPE_FUNCTION_PARAMETER_ATTRIBUTE:
- case SPV_OPERAND_TYPE_DECORATION:
- case SPV_OPERAND_TYPE_BUILT_IN:
- case SPV_OPERAND_TYPE_GROUP_OPERATION:
- case SPV_OPERAND_TYPE_KERNEL_ENQ_FLAGS:
- case SPV_OPERAND_TYPE_KERNEL_PROFILING_INFO:
- case SPV_OPERAND_TYPE_RAY_FLAGS:
- case SPV_OPERAND_TYPE_RAY_QUERY_INTERSECTION:
- case SPV_OPERAND_TYPE_RAY_QUERY_COMMITTED_INTERSECTION_TYPE:
- case SPV_OPERAND_TYPE_RAY_QUERY_CANDIDATE_INTERSECTION_TYPE:
- case SPV_OPERAND_TYPE_DEBUG_BASE_TYPE_ATTRIBUTE_ENCODING:
- case SPV_OPERAND_TYPE_DEBUG_COMPOSITE_TYPE:
- case SPV_OPERAND_TYPE_DEBUG_TYPE_QUALIFIER:
- case SPV_OPERAND_TYPE_DEBUG_OPERATION:
- case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_BASE_TYPE_ATTRIBUTE_ENCODING:
- case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_COMPOSITE_TYPE:
- case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_TYPE_QUALIFIER:
- case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_OPERATION:
- case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_IMPORTED_ENTITY:
- case SPV_OPERAND_TYPE_FPDENORM_MODE:
- case SPV_OPERAND_TYPE_FPOPERATION_MODE:
- case SPV_OPERAND_TYPE_QUANTIZATION_MODES:
- case SPV_OPERAND_TYPE_OVERFLOW_MODES: {
- spv_operand_desc entry;
- if (grammar_.lookupOperand(operand.type, word, &entry))
- assert(false && "should have caught this earlier");
- stream_ << entry->name;
- } break;
- case SPV_OPERAND_TYPE_FP_FAST_MATH_MODE:
- case SPV_OPERAND_TYPE_FUNCTION_CONTROL:
- case SPV_OPERAND_TYPE_LOOP_CONTROL:
- case SPV_OPERAND_TYPE_IMAGE:
- case SPV_OPERAND_TYPE_MEMORY_ACCESS:
- case SPV_OPERAND_TYPE_SELECTION_CONTROL:
- case SPV_OPERAND_TYPE_DEBUG_INFO_FLAGS:
- case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_INFO_FLAGS:
- EmitMaskOperand(operand.type, word);
- break;
- default:
- if (spvOperandIsConcreteMask(operand.type)) {
- EmitMaskOperand(operand.type, word);
- } else if (spvOperandIsConcrete(operand.type)) {
- spv_operand_desc entry;
- if (grammar_.lookupOperand(operand.type, word, &entry))
- assert(false && "should have caught this earlier");
- stream_ << entry->name;
- } else {
- assert(false && "unhandled or invalid case");
- }
- break;
- }
- ResetColor();
-}
-
-void Disassembler::EmitMaskOperand(const spv_operand_type_t type,
- const uint32_t word) {
- // Scan the mask from least significant bit to most significant bit. For each
- // set bit, emit the name of that bit. Separate multiple names with '|'.
- uint32_t remaining_word = word;
- uint32_t mask;
- int num_emitted = 0;
- for (mask = 1; remaining_word; mask <<= 1) {
- if (remaining_word & mask) {
- remaining_word ^= mask;
- spv_operand_desc entry;
- if (grammar_.lookupOperand(type, mask, &entry))
- assert(false && "should have caught this earlier");
- if (num_emitted) stream_ << "|";
- stream_ << entry->name;
- num_emitted++;
- }
- }
- if (!num_emitted) {
- // An operand value of 0 was provided, so represent it by the name
- // of the 0 value. In many cases, that's "None".
- spv_operand_desc entry;
- if (SPV_SUCCESS == grammar_.lookupOperand(type, 0, &entry))
- stream_ << entry->name;
- }
-}
-
spv_result_t Disassembler::SaveTextResult(spv_text* text_result) const {
if (!print_) {
size_t length = text_.str().size();
@@ -470,8 +194,342 @@
return SPV_SUCCESS;
}
+constexpr int kStandardIndent = 15;
} // namespace
+namespace disassemble {
+InstructionDisassembler::InstructionDisassembler(const AssemblyGrammar& grammar,
+ std::ostream& stream,
+ uint32_t options,
+ NameMapper name_mapper)
+ : grammar_(grammar),
+ stream_(stream),
+ print_(spvIsInBitfield(SPV_BINARY_TO_TEXT_OPTION_PRINT, options)),
+ color_(spvIsInBitfield(SPV_BINARY_TO_TEXT_OPTION_COLOR, options)),
+ indent_(spvIsInBitfield(SPV_BINARY_TO_TEXT_OPTION_INDENT, options)
+ ? kStandardIndent
+ : 0),
+ comment_(spvIsInBitfield(SPV_BINARY_TO_TEXT_OPTION_COMMENT, options)),
+ show_byte_offset_(
+ spvIsInBitfield(SPV_BINARY_TO_TEXT_OPTION_SHOW_BYTE_OFFSET, options)),
+ name_mapper_(std::move(name_mapper)) {}
+
+void InstructionDisassembler::EmitHeaderSpirv() { stream_ << "; SPIR-V\n"; }
+
+void InstructionDisassembler::EmitHeaderVersion(uint32_t version) {
+ stream_ << "; Version: " << SPV_SPIRV_VERSION_MAJOR_PART(version) << "."
+ << SPV_SPIRV_VERSION_MINOR_PART(version) << "\n";
+}
+
+void InstructionDisassembler::EmitHeaderGenerator(uint32_t generator) {
+ const char* generator_tool =
+ spvGeneratorStr(SPV_GENERATOR_TOOL_PART(generator));
+ stream_ << "; Generator: " << generator_tool;
+ // For unknown tools, print the numeric tool value.
+ if (0 == strcmp("Unknown", generator_tool)) {
+ stream_ << "(" << SPV_GENERATOR_TOOL_PART(generator) << ")";
+ }
+ // Print the miscellaneous part of the generator word on the same
+ // line as the tool name.
+ stream_ << "; " << SPV_GENERATOR_MISC_PART(generator) << "\n";
+}
+
+void InstructionDisassembler::EmitHeaderIdBound(uint32_t id_bound) {
+ stream_ << "; Bound: " << id_bound << "\n";
+}
+
+void InstructionDisassembler::EmitHeaderSchema(uint32_t schema) {
+ stream_ << "; Schema: " << schema << "\n";
+}
+
+void InstructionDisassembler::EmitInstruction(
+ const spv_parsed_instruction_t& inst, size_t inst_byte_offset) {
+ auto opcode = static_cast<SpvOp>(inst.opcode);
+
+ if (inst.result_id) {
+ SetBlue();
+ const std::string id_name = name_mapper_(inst.result_id);
+ if (indent_)
+ stream_ << std::setw(std::max(0, indent_ - 3 - int(id_name.size())));
+ stream_ << "%" << id_name;
+ ResetColor();
+ stream_ << " = ";
+ } else {
+ stream_ << std::string(indent_, ' ');
+ }
+
+ stream_ << "Op" << spvOpcodeString(opcode);
+
+ for (uint16_t i = 0; i < inst.num_operands; i++) {
+ const spv_operand_type_t type = inst.operands[i].type;
+ assert(type != SPV_OPERAND_TYPE_NONE);
+ if (type == SPV_OPERAND_TYPE_RESULT_ID) continue;
+ stream_ << " ";
+ EmitOperand(inst, i);
+ }
+
+ if (comment_ && opcode == SpvOpName) {
+ const spv_parsed_operand_t& operand = inst.operands[0];
+ const uint32_t word = inst.words[operand.offset];
+ stream_ << " ; id %" << word;
+ }
+
+ if (show_byte_offset_) {
+ SetGrey();
+ auto saved_flags = stream_.flags();
+ auto saved_fill = stream_.fill();
+ stream_ << " ; 0x" << std::setw(8) << std::hex << std::setfill('0')
+ << inst_byte_offset;
+ stream_.flags(saved_flags);
+ stream_.fill(saved_fill);
+ ResetColor();
+ }
+ stream_ << "\n";
+}
+
+void InstructionDisassembler::EmitSectionComment(
+ const spv_parsed_instruction_t& inst, bool& inserted_decoration_space,
+ bool& inserted_debug_space, bool& inserted_type_space) {
+ auto opcode = static_cast<SpvOp>(inst.opcode);
+ if (comment_ && opcode == SpvOpFunction) {
+ stream_ << std::endl;
+ stream_ << std::string(indent_, ' ');
+ stream_ << "; Function " << name_mapper_(inst.result_id) << std::endl;
+ }
+ if (comment_ && !inserted_decoration_space && spvOpcodeIsDecoration(opcode)) {
+ inserted_decoration_space = true;
+ stream_ << std::endl;
+ stream_ << std::string(indent_, ' ');
+ stream_ << "; Annotations" << std::endl;
+ }
+ if (comment_ && !inserted_debug_space && spvOpcodeIsDebug(opcode)) {
+ inserted_debug_space = true;
+ stream_ << std::endl;
+ stream_ << std::string(indent_, ' ');
+ stream_ << "; Debug Information" << std::endl;
+ }
+ if (comment_ && !inserted_type_space && spvOpcodeGeneratesType(opcode)) {
+ inserted_type_space = true;
+ stream_ << std::endl;
+ stream_ << std::string(indent_, ' ');
+ stream_ << "; Types, variables and constants" << std::endl;
+ }
+}
+
+void InstructionDisassembler::EmitOperand(const spv_parsed_instruction_t& inst,
+ const uint16_t operand_index) {
+ assert(operand_index < inst.num_operands);
+ const spv_parsed_operand_t& operand = inst.operands[operand_index];
+ const uint32_t word = inst.words[operand.offset];
+ switch (operand.type) {
+ case SPV_OPERAND_TYPE_RESULT_ID:
+ assert(false && "<result-id> is not supposed to be handled here");
+ SetBlue();
+ stream_ << "%" << name_mapper_(word);
+ break;
+ case SPV_OPERAND_TYPE_ID:
+ case SPV_OPERAND_TYPE_TYPE_ID:
+ case SPV_OPERAND_TYPE_SCOPE_ID:
+ case SPV_OPERAND_TYPE_MEMORY_SEMANTICS_ID:
+ SetYellow();
+ stream_ << "%" << name_mapper_(word);
+ break;
+ case SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER: {
+ spv_ext_inst_desc ext_inst;
+ SetRed();
+ if (grammar_.lookupExtInst(inst.ext_inst_type, word, &ext_inst) ==
+ SPV_SUCCESS) {
+ stream_ << ext_inst->name;
+ } else {
+ if (!spvExtInstIsNonSemantic(inst.ext_inst_type)) {
+ assert(false && "should have caught this earlier");
+ } else {
+ // for non-semantic instruction sets we can just print the number
+ stream_ << word;
+ }
+ }
+ } break;
+ case SPV_OPERAND_TYPE_SPEC_CONSTANT_OP_NUMBER: {
+ spv_opcode_desc opcode_desc;
+ if (grammar_.lookupOpcode(SpvOp(word), &opcode_desc))
+ assert(false && "should have caught this earlier");
+ SetRed();
+ stream_ << opcode_desc->name;
+ } break;
+ case SPV_OPERAND_TYPE_LITERAL_INTEGER:
+ case SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER: {
+ SetRed();
+ EmitNumericLiteral(&stream_, inst, operand);
+ ResetColor();
+ } break;
+ case SPV_OPERAND_TYPE_LITERAL_STRING: {
+ stream_ << "\"";
+ SetGreen();
+
+ std::string str = spvDecodeLiteralStringOperand(inst, operand_index);
+ for (char const& c : str) {
+ if (c == '"' || c == '\\') stream_ << '\\';
+ stream_ << c;
+ }
+ ResetColor();
+ stream_ << '"';
+ } break;
+ case SPV_OPERAND_TYPE_CAPABILITY:
+ case SPV_OPERAND_TYPE_SOURCE_LANGUAGE:
+ case SPV_OPERAND_TYPE_EXECUTION_MODEL:
+ case SPV_OPERAND_TYPE_ADDRESSING_MODEL:
+ case SPV_OPERAND_TYPE_MEMORY_MODEL:
+ case SPV_OPERAND_TYPE_EXECUTION_MODE:
+ case SPV_OPERAND_TYPE_STORAGE_CLASS:
+ case SPV_OPERAND_TYPE_DIMENSIONALITY:
+ case SPV_OPERAND_TYPE_SAMPLER_ADDRESSING_MODE:
+ case SPV_OPERAND_TYPE_SAMPLER_FILTER_MODE:
+ case SPV_OPERAND_TYPE_SAMPLER_IMAGE_FORMAT:
+ case SPV_OPERAND_TYPE_FP_ROUNDING_MODE:
+ case SPV_OPERAND_TYPE_LINKAGE_TYPE:
+ case SPV_OPERAND_TYPE_ACCESS_QUALIFIER:
+ case SPV_OPERAND_TYPE_FUNCTION_PARAMETER_ATTRIBUTE:
+ case SPV_OPERAND_TYPE_DECORATION:
+ case SPV_OPERAND_TYPE_BUILT_IN:
+ case SPV_OPERAND_TYPE_GROUP_OPERATION:
+ case SPV_OPERAND_TYPE_KERNEL_ENQ_FLAGS:
+ case SPV_OPERAND_TYPE_KERNEL_PROFILING_INFO:
+ case SPV_OPERAND_TYPE_RAY_FLAGS:
+ case SPV_OPERAND_TYPE_RAY_QUERY_INTERSECTION:
+ case SPV_OPERAND_TYPE_RAY_QUERY_COMMITTED_INTERSECTION_TYPE:
+ case SPV_OPERAND_TYPE_RAY_QUERY_CANDIDATE_INTERSECTION_TYPE:
+ case SPV_OPERAND_TYPE_DEBUG_BASE_TYPE_ATTRIBUTE_ENCODING:
+ case SPV_OPERAND_TYPE_DEBUG_COMPOSITE_TYPE:
+ case SPV_OPERAND_TYPE_DEBUG_TYPE_QUALIFIER:
+ case SPV_OPERAND_TYPE_DEBUG_OPERATION:
+ case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_BASE_TYPE_ATTRIBUTE_ENCODING:
+ case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_COMPOSITE_TYPE:
+ case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_TYPE_QUALIFIER:
+ case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_OPERATION:
+ case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_IMPORTED_ENTITY:
+ case SPV_OPERAND_TYPE_FPDENORM_MODE:
+ case SPV_OPERAND_TYPE_FPOPERATION_MODE:
+ case SPV_OPERAND_TYPE_QUANTIZATION_MODES:
+ case SPV_OPERAND_TYPE_OVERFLOW_MODES: {
+ spv_operand_desc entry;
+ if (grammar_.lookupOperand(operand.type, word, &entry))
+ assert(false && "should have caught this earlier");
+ stream_ << entry->name;
+ } break;
+ case SPV_OPERAND_TYPE_FP_FAST_MATH_MODE:
+ case SPV_OPERAND_TYPE_FUNCTION_CONTROL:
+ case SPV_OPERAND_TYPE_LOOP_CONTROL:
+ case SPV_OPERAND_TYPE_IMAGE:
+ case SPV_OPERAND_TYPE_MEMORY_ACCESS:
+ case SPV_OPERAND_TYPE_SELECTION_CONTROL:
+ case SPV_OPERAND_TYPE_DEBUG_INFO_FLAGS:
+ case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_INFO_FLAGS:
+ EmitMaskOperand(operand.type, word);
+ break;
+ default:
+ if (spvOperandIsConcreteMask(operand.type)) {
+ EmitMaskOperand(operand.type, word);
+ } else if (spvOperandIsConcrete(operand.type)) {
+ spv_operand_desc entry;
+ if (grammar_.lookupOperand(operand.type, word, &entry))
+ assert(false && "should have caught this earlier");
+ stream_ << entry->name;
+ } else {
+ assert(false && "unhandled or invalid case");
+ }
+ break;
+ }
+ ResetColor();
+}
+
+void InstructionDisassembler::EmitMaskOperand(const spv_operand_type_t type,
+ const uint32_t word) {
+ // Scan the mask from least significant bit to most significant bit. For each
+ // set bit, emit the name of that bit. Separate multiple names with '|'.
+ uint32_t remaining_word = word;
+ uint32_t mask;
+ int num_emitted = 0;
+ for (mask = 1; remaining_word; mask <<= 1) {
+ if (remaining_word & mask) {
+ remaining_word ^= mask;
+ spv_operand_desc entry;
+ if (grammar_.lookupOperand(type, mask, &entry))
+ assert(false && "should have caught this earlier");
+ if (num_emitted) stream_ << "|";
+ stream_ << entry->name;
+ num_emitted++;
+ }
+ }
+ if (!num_emitted) {
+ // An operand value of 0 was provided, so represent it by the name
+ // of the 0 value. In many cases, that's "None".
+ spv_operand_desc entry;
+ if (SPV_SUCCESS == grammar_.lookupOperand(type, 0, &entry))
+ stream_ << entry->name;
+ }
+}
+
+void InstructionDisassembler::ResetColor() {
+ if (color_) stream_ << spvtools::clr::reset{print_};
+}
+void InstructionDisassembler::SetGrey() {
+ if (color_) stream_ << spvtools::clr::grey{print_};
+}
+void InstructionDisassembler::SetBlue() {
+ if (color_) stream_ << spvtools::clr::blue{print_};
+}
+void InstructionDisassembler::SetYellow() {
+ if (color_) stream_ << spvtools::clr::yellow{print_};
+}
+void InstructionDisassembler::SetRed() {
+ if (color_) stream_ << spvtools::clr::red{print_};
+}
+void InstructionDisassembler::SetGreen() {
+ if (color_) stream_ << spvtools::clr::green{print_};
+}
+} // namespace disassemble
+
+std::string spvInstructionBinaryToText(const spv_target_env env,
+ const uint32_t* instCode,
+ const size_t instWordCount,
+ const uint32_t* code,
+ const size_t wordCount,
+ const uint32_t options) {
+ spv_context context = spvContextCreate(env);
+ const AssemblyGrammar grammar(context);
+ if (!grammar.isValid()) {
+ spvContextDestroy(context);
+ return "";
+ }
+
+ // Generate friendly names for Ids if requested.
+ std::unique_ptr<FriendlyNameMapper> friendly_mapper;
+ NameMapper name_mapper = GetTrivialNameMapper();
+ if (options & SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES) {
+ friendly_mapper = MakeUnique<FriendlyNameMapper>(context, code, wordCount);
+ name_mapper = friendly_mapper->GetNameMapper();
+ }
+
+ // Now disassemble!
+ Disassembler disassembler(grammar, options, name_mapper);
+ WrappedDisassembler wrapped(&disassembler, instCode, instWordCount);
+ spvBinaryParse(context, &wrapped, code, wordCount, DisassembleTargetHeader,
+ DisassembleTargetInstruction, nullptr);
+
+ spv_text text = nullptr;
+ std::string output;
+ if (disassembler.SaveTextResult(&text) == SPV_SUCCESS) {
+ output.assign(text->str, text->str + text->length);
+ // Drop trailing newline characters.
+ while (!output.empty() && output.back() == '\n') output.pop_back();
+ }
+ spvTextDestroy(text);
+ spvContextDestroy(context);
+
+ return output;
+}
+} // namespace spvtools
+
spv_result_t spvBinaryToText(const spv_const_context context,
const uint32_t* code, const size_t wordCount,
const uint32_t options, spv_text* pText,
@@ -495,53 +553,13 @@
}
// Now disassemble!
- Disassembler disassembler(grammar, options, name_mapper);
- if (auto error = spvBinaryParse(&hijack_context, &disassembler, code,
- wordCount, DisassembleHeader,
- DisassembleInstruction, pDiagnostic)) {
+ spvtools::Disassembler disassembler(grammar, options, name_mapper);
+ if (auto error =
+ spvBinaryParse(&hijack_context, &disassembler, code, wordCount,
+ spvtools::DisassembleHeader,
+ spvtools::DisassembleInstruction, pDiagnostic)) {
return error;
}
return disassembler.SaveTextResult(pText);
}
-
-std::string spvtools::spvInstructionBinaryToText(const spv_target_env env,
- const uint32_t* instCode,
- const size_t instWordCount,
- const uint32_t* code,
- const size_t wordCount,
- const uint32_t options) {
- spv_context context = spvContextCreate(env);
- const spvtools::AssemblyGrammar grammar(context);
- if (!grammar.isValid()) {
- spvContextDestroy(context);
- return "";
- }
-
- // Generate friendly names for Ids if requested.
- std::unique_ptr<spvtools::FriendlyNameMapper> friendly_mapper;
- spvtools::NameMapper name_mapper = spvtools::GetTrivialNameMapper();
- if (options & SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES) {
- friendly_mapper = spvtools::MakeUnique<spvtools::FriendlyNameMapper>(
- context, code, wordCount);
- name_mapper = friendly_mapper->GetNameMapper();
- }
-
- // Now disassemble!
- Disassembler disassembler(grammar, options, name_mapper);
- WrappedDisassembler wrapped(&disassembler, instCode, instWordCount);
- spvBinaryParse(context, &wrapped, code, wordCount, DisassembleTargetHeader,
- DisassembleTargetInstruction, nullptr);
-
- spv_text text = nullptr;
- std::string output;
- if (disassembler.SaveTextResult(&text) == SPV_SUCCESS) {
- output.assign(text->str, text->str + text->length);
- // Drop trailing newline characters.
- while (!output.empty() && output.back() == '\n') output.pop_back();
- }
- spvTextDestroy(text);
- spvContextDestroy(context);
-
- return output;
-}
diff --git a/third_party/SPIRV-Tools/source/disassemble.h b/third_party/SPIRV-Tools/source/disassemble.h
index ac35742..8eacb10 100644
--- a/third_party/SPIRV-Tools/source/disassemble.h
+++ b/third_party/SPIRV-Tools/source/disassemble.h
@@ -15,8 +15,10 @@
#ifndef SOURCE_DISASSEMBLE_H_
#define SOURCE_DISASSEMBLE_H_
+#include <iosfwd>
#include <string>
+#include "source/name_mapper.h"
#include "spirv-tools/libspirv.h"
namespace spvtools {
@@ -33,6 +35,63 @@
const size_t word_count,
const uint32_t options);
+class AssemblyGrammar;
+namespace disassemble {
+
+// Shared code with other tools (than the disassembler) that might need to
+// output disassembly. An InstructionDisassembler instance converts SPIR-V
+// binary for an instruction to its assembly representation.
+class InstructionDisassembler {
+ public:
+ InstructionDisassembler(const AssemblyGrammar& grammar, std::ostream& stream,
+ uint32_t options, NameMapper name_mapper);
+
+ // Emits the assembly header for the module.
+ void EmitHeaderSpirv();
+ void EmitHeaderVersion(uint32_t version);
+ void EmitHeaderGenerator(uint32_t generator);
+ void EmitHeaderIdBound(uint32_t id_bound);
+ void EmitHeaderSchema(uint32_t schema);
+
+ // Emits the assembly text for the given instruction.
+ void EmitInstruction(const spv_parsed_instruction_t& inst,
+ size_t inst_byte_offset);
+
+ // Emits a comment between different sections of the module.
+ void EmitSectionComment(const spv_parsed_instruction_t& inst,
+ bool& inserted_decoration_space,
+ bool& inserted_debug_space,
+ bool& inserted_type_space);
+
+ // Resets the output color, if color is turned on.
+ void ResetColor();
+ // Set the output color, if color is turned on.
+ void SetGrey();
+ void SetBlue();
+ void SetYellow();
+ void SetRed();
+ void SetGreen();
+
+ private:
+ // Emits an operand for the given instruction, where the instruction
+ // is at offset words from the start of the binary.
+ void EmitOperand(const spv_parsed_instruction_t& inst,
+ const uint16_t operand_index);
+
+ // Emits a mask expression for the given mask word of the specified type.
+ void EmitMaskOperand(const spv_operand_type_t type, const uint32_t word);
+
+ const spvtools::AssemblyGrammar& grammar_;
+ std::ostream& stream_;
+ const bool print_; // Should we also print to the standard output stream?
+ const bool color_; // Should we print in colour?
+ const int indent_; // How much to indent. 0 means don't indent
+ const int comment_; // Should we comment the source
+ const bool show_byte_offset_; // Should we print byte offset, in hex?
+ spvtools::NameMapper name_mapper_;
+};
+
+} // namespace disassemble
} // namespace spvtools
#endif // SOURCE_DISASSEMBLE_H_
diff --git a/third_party/SPIRV-Tools/source/ext_inst.cpp b/third_party/SPIRV-Tools/source/ext_inst.cpp
index 812053e..4e27954 100644
--- a/third_party/SPIRV-Tools/source/ext_inst.cpp
+++ b/third_party/SPIRV-Tools/source/ext_inst.cpp
@@ -96,6 +96,8 @@
case SPV_ENV_UNIVERSAL_1_4:
case SPV_ENV_UNIVERSAL_1_5:
case SPV_ENV_VULKAN_1_2:
+ case SPV_ENV_UNIVERSAL_1_6:
+ case SPV_ENV_VULKAN_1_3:
*pExtInstTable = &kTable_1_0;
return SPV_SUCCESS;
default:
diff --git a/third_party/SPIRV-Tools/source/ext_inst.h b/third_party/SPIRV-Tools/source/ext_inst.h
index aff6e30..4027f4c 100644
--- a/third_party/SPIRV-Tools/source/ext_inst.h
+++ b/third_party/SPIRV-Tools/source/ext_inst.h
@@ -27,7 +27,7 @@
// Returns true if the extended instruction set is debug info
bool spvExtInstIsDebugInfo(const spv_ext_inst_type_t type);
-// Finds the named extented instruction of the given type in the given extended
+// Finds the named extended instruction of the given type in the given extended
// instruction table. On success, returns SPV_SUCCESS and writes a handle of
// the instruction entry into *entry.
spv_result_t spvExtInstTableNameLookup(const spv_ext_inst_table table,
@@ -35,7 +35,7 @@
const char* name,
spv_ext_inst_desc* entry);
-// Finds the extented instruction of the given type in the given extended
+// Finds the extended instruction of the given type in the given extended
// instruction table by value. On success, returns SPV_SUCCESS and writes a
// handle of the instruction entry into *entry.
spv_result_t spvExtInstTableValueLookup(const spv_ext_inst_table table,
diff --git a/third_party/SPIRV-Tools/source/extensions.cpp b/third_party/SPIRV-Tools/source/extensions.cpp
index a94db27..049a3ad 100644
--- a/third_party/SPIRV-Tools/source/extensions.cpp
+++ b/third_party/SPIRV-Tools/source/extensions.cpp
@@ -18,6 +18,7 @@
#include <sstream>
#include <string>
+#include "source/binary.h"
#include "source/enum_string_mapping.h"
namespace spvtools {
@@ -30,8 +31,9 @@
const auto& operand = inst->operands[0];
assert(operand.type == SPV_OPERAND_TYPE_LITERAL_STRING);
assert(inst->num_words > operand.offset);
+ (void)operand; /* No unused variables in release builds. */
- return reinterpret_cast<const char*>(inst->words + operand.offset);
+ return spvDecodeLiteralStringOperand(*inst, 0);
}
std::string ExtensionSetToString(const ExtensionSet& extensions) {
diff --git a/third_party/SPIRV-Tools/source/fuzz/fact_manager/fact_manager.h b/third_party/SPIRV-Tools/source/fuzz/fact_manager/fact_manager.h
index 5cf5b18..ce28ae4 100644
--- a/third_party/SPIRV-Tools/source/fuzz/fact_manager/fact_manager.h
+++ b/third_party/SPIRV-Tools/source/fuzz/fact_manager/fact_manager.h
@@ -163,7 +163,7 @@
std::vector<const protobufs::DataDescriptor*> GetSynonymsForDataDescriptor(
const protobufs::DataDescriptor& data_descriptor) const;
- // Returns true if and ony if |data_descriptor1| and |data_descriptor2| are
+ // Returns true if and only if |data_descriptor1| and |data_descriptor2| are
// known to be synonymous.
bool IsSynonymous(const protobufs::DataDescriptor& data_descriptor1,
const protobufs::DataDescriptor& data_descriptor2) const;
@@ -174,7 +174,7 @@
//==============================
// Querying facts about dead blocks
- // Returns true if and ony if |block_id| is the id of a block known to be
+ // Returns true if and only if |block_id| is the id of a block known to be
// dynamically unreachable.
bool BlockIsDead(uint32_t block_id) const;
@@ -184,7 +184,7 @@
//==============================
// Querying facts about livesafe function
- // Returns true if and ony if |function_id| is the id of a function known
+ // Returns true if and only if |function_id| is the id of a function known
// to be livesafe.
bool FunctionIsLivesafe(uint32_t function_id) const;
@@ -194,7 +194,7 @@
//==============================
// Querying facts about irrelevant values
- // Returns true if and ony if the value of the pointee associated with
+ // Returns true if and only if the value of the pointee associated with
// |pointer_id| is irrelevant.
bool PointeeValueIsIrrelevant(uint32_t pointer_id) const;
diff --git a/third_party/SPIRV-Tools/source/fuzz/fuzzer_context.cpp b/third_party/SPIRV-Tools/source/fuzz/fuzzer_context.cpp
index c217542..7e34cc3 100644
--- a/third_party/SPIRV-Tools/source/fuzz/fuzzer_context.cpp
+++ b/third_party/SPIRV-Tools/source/fuzz/fuzzer_context.cpp
@@ -21,7 +21,7 @@
namespace {
-// An offset between the the module's id bound and the minimum fresh id.
+// An offset between the module's id bound and the minimum fresh id.
//
// TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/2541): consider
// the case where the maximum id bound is reached.
diff --git a/third_party/SPIRV-Tools/source/fuzz/fuzzer_pass.cpp b/third_party/SPIRV-Tools/source/fuzz/fuzzer_pass.cpp
index d91482c..6a87985 100644
--- a/third_party/SPIRV-Tools/source/fuzz/fuzzer_pass.cpp
+++ b/third_party/SPIRV-Tools/source/fuzz/fuzzer_pass.cpp
@@ -261,7 +261,7 @@
uint32_t FuzzerPass::FindOrCreateFunctionType(
uint32_t return_type_id, const std::vector<uint32_t>& argument_id) {
- // FindFunctionType has a sigle argument for OpTypeFunction operands
+ // FindFunctionType has a single argument for OpTypeFunction operands
// so we will have to copy them all in this vector
std::vector<uint32_t> type_ids(argument_id.size() + 1);
type_ids[0] = return_type_id;
diff --git a/third_party/SPIRV-Tools/source/fuzz/fuzzer_pass_donate_modules.cpp b/third_party/SPIRV-Tools/source/fuzz/fuzzer_pass_donate_modules.cpp
index 5bdf697..29ede58 100644
--- a/third_party/SPIRV-Tools/source/fuzz/fuzzer_pass_donate_modules.cpp
+++ b/third_party/SPIRV-Tools/source/fuzz/fuzzer_pass_donate_modules.cpp
@@ -479,7 +479,7 @@
"should have been donated.");
// It is OK to have duplicate constant composite definitions, so add
- // this to the module using remapped versions of all consituent ids and
+ // this to the module using remapped versions of all constituent ids and
// the result type.
new_result_id = GetFuzzerContext()->GetFreshId();
std::vector<uint32_t> constituent_ids;
diff --git a/third_party/SPIRV-Tools/source/fuzz/protobufs/spvtoolsfuzz.proto b/third_party/SPIRV-Tools/source/fuzz/protobufs/spvtoolsfuzz.proto
index cba9397..e71b6a3 100644
--- a/third_party/SPIRV-Tools/source/fuzz/protobufs/spvtoolsfuzz.proto
+++ b/third_party/SPIRV-Tools/source/fuzz/protobufs/spvtoolsfuzz.proto
@@ -1961,10 +1961,10 @@
// A descriptor for the boolean constant id we would like to replace
IdUseDescriptor id_use_descriptor = 1;
- // Id for the constant to be used on the LHS of the comparision
+ // Id for the constant to be used on the LHS of the comparison
uint32 lhs_id = 2;
- // Id for the constant to be used on the RHS of the comparision
+ // Id for the constant to be used on the RHS of the comparison
uint32 rhs_id = 3;
// Opcode for binary operator
@@ -2403,7 +2403,7 @@
// va = vector(..., a, ...)
// vb = vector(..., b, ...)
//
- // where a and b are in the same position i in each of their correponding vector
+ // where a and b are in the same position i in each of their corresponding vector
// and a is synonymous with va[i] and b is synonymous with vb[i].
//
// The transformation then add an instruction vc = va op vb where c is synonymous
diff --git a/third_party/SPIRV-Tools/source/fuzz/transformation_add_constant_composite.cpp b/third_party/SPIRV-Tools/source/fuzz/transformation_add_constant_composite.cpp
index e6cd5a9..89007ab 100644
--- a/third_party/SPIRV-Tools/source/fuzz/transformation_add_constant_composite.cpp
+++ b/third_party/SPIRV-Tools/source/fuzz/transformation_add_constant_composite.cpp
@@ -75,7 +75,7 @@
// We do not create constants of structs decorated with Block nor
// BufferBlock. The SPIR-V spec does not explicitly disallow this, but it
// seems like a strange thing to do, so we disallow it to avoid triggering
- // low priorty edge case issues related to it.
+ // low priority edge case issues related to it.
if (fuzzerutil::HasBlockOrBufferBlockDecoration(
ir_context, composite_type_instruction->result_id())) {
return false;
diff --git a/third_party/SPIRV-Tools/source/fuzz/transformation_duplicate_region_with_selection.cpp b/third_party/SPIRV-Tools/source/fuzz/transformation_duplicate_region_with_selection.cpp
index a80becd..db88610 100644
--- a/third_party/SPIRV-Tools/source/fuzz/transformation_duplicate_region_with_selection.cpp
+++ b/third_party/SPIRV-Tools/source/fuzz/transformation_duplicate_region_with_selection.cpp
@@ -325,7 +325,7 @@
std::map<uint32_t, uint32_t> original_id_to_phi_id =
fuzzerutil::RepeatedUInt32PairToMap(message_.original_id_to_phi_id());
- // Use oveflow ids to fill in any required ids that are missing from these
+ // Use overflow ids to fill in any required ids that are missing from these
// maps.
for (auto block : region_blocks) {
if (original_label_to_duplicate_label.count(block->id()) == 0) {
diff --git a/third_party/SPIRV-Tools/source/fuzz/transformation_replace_id_with_synonym.h b/third_party/SPIRV-Tools/source/fuzz/transformation_replace_id_with_synonym.h
index 4570fce..66f8e43 100644
--- a/third_party/SPIRV-Tools/source/fuzz/transformation_replace_id_with_synonym.h
+++ b/third_party/SPIRV-Tools/source/fuzz/transformation_replace_id_with_synonym.h
@@ -32,7 +32,7 @@
protobufs::IdUseDescriptor id_use_descriptor, uint32_t synonymous_id);
// - The fact manager must know that the id identified by
- // |message_.id_use_descriptor| is synonomous with |message_.synonymous_id|.
+ // |message_.id_use_descriptor| is synonymous with |message_.synonymous_id|.
// - Replacing the id in |message_.id_use_descriptor| by
// |message_.synonymous_id| must respect SPIR-V's rules about uses being
// dominated by their definitions.
diff --git a/third_party/SPIRV-Tools/source/link/CMakeLists.txt b/third_party/SPIRV-Tools/source/link/CMakeLists.txt
index c8dd2f7..a452a10 100644
--- a/third_party/SPIRV-Tools/source/link/CMakeLists.txt
+++ b/third_party/SPIRV-Tools/source/link/CMakeLists.txt
@@ -23,7 +23,7 @@
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
PRIVATE ${spirv-tools_BINARY_DIR}
)
-# We need the IR functionnalities from the optimizer
+# We need the IR functionalities from the optimizer
target_link_libraries(SPIRV-Tools-link
PUBLIC SPIRV-Tools-opt)
diff --git a/third_party/SPIRV-Tools/source/link/linker.cpp b/third_party/SPIRV-Tools/source/link/linker.cpp
index c5ca562..76ce775 100644
--- a/third_party/SPIRV-Tools/source/link/linker.cpp
+++ b/third_party/SPIRV-Tools/source/link/linker.cpp
@@ -19,6 +19,7 @@
#include <cstring>
#include <iostream>
#include <memory>
+#include <numeric>
#include <string>
#include <unordered_map>
#include <unordered_set>
@@ -37,6 +38,7 @@
#include "source/spirv_constant.h"
#include "source/spirv_target_env.h"
#include "source/util/make_unique.h"
+#include "source/util/string_utils.h"
#include "spirv-tools/libspirv.hpp"
namespace spvtools {
@@ -86,10 +88,6 @@
//
// |header| should not be null, |modules| should not be empty and pointers
// should be non-null. |max_id_bound| should be strictly greater than 0.
-//
-// TODO(pierremoreau): What to do when binaries use different versions of
-// SPIR-V? For now, use the max of all versions found in
-// the input modules.
spv_result_t GenerateHeader(const MessageConsumer& consumer,
const std::vector<opt::Module*>& modules,
uint32_t max_id_bound, opt::ModuleHeader* header);
@@ -130,7 +128,7 @@
// Remove linkage specific instructions, such as prototypes of imported
// functions, declarations of imported variables, import (and export if
-// necessary) linkage attribtes.
+// necessary) linkage attributes.
//
// |linked_context| and |decoration_manager| should not be null, and the
// 'RemoveDuplicatePass' should be run first.
@@ -148,6 +146,15 @@
spv_result_t VerifyIds(const MessageConsumer& consumer,
opt::IRContext* linked_context);
+// Verify that the universal limits are not crossed, and warn the user
+// otherwise.
+//
+// TODO(pierremoreau):
+// - Verify against the limits of the environment (e.g. Vulkan limits if
+// consuming vulkan1.x)
+spv_result_t VerifyLimits(const MessageConsumer& consumer,
+ const opt::IRContext& linked_context);
+
spv_result_t ShiftIdsInModules(const MessageConsumer& consumer,
std::vector<opt::Module*>* modules,
uint32_t* max_id_bound) {
@@ -163,29 +170,31 @@
return DiagnosticStream(position, consumer, "", SPV_ERROR_INVALID_DATA)
<< "|max_id_bound| of ShiftIdsInModules should not be null.";
- uint32_t id_bound = modules->front()->IdBound() - 1u;
+ const size_t id_bound =
+ std::accumulate(modules->begin(), modules->end(), static_cast<size_t>(1),
+ [](const size_t& accumulation, opt::Module* module) {
+ return accumulation + module->IdBound() - 1u;
+ });
+ if (id_bound > std::numeric_limits<uint32_t>::max())
+ return DiagnosticStream(position, consumer, "", SPV_ERROR_INVALID_DATA)
+ << "Too many IDs (" << id_bound
+ << "): combining all modules would overflow the 32-bit word of the "
+ "SPIR-V header.";
+
+ *max_id_bound = static_cast<uint32_t>(id_bound);
+
+ uint32_t id_offset = modules->front()->IdBound() - 1u;
for (auto module_iter = modules->begin() + 1; module_iter != modules->end();
++module_iter) {
Module* module = *module_iter;
- module->ForEachInst([&id_bound](Instruction* insn) {
- insn->ForEachId([&id_bound](uint32_t* id) { *id += id_bound; });
+ module->ForEachInst([&id_offset](Instruction* insn) {
+ insn->ForEachId([&id_offset](uint32_t* id) { *id += id_offset; });
});
- id_bound += module->IdBound() - 1u;
- if (id_bound > 0x3FFFFF)
- return DiagnosticStream(position, consumer, "", SPV_ERROR_INVALID_ID)
- << "The limit of IDs, 4194303, was exceeded:"
- << " " << id_bound << " is the current ID bound.";
+ id_offset += module->IdBound() - 1u;
// Invalidate the DefUseManager
module->context()->InvalidateAnalyses(opt::IRContext::kAnalysisDefUse);
}
- ++id_bound;
- if (id_bound > 0x3FFFFF)
- return DiagnosticStream(position, consumer, "", SPV_ERROR_INVALID_ID)
- << "The limit of IDs, 4194303, was exceeded:"
- << " " << id_bound << " is the current ID bound.";
-
- *max_id_bound = id_bound;
return SPV_SUCCESS;
}
@@ -202,15 +211,25 @@
return DiagnosticStream(position, consumer, "", SPV_ERROR_INVALID_DATA)
<< "|max_id_bound| of GenerateHeader should not be null.";
- uint32_t version = 0u;
- for (const auto& module : modules)
- version = std::max(version, module->version());
+ const uint32_t linked_version = modules.front()->version();
+ for (std::size_t i = 1; i < modules.size(); ++i) {
+ const uint32_t module_version = modules[i]->version();
+ if (module_version != linked_version)
+ return DiagnosticStream({0, 0, 1}, consumer, "", SPV_ERROR_INTERNAL)
+ << "Conflicting SPIR-V versions: "
+ << SPV_SPIRV_VERSION_MAJOR_PART(linked_version) << "."
+ << SPV_SPIRV_VERSION_MINOR_PART(linked_version)
+ << " (input modules 1 through " << i << ") vs "
+ << SPV_SPIRV_VERSION_MAJOR_PART(module_version) << "."
+ << SPV_SPIRV_VERSION_MINOR_PART(module_version)
+ << " (input module " << (i + 1) << ").";
+ }
header->magic_number = SpvMagicNumber;
- header->version = version;
+ header->version = linked_version;
header->generator = SPV_GENERATOR_WORD(SPV_GENERATOR_KHRONOS_LINKER, 0);
header->bound = max_id_bound;
- header->reserved = 0u;
+ header->schema = 0u;
return SPV_SUCCESS;
}
@@ -243,55 +262,65 @@
linked_module->AddExtInstImport(
std::unique_ptr<Instruction>(inst.Clone(linked_context)));
- do {
- const Instruction* memory_model_inst = input_modules[0]->GetMemoryModel();
- if (memory_model_inst == nullptr) break;
+ const Instruction* linked_memory_model_inst =
+ input_modules.front()->GetMemoryModel();
+ if (linked_memory_model_inst == nullptr) {
+ return DiagnosticStream(position, consumer, "", SPV_ERROR_INVALID_BINARY)
+ << "Input module 1 is lacking an OpMemoryModel instruction.";
+ }
+ const uint32_t linked_addressing_model =
+ linked_memory_model_inst->GetSingleWordOperand(0u);
+ const uint32_t linked_memory_model =
+ linked_memory_model_inst->GetSingleWordOperand(1u);
- uint32_t addressing_model = memory_model_inst->GetSingleWordOperand(0u);
- uint32_t memory_model = memory_model_inst->GetSingleWordOperand(1u);
- for (const auto& module : input_modules) {
- memory_model_inst = module->GetMemoryModel();
- if (memory_model_inst == nullptr) continue;
+ for (std::size_t i = 1; i < input_modules.size(); ++i) {
+ const Module* module = input_modules[i];
+ const Instruction* memory_model_inst = module->GetMemoryModel();
+ if (memory_model_inst == nullptr)
+ return DiagnosticStream(position, consumer, "", SPV_ERROR_INVALID_BINARY)
+ << "Input module " << (i + 1)
+ << " is lacking an OpMemoryModel instruction.";
- if (addressing_model != memory_model_inst->GetSingleWordOperand(0u)) {
- spv_operand_desc initial_desc = nullptr, current_desc = nullptr;
- grammar.lookupOperand(SPV_OPERAND_TYPE_ADDRESSING_MODEL,
- addressing_model, &initial_desc);
- grammar.lookupOperand(SPV_OPERAND_TYPE_ADDRESSING_MODEL,
- memory_model_inst->GetSingleWordOperand(0u),
- ¤t_desc);
- return DiagnosticStream(position, consumer, "", SPV_ERROR_INTERNAL)
- << "Conflicting addressing models: " << initial_desc->name
- << " vs " << current_desc->name << ".";
- }
- if (memory_model != memory_model_inst->GetSingleWordOperand(1u)) {
- spv_operand_desc initial_desc = nullptr, current_desc = nullptr;
- grammar.lookupOperand(SPV_OPERAND_TYPE_MEMORY_MODEL, memory_model,
- &initial_desc);
- grammar.lookupOperand(SPV_OPERAND_TYPE_MEMORY_MODEL,
- memory_model_inst->GetSingleWordOperand(1u),
- ¤t_desc);
- return DiagnosticStream(position, consumer, "", SPV_ERROR_INTERNAL)
- << "Conflicting memory models: " << initial_desc->name << " vs "
- << current_desc->name << ".";
- }
+ const uint32_t module_addressing_model =
+ memory_model_inst->GetSingleWordOperand(0u);
+ if (module_addressing_model != linked_addressing_model) {
+ spv_operand_desc linked_desc = nullptr, module_desc = nullptr;
+ grammar.lookupOperand(SPV_OPERAND_TYPE_ADDRESSING_MODEL,
+ linked_addressing_model, &linked_desc);
+ grammar.lookupOperand(SPV_OPERAND_TYPE_ADDRESSING_MODEL,
+ module_addressing_model, &module_desc);
+ return DiagnosticStream(position, consumer, "", SPV_ERROR_INTERNAL)
+ << "Conflicting addressing models: " << linked_desc->name
+ << " (input modules 1 through " << i << ") vs "
+ << module_desc->name << " (input module " << (i + 1) << ").";
}
- if (memory_model_inst != nullptr)
- linked_module->SetMemoryModel(std::unique_ptr<Instruction>(
- memory_model_inst->Clone(linked_context)));
- } while (false);
+ const uint32_t module_memory_model =
+ memory_model_inst->GetSingleWordOperand(1u);
+ if (module_memory_model != linked_memory_model) {
+ spv_operand_desc linked_desc = nullptr, module_desc = nullptr;
+ grammar.lookupOperand(SPV_OPERAND_TYPE_MEMORY_MODEL, linked_memory_model,
+ &linked_desc);
+ grammar.lookupOperand(SPV_OPERAND_TYPE_MEMORY_MODEL, module_memory_model,
+ &module_desc);
+ return DiagnosticStream(position, consumer, "", SPV_ERROR_INTERNAL)
+ << "Conflicting memory models: " << linked_desc->name
+ << " (input modules 1 through " << i << ") vs "
+ << module_desc->name << " (input module " << (i + 1) << ").";
+ }
+ }
+ linked_module->SetMemoryModel(std::unique_ptr<Instruction>(
+ linked_memory_model_inst->Clone(linked_context)));
- std::vector<std::pair<uint32_t, const char*>> entry_points;
+ std::vector<std::pair<uint32_t, std::string>> entry_points;
for (const auto& module : input_modules)
for (const auto& inst : module->entry_points()) {
const uint32_t model = inst.GetSingleWordInOperand(0);
- const char* const name =
- reinterpret_cast<const char*>(inst.GetInOperand(2).words.data());
+ const std::string name = inst.GetInOperand(2).AsString();
const auto i = std::find_if(
entry_points.begin(), entry_points.end(),
- [model, name](const std::pair<uint32_t, const char*>& v) {
- return v.first == model && strcmp(name, v.second) == 0;
+ [model, name](const std::pair<uint32_t, std::string>& v) {
+ return v.first == model && v.second == name;
});
if (i != entry_points.end()) {
spv_operand_desc desc = nullptr;
@@ -332,13 +361,10 @@
// If the generated module uses SPIR-V 1.1 or higher, add an
// OpModuleProcessed instruction about the linking step.
- if (linked_module->version() >= 0x10100) {
+ if (linked_module->version() >= SPV_SPIRV_VERSION_WORD(1, 1)) {
const std::string processed_string("Linked by SPIR-V Tools Linker");
- const auto num_chars = processed_string.size();
- // Compute num words, accommodate the terminating null character.
- const auto num_words = (num_chars + 1 + 3) / 4;
- std::vector<uint32_t> processed_words(num_words, 0u);
- std::memcpy(processed_words.data(), processed_string.data(), num_chars);
+ std::vector<uint32_t> processed_words =
+ spvtools::utils::MakeVector(processed_string);
linked_module->AddDebug3Inst(std::unique_ptr<Instruction>(
new Instruction(linked_context, SpvOpModuleProcessed, 0u, 0u,
{{SPV_OPERAND_TYPE_LITERAL_STRING, processed_words}})));
@@ -352,18 +378,12 @@
// TODO(pierremoreau): Since the modules have not been validate, should we
// expect SpvStorageClassFunction variables outside
// functions?
- uint32_t num_global_values = 0u;
for (const auto& module : input_modules) {
for (const auto& inst : module->types_values()) {
linked_module->AddType(
std::unique_ptr<Instruction>(inst.Clone(linked_context)));
- num_global_values += inst.opcode() == SpvOpVariable;
}
}
- if (num_global_values > 0xFFFF)
- return DiagnosticStream(position, consumer, "", SPV_ERROR_INTERNAL)
- << "The limit of global values, 65535, was exceeded;"
- << " " << num_global_values << " global values were found.";
// Process functions and their basic blocks
for (const auto& module : input_modules) {
@@ -414,8 +434,7 @@
const uint32_t type = decoration.GetSingleWordInOperand(3u);
LinkageSymbolInfo symbol_info;
- symbol_info.name =
- reinterpret_cast<const char*>(decoration.GetInOperand(2u).words.data());
+ symbol_info.name = decoration.GetInOperand(2u).AsString();
symbol_info.id = id;
symbol_info.type_id = 0u;
@@ -636,6 +655,34 @@
return SPV_SUCCESS;
}
+spv_result_t VerifyLimits(const MessageConsumer& consumer,
+ const opt::IRContext& linked_context) {
+ spv_position_t position = {};
+
+ const uint32_t max_id_bound = linked_context.module()->id_bound();
+ if (max_id_bound >= SPV_LIMIT_RESULT_ID_BOUND)
+ DiagnosticStream({0u, 0u, 4u}, consumer, "", SPV_WARNING)
+ << "The minimum limit of IDs, " << (SPV_LIMIT_RESULT_ID_BOUND - 1)
+ << ", was exceeded:"
+ << " " << max_id_bound << " is the current ID bound.\n"
+ << "The resulting module might not be supported by all "
+ "implementations.";
+
+ size_t num_global_values = 0u;
+ for (const auto& inst : linked_context.module()->types_values()) {
+ num_global_values += inst.opcode() == SpvOpVariable;
+ }
+ if (num_global_values >= SPV_LIMIT_GLOBAL_VARIABLES_MAX)
+ DiagnosticStream(position, consumer, "", SPV_WARNING)
+ << "The minimum limit of global values, "
+ << (SPV_LIMIT_GLOBAL_VARIABLES_MAX - 1) << ", was exceeded;"
+ << " " << num_global_values << " global values were found.\n"
+ << "The resulting module might not be supported by all "
+ "implementations.";
+
+ return SPV_SUCCESS;
+}
+
} // namespace
spv_result_t Link(const Context& context,
@@ -760,7 +807,11 @@
pass_res = manager.Run(&linked_context);
if (pass_res == opt::Pass::Status::Failure) return SPV_ERROR_INVALID_DATA;
- // Phase 11: Output the module
+ // Phase 11: Warn if SPIR-V limits were exceeded
+ res = VerifyLimits(consumer, linked_context);
+ if (res != SPV_SUCCESS) return res;
+
+ // Phase 12: Output the module
linked_context.module()->ToBinary(linked_binary, true);
return SPV_SUCCESS;
diff --git a/third_party/SPIRV-Tools/source/name_mapper.cpp b/third_party/SPIRV-Tools/source/name_mapper.cpp
index eb08f8f..3b31d33 100644
--- a/third_party/SPIRV-Tools/source/name_mapper.cpp
+++ b/third_party/SPIRV-Tools/source/name_mapper.cpp
@@ -22,10 +22,10 @@
#include <unordered_map>
#include <unordered_set>
-#include "spirv-tools/libspirv.h"
-
+#include "source/binary.h"
#include "source/latest_version_spirv_header.h"
#include "source/parsed_operand.h"
+#include "spirv-tools/libspirv.h"
namespace spvtools {
namespace {
@@ -172,7 +172,7 @@
const auto result_id = inst.result_id;
switch (inst.opcode) {
case SpvOpName:
- SaveName(inst.words[1], reinterpret_cast<const char*>(inst.words + 2));
+ SaveName(inst.words[1], spvDecodeLiteralStringOperand(inst, 1));
break;
case SpvOpDecorate:
// Decorations come after OpName. So OpName will take precedence over
@@ -274,9 +274,8 @@
SaveName(result_id, "Queue");
break;
case SpvOpTypeOpaque:
- SaveName(result_id,
- std::string("Opaque_") +
- Sanitize(reinterpret_cast<const char*>(inst.words + 2)));
+ SaveName(result_id, std::string("Opaque_") +
+ Sanitize(spvDecodeLiteralStringOperand(inst, 1)));
break;
case SpvOpTypePipeStorage:
SaveName(result_id, "PipeStorage");
diff --git a/third_party/SPIRV-Tools/source/opcode.cpp b/third_party/SPIRV-Tools/source/opcode.cpp
index c96cde8..c9c425d 100644
--- a/third_party/SPIRV-Tools/source/opcode.cpp
+++ b/third_party/SPIRV-Tools/source/opcode.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2015-2020 The Khronos Group Inc.
+// Copyright (c) 2015-2022 The Khronos Group Inc.
// Modifications Copyright (C) 2020 Advanced Micro Devices, Inc. All rights
// reserved.
//
@@ -40,12 +40,12 @@
static const spv_opcode_table_t kOpcodeTable = {ARRAY_SIZE(kOpcodeTableEntries),
kOpcodeTableEntries};
-// Represents a vendor tool entry in the SPIR-V XML Regsitry.
+// Represents a vendor tool entry in the SPIR-V XML Registry.
struct VendorTool {
uint32_t value;
const char* vendor;
const char* tool; // Might be empty string.
- const char* vendor_tool; // Combiantion of vendor and tool.
+ const char* vendor_tool; // Combination of vendor and tool.
};
const VendorTool vendor_tools[] = {
@@ -631,6 +631,7 @@
case SpvOpString:
case SpvOpLine:
case SpvOpNoLine:
+ case SpvOpModuleProcessed:
return true;
default:
return false;
diff --git a/third_party/SPIRV-Tools/source/opt/CMakeLists.txt b/third_party/SPIRV-Tools/source/opt/CMakeLists.txt
index 7d522fb..7508dc0 100644
--- a/third_party/SPIRV-Tools/source/opt/CMakeLists.txt
+++ b/third_party/SPIRV-Tools/source/opt/CMakeLists.txt
@@ -108,10 +108,11 @@
scalar_replacement_pass.h
set_spec_constant_default_value_pass.h
simplification_pass.h
+ spread_volatile_semantics.h
ssa_rewrite_pass.h
strength_reduction_pass.h
strip_debug_info_pass.h
- strip_reflect_info_pass.h
+ strip_nonsemantic_info_pass.h
struct_cfg_analysis.h
tree_iterator.h
type_manager.h
@@ -215,10 +216,11 @@
scalar_replacement_pass.cpp
set_spec_constant_default_value_pass.cpp
simplification_pass.cpp
+ spread_volatile_semantics.cpp
ssa_rewrite_pass.cpp
strength_reduction_pass.cpp
strip_debug_info_pass.cpp
- strip_reflect_info_pass.cpp
+ strip_nonsemantic_info_pass.cpp
struct_cfg_analysis.cpp
type_manager.cpp
types.cpp
diff --git a/third_party/SPIRV-Tools/source/opt/aggressive_dead_code_elim_pass.cpp b/third_party/SPIRV-Tools/source/opt/aggressive_dead_code_elim_pass.cpp
index c2ed2f8..9827c53 100644
--- a/third_party/SPIRV-Tools/source/opt/aggressive_dead_code_elim_pass.cpp
+++ b/third_party/SPIRV-Tools/source/opt/aggressive_dead_code_elim_pass.cpp
@@ -27,6 +27,7 @@
#include "source/opt/iterator.h"
#include "source/opt/reflect.h"
#include "source/spirv_constant.h"
+#include "source/util/string_utils.h"
namespace spvtools {
namespace opt {
@@ -146,8 +147,7 @@
bool AggressiveDCEPass::AllExtensionsSupported() const {
// If any extension not in allowlist, return false
for (auto& ei : get_module()->extensions()) {
- const char* extName =
- reinterpret_cast<const char*>(&ei.GetInOperand(0).words[0]);
+ const std::string extName = ei.GetInOperand(0).AsString();
if (extensions_allowlist_.find(extName) == extensions_allowlist_.end())
return false;
}
@@ -156,11 +156,9 @@
for (auto& inst : context()->module()->ext_inst_imports()) {
assert(inst.opcode() == SpvOpExtInstImport &&
"Expecting an import of an extension's instruction set.");
- const char* extension_name =
- reinterpret_cast<const char*>(&inst.GetInOperand(0).words[0]);
- if (0 == std::strncmp(extension_name, "NonSemantic.", 12) &&
- 0 != std::strncmp(extension_name, "NonSemantic.Shader.DebugInfo.100",
- 32)) {
+ const std::string extension_name = inst.GetInOperand(0).AsString();
+ if (spvtools::utils::starts_with(extension_name, "NonSemantic.") &&
+ extension_name != "NonSemantic.Shader.DebugInfo.100") {
return false;
}
}
diff --git a/third_party/SPIRV-Tools/source/opt/amd_ext_to_khr.cpp b/third_party/SPIRV-Tools/source/opt/amd_ext_to_khr.cpp
index d46d243..dd9bafd 100644
--- a/third_party/SPIRV-Tools/source/opt/amd_ext_to_khr.cpp
+++ b/third_party/SPIRV-Tools/source/opt/amd_ext_to_khr.cpp
@@ -935,8 +935,7 @@
std::vector<Instruction*> to_be_killed;
for (Instruction& inst : context()->module()->extensions()) {
if (inst.opcode() == SpvOpExtension) {
- if (ext_to_remove.count(reinterpret_cast<const char*>(
- &(inst.GetInOperand(0).words[0]))) != 0) {
+ if (ext_to_remove.count(inst.GetInOperand(0).AsString()) != 0) {
to_be_killed.push_back(&inst);
}
}
@@ -944,8 +943,7 @@
for (Instruction& inst : context()->ext_inst_imports()) {
if (inst.opcode() == SpvOpExtInstImport) {
- if (ext_to_remove.count(reinterpret_cast<const char*>(
- &(inst.GetInOperand(0).words[0]))) != 0) {
+ if (ext_to_remove.count(inst.GetInOperand(0).AsString()) != 0) {
to_be_killed.push_back(&inst);
}
}
diff --git a/third_party/SPIRV-Tools/source/opt/amd_ext_to_khr.h b/third_party/SPIRV-Tools/source/opt/amd_ext_to_khr.h
index fd3dab4..6a39d95 100644
--- a/third_party/SPIRV-Tools/source/opt/amd_ext_to_khr.h
+++ b/third_party/SPIRV-Tools/source/opt/amd_ext_to_khr.h
@@ -23,7 +23,7 @@
namespace opt {
// Replaces the extensions VK_AMD_shader_ballot, VK_AMD_gcn_shader, and
-// VK_AMD_shader_trinary_minmax with equivalant code using core instructions and
+// VK_AMD_shader_trinary_minmax with equivalent code using core instructions and
// capabilities.
class AmdExtensionToKhrPass : public Pass {
public:
diff --git a/third_party/SPIRV-Tools/source/opt/basic_block.h b/third_party/SPIRV-Tools/source/opt/basic_block.h
index 6741a50..dd3b2e2 100644
--- a/third_party/SPIRV-Tools/source/opt/basic_block.h
+++ b/third_party/SPIRV-Tools/source/opt/basic_block.h
@@ -83,7 +83,7 @@
const Instruction* GetMergeInst() const;
Instruction* GetMergeInst();
- // Returns the OpLoopMerge instruciton in this basic block, if it exists.
+ // Returns the OpLoopMerge instruction in this basic block, if it exists.
// Otherwise return null. May be used whenever tail() can be used.
const Instruction* GetLoopMergeInst() const;
Instruction* GetLoopMergeInst();
diff --git a/third_party/SPIRV-Tools/source/opt/cfg.h b/third_party/SPIRV-Tools/source/opt/cfg.h
index f280682..33412f1 100644
--- a/third_party/SPIRV-Tools/source/opt/cfg.h
+++ b/third_party/SPIRV-Tools/source/opt/cfg.h
@@ -30,7 +30,7 @@
public:
explicit CFG(Module* module);
- // Return the list of predecesors for basic block with label |blkid|.
+ // Return the list of predecessors for basic block with label |blkid|.
// TODO(dnovillo): Move this to BasicBlock.
const std::vector<uint32_t>& preds(uint32_t blk_id) const {
assert(label2preds_.count(blk_id));
diff --git a/third_party/SPIRV-Tools/source/opt/const_folding_rules.cpp b/third_party/SPIRV-Tools/source/opt/const_folding_rules.cpp
index a9830a2..249e11e 100644
--- a/third_party/SPIRV-Tools/source/opt/const_folding_rules.cpp
+++ b/third_party/SPIRV-Tools/source/opt/const_folding_rules.cpp
@@ -550,7 +550,7 @@
ConstantFoldingRule FoldFMul() { return FoldFPBinaryOp(FOLD_FPARITH_OP(*)); }
// Returns the constant that results from evaluating |numerator| / 0.0. Returns
-// |nullptr| if the result could not be evalutated.
+// |nullptr| if the result could not be evaluated.
const analysis::Constant* FoldFPScalarDivideByZero(
const analysis::Type* result_type, const analysis::Constant* numerator,
analysis::ConstantManager* const_mgr) {
@@ -1346,7 +1346,7 @@
FoldFPUnaryOp(FoldFTranscendentalUnary(std::log)));
#ifdef __ANDROID__
- // Android NDK r15c tageting ABI 15 doesn't have full support for C++11
+ // Android NDK r15c targeting ABI 15 doesn't have full support for C++11
// (no std::exp2/log2). ::exp2 is available from C99 but ::log2 isn't
// available up until ABI 18 so we use a shim
auto log2_shim = [](double v) -> double { return log(v) / log(2.0); };
diff --git a/third_party/SPIRV-Tools/source/opt/constants.cpp b/third_party/SPIRV-Tools/source/opt/constants.cpp
index d286cd2..bcff08c 100644
--- a/third_party/SPIRV-Tools/source/opt/constants.cpp
+++ b/third_party/SPIRV-Tools/source/opt/constants.cpp
@@ -158,6 +158,7 @@
std::vector<const Constant*> ConstantManager::GetOperandConstants(
const Instruction* inst) const {
std::vector<const Constant*> constants;
+ constants.reserve(inst->NumInOperands());
for (uint32_t i = 0; i < inst->NumInOperands(); i++) {
const Operand* operand = &inst->GetInOperand(i);
if (operand->type != SPV_OPERAND_TYPE_ID) {
diff --git a/third_party/SPIRV-Tools/source/opt/constants.h b/third_party/SPIRV-Tools/source/opt/constants.h
index 10f7bd6..c039ae0 100644
--- a/third_party/SPIRV-Tools/source/opt/constants.h
+++ b/third_party/SPIRV-Tools/source/opt/constants.h
@@ -541,7 +541,7 @@
// instruction at the end of the current module's types section.
//
// |type_id| is an optional argument for disambiguating equivalent types. If
- // |type_id| is specified, the contant returned will have that type id.
+ // |type_id| is specified, the constant returned will have that type id.
Instruction* GetDefiningInstruction(const Constant* c, uint32_t type_id = 0,
Module::inst_iterator* pos = nullptr);
diff --git a/third_party/SPIRV-Tools/source/opt/convert_to_half_pass.cpp b/third_party/SPIRV-Tools/source/opt/convert_to_half_pass.cpp
index b127eab..4086e31 100644
--- a/third_party/SPIRV-Tools/source/opt/convert_to_half_pass.cpp
+++ b/third_party/SPIRV-Tools/source/opt/convert_to_half_pass.cpp
@@ -181,7 +181,7 @@
uint32_t to_width) {
// Add converts of any float operands to to_width if they are of from_width.
// If converting to 16, change type of phi to float16 equivalent and remember
- // result id. Converts need to be added to preceeding blocks.
+ // result id. Converts need to be added to preceding blocks.
uint32_t ocnt = 0;
uint32_t* prev_idp;
bool modified = false;
diff --git a/third_party/SPIRV-Tools/source/opt/copy_prop_arrays.cpp b/third_party/SPIRV-Tools/source/opt/copy_prop_arrays.cpp
index 62ed5e7..321d496 100644
--- a/third_party/SPIRV-Tools/source/opt/copy_prop_arrays.cpp
+++ b/third_party/SPIRV-Tools/source/opt/copy_prop_arrays.cpp
@@ -745,11 +745,11 @@
context()->AnalyzeUses(use);
}
break;
+ case SpvOpDecorate:
+ // We treat an OpImageTexelPointer as a load. The result type should
+ // always have the Image storage class, and should not need to be
+ // updated.
case SpvOpImageTexelPointer:
- // We treat an OpImageTexelPointer as a load. The result type should
- // always have the Image storage class, and should not need to be
- // updated.
-
// Replace the actual use.
context()->ForgetUses(use);
use->SetOperand(index, {new_ptr_inst->result_id()});
diff --git a/third_party/SPIRV-Tools/source/opt/copy_prop_arrays.h b/third_party/SPIRV-Tools/source/opt/copy_prop_arrays.h
index f4314a7..46a508c 100644
--- a/third_party/SPIRV-Tools/source/opt/copy_prop_arrays.h
+++ b/third_party/SPIRV-Tools/source/opt/copy_prop_arrays.h
@@ -35,7 +35,7 @@
//
// The hard part is keeping all of the types correct. We do not want to
// have to do too large a search to update everything, which may not be
-// possible, do we give up if we see any instruction that might be hard to
+// possible, so we give up if we see any instruction that might be hard to
// update.
class CopyPropagateArrays : public MemPass {
diff --git a/third_party/SPIRV-Tools/source/opt/dead_branch_elim_pass.h b/third_party/SPIRV-Tools/source/opt/dead_branch_elim_pass.h
index 7841bc4..198bad2 100644
--- a/third_party/SPIRV-Tools/source/opt/dead_branch_elim_pass.h
+++ b/third_party/SPIRV-Tools/source/opt/dead_branch_elim_pass.h
@@ -98,7 +98,7 @@
// Fix phis in reachable blocks so that only live (or unremovable) incoming
// edges are present. If the block now only has a single live incoming edge,
// remove the phi and replace its uses with its data input. If the single
- // remaining incoming edge is from the phi itself, the the phi is in an
+ // remaining incoming edge is from the phi itself, the phi is in an
// unreachable single block loop. Either the block is dead and will be
// removed, or it's reachable from an unreachable continue target. In the
// latter case that continue target block will be collapsed into a block that
@@ -158,7 +158,7 @@
uint32_t cont_id, uint32_t header_id, uint32_t merge_id,
std::unordered_set<BasicBlock*>* blocks_with_back_edges);
- // Returns true if there is a brach to the merge node of the selection
+ // Returns true if there is a branch to the merge node of the selection
// construct |switch_header_id| that is inside a nested selection construct or
// in the header of the nested selection construct.
bool SwitchHasNestedBreak(uint32_t switch_header_id);
diff --git a/third_party/SPIRV-Tools/source/opt/debug_info_manager.cpp b/third_party/SPIRV-Tools/source/opt/debug_info_manager.cpp
index 060e0d9..c1df625 100644
--- a/third_party/SPIRV-Tools/source/opt/debug_info_manager.cpp
+++ b/third_party/SPIRV-Tools/source/opt/debug_info_manager.cpp
@@ -149,7 +149,7 @@
// Create new constant directly into global value area, bypassing the
// Constant manager. This is used when the DefUse or Constant managers
// are invalid and cannot be regenerated due to the module being in an
-// inconsistant state e.g. in the middle of significant modification
+// inconsistent state e.g. in the middle of significant modification
// such as inlining. Invalidate Constant and DefUse managers if used.
uint32_t AddNewConstInGlobals(IRContext* context, uint32_t const_value) {
uint32_t id = context->TakeNextId();
diff --git a/third_party/SPIRV-Tools/source/opt/def_use_manager.cpp b/third_party/SPIRV-Tools/source/opt/def_use_manager.cpp
index 394b9fa..e1e441e 100644
--- a/third_party/SPIRV-Tools/source/opt/def_use_manager.cpp
+++ b/third_party/SPIRV-Tools/source/opt/def_use_manager.cpp
@@ -13,16 +13,23 @@
// limitations under the License.
#include "source/opt/def_use_manager.h"
-
-#include <iostream>
-
-#include "source/opt/log.h"
-#include "source/opt/reflect.h"
+#include "source/util/make_unique.h"
namespace spvtools {
namespace opt {
namespace analysis {
+// Don't compact before we have a reasonable number of ids allocated (~32kb).
+static const size_t kCompactThresholdMinTotalIds = (8 * 1024);
+// Compact when fewer than this fraction of the storage is used (should be 2^n
+// for performance).
+static const size_t kCompactThresholdFractionFreeIds = 8;
+
+DefUseManager::DefUseManager() {
+ use_pool_ = MakeUnique<UseListPool>();
+ used_id_pool_ = MakeUnique<UsedIdListPool>();
+}
+
void DefUseManager::AnalyzeInstDef(Instruction* inst) {
const uint32_t def_id = inst->result_id();
if (def_id != 0) {
@@ -39,15 +46,15 @@
}
void DefUseManager::AnalyzeInstUse(Instruction* inst) {
+ // It might have existed before.
+ EraseUseRecordsOfOperandIds(inst);
+
// Create entry for the given instruction. Note that the instruction may
// not have any in-operands. In such cases, we still need a entry for those
// instructions so this manager knows it has seen the instruction later.
- auto* used_ids = &inst_to_used_ids_[inst];
- if (used_ids->size()) {
- EraseUseRecordsOfOperandIds(inst);
- used_ids = &inst_to_used_ids_[inst];
- }
- used_ids->clear(); // It might have existed before.
+ UsedIdList& used_ids =
+ inst_to_used_id_.insert({inst, UsedIdList(used_id_pool_.get())})
+ .first->second;
for (uint32_t i = 0; i < inst->NumOperands(); ++i) {
switch (inst->GetOperand(i).type) {
@@ -58,9 +65,18 @@
case SPV_OPERAND_TYPE_SCOPE_ID: {
uint32_t use_id = inst->GetSingleWordOperand(i);
Instruction* def = GetDef(use_id);
- if (!def) assert(false && "Definition is not registered.");
- id_to_users_.insert(UserEntry(def, inst));
- used_ids->push_back(use_id);
+ assert(def && "Definition is not registered.");
+
+ // Add to inst's use records
+ used_ids.push_back(use_id);
+
+ // Add to the users, taking care to avoid adding duplicates. We know
+ // the duplicate for this instruction will always be at the tail.
+ UseList& list = inst_to_users_.insert({def, UseList(use_pool_.get())})
+ .first->second;
+ if (list.empty() || list.back() != inst) {
+ list.push_back(inst);
+ }
} break;
default:
break;
@@ -99,23 +115,6 @@
return iter->second;
}
-DefUseManager::IdToUsersMap::const_iterator DefUseManager::UsersBegin(
- const Instruction* def) const {
- return id_to_users_.lower_bound(
- UserEntry(const_cast<Instruction*>(def), nullptr));
-}
-
-bool DefUseManager::UsersNotEnd(const IdToUsersMap::const_iterator& iter,
- const IdToUsersMap::const_iterator& cached_end,
- const Instruction* inst) const {
- return (iter != cached_end && iter->first == inst);
-}
-
-bool DefUseManager::UsersNotEnd(const IdToUsersMap::const_iterator& iter,
- const Instruction* inst) const {
- return UsersNotEnd(iter, id_to_users_.end(), inst);
-}
-
bool DefUseManager::WhileEachUser(
const Instruction* def, const std::function<bool(Instruction*)>& f) const {
// Ensure that |def| has been registered.
@@ -123,9 +122,11 @@
"Definition is not registered.");
if (!def->HasResultId()) return true;
- auto end = id_to_users_.end();
- for (auto iter = UsersBegin(def); UsersNotEnd(iter, end, def); ++iter) {
- if (!f(iter->second)) return false;
+ auto iter = inst_to_users_.find(def);
+ if (iter != inst_to_users_.end()) {
+ for (Instruction* user : iter->second) {
+ if (!f(user)) return false;
+ }
}
return true;
}
@@ -156,14 +157,15 @@
"Definition is not registered.");
if (!def->HasResultId()) return true;
- auto end = id_to_users_.end();
- for (auto iter = UsersBegin(def); UsersNotEnd(iter, end, def); ++iter) {
- Instruction* user = iter->second;
- for (uint32_t idx = 0; idx != user->NumOperands(); ++idx) {
- const Operand& op = user->GetOperand(idx);
- if (op.type != SPV_OPERAND_TYPE_RESULT_ID && spvIsIdType(op.type)) {
- if (def->result_id() == op.words[0]) {
- if (!f(user, idx)) return false;
+ auto iter = inst_to_users_.find(def);
+ if (iter != inst_to_users_.end()) {
+ for (Instruction* user : iter->second) {
+ for (uint32_t idx = 0; idx != user->NumOperands(); ++idx) {
+ const Operand& op = user->GetOperand(idx);
+ if (op.type != SPV_OPERAND_TYPE_RESULT_ID && spvIsIdType(op.type)) {
+ if (def->result_id() == op.words[0]) {
+ if (!f(user, idx)) return false;
+ }
}
}
}
@@ -235,17 +237,18 @@
}
void DefUseManager::ClearInst(Instruction* inst) {
- auto iter = inst_to_used_ids_.find(inst);
- if (iter != inst_to_used_ids_.end()) {
+ if (inst_to_used_id_.find(inst) != inst_to_used_id_.end()) {
EraseUseRecordsOfOperandIds(inst);
- if (inst->result_id() != 0) {
- // Remove all uses of this inst.
- auto users_begin = UsersBegin(inst);
- auto end = id_to_users_.end();
- auto new_end = users_begin;
- for (; UsersNotEnd(new_end, end, inst); ++new_end) {
+ uint32_t const result_id = inst->result_id();
+ if (result_id != 0) {
+ // For each using instruction, remove result_id from their used ids.
+ auto iter = inst_to_users_.find(inst);
+ if (iter != inst_to_users_.end()) {
+ for (Instruction* use : iter->second) {
+ inst_to_used_id_.at(use).remove_first(result_id);
+ }
+ inst_to_users_.erase(iter);
}
- id_to_users_.erase(users_begin, new_end);
id_to_def_.erase(inst->result_id());
}
}
@@ -254,59 +257,113 @@
void DefUseManager::EraseUseRecordsOfOperandIds(const Instruction* inst) {
// Go through all ids used by this instruction, remove this instruction's
// uses of them.
- auto iter = inst_to_used_ids_.find(inst);
- if (iter != inst_to_used_ids_.end()) {
- for (auto use_id : iter->second) {
- id_to_users_.erase(
- UserEntry(GetDef(use_id), const_cast<Instruction*>(inst)));
+ auto iter = inst_to_used_id_.find(inst);
+ if (iter != inst_to_used_id_.end()) {
+ const UsedIdList& used_ids = iter->second;
+ for (uint32_t def_id : used_ids) {
+ auto def_iter = inst_to_users_.find(GetDef(def_id));
+ if (def_iter != inst_to_users_.end()) {
+ def_iter->second.remove_first(const_cast<Instruction*>(inst));
+ }
}
- inst_to_used_ids_.erase(inst);
+ inst_to_used_id_.erase(inst);
+
+ // If we're using only a fraction of the space in used_ids_, compact storage
+ // to prevent memory usage from being unbounded.
+ if (used_id_pool_->total_nodes() > kCompactThresholdMinTotalIds &&
+ used_id_pool_->used_nodes() <
+ used_id_pool_->total_nodes() / kCompactThresholdFractionFreeIds) {
+ CompactStorage();
+ }
}
}
-bool operator==(const DefUseManager& lhs, const DefUseManager& rhs) {
+void DefUseManager::CompactStorage() {
+ CompactUseRecords();
+ CompactUsedIds();
+}
+
+void DefUseManager::CompactUseRecords() {
+ std::unique_ptr<UseListPool> new_pool = MakeUnique<UseListPool>();
+ for (auto& iter : inst_to_users_) {
+ iter.second.move_nodes(new_pool.get());
+ }
+ use_pool_ = std::move(new_pool);
+}
+
+void DefUseManager::CompactUsedIds() {
+ std::unique_ptr<UsedIdListPool> new_pool = MakeUnique<UsedIdListPool>();
+ for (auto& iter : inst_to_used_id_) {
+ iter.second.move_nodes(new_pool.get());
+ }
+ used_id_pool_ = std::move(new_pool);
+}
+
+bool CompareAndPrintDifferences(const DefUseManager& lhs,
+ const DefUseManager& rhs) {
+ bool same = true;
+
if (lhs.id_to_def_ != rhs.id_to_def_) {
for (auto p : lhs.id_to_def_) {
if (rhs.id_to_def_.find(p.first) == rhs.id_to_def_.end()) {
- return false;
+ printf("Diff in id_to_def: missing value in rhs\n");
}
}
for (auto p : rhs.id_to_def_) {
if (lhs.id_to_def_.find(p.first) == lhs.id_to_def_.end()) {
- return false;
+ printf("Diff in id_to_def: missing value in lhs\n");
}
}
- return false;
+ same = false;
}
- if (lhs.id_to_users_ != rhs.id_to_users_) {
- for (auto p : lhs.id_to_users_) {
- if (rhs.id_to_users_.count(p) == 0) {
- return false;
- }
+ for (const auto& l : lhs.inst_to_used_id_) {
+ std::set<uint32_t> ul, ur;
+ lhs.ForEachUse(l.first,
+ [&ul](Instruction*, uint32_t id) { ul.insert(id); });
+ rhs.ForEachUse(l.first,
+ [&ur](Instruction*, uint32_t id) { ur.insert(id); });
+ if (ul.size() != ur.size()) {
+ printf(
+ "Diff in inst_to_used_id_: different number of used ids (%zu != %zu)",
+ ul.size(), ur.size());
+ same = false;
+ } else if (ul != ur) {
+ printf("Diff in inst_to_used_id_: different used ids\n");
+ same = false;
}
- for (auto p : rhs.id_to_users_) {
- if (lhs.id_to_users_.count(p) == 0) {
- return false;
- }
+ }
+ for (const auto& r : rhs.inst_to_used_id_) {
+ auto iter_l = lhs.inst_to_used_id_.find(r.first);
+ if (r.second.empty() &&
+ !(iter_l == lhs.inst_to_used_id_.end() || iter_l->second.empty())) {
+ printf("Diff in inst_to_used_id_: unexpected instr in rhs\n");
+ same = false;
}
- return false;
}
- if (lhs.inst_to_used_ids_ != rhs.inst_to_used_ids_) {
- for (auto p : lhs.inst_to_used_ids_) {
- if (rhs.inst_to_used_ids_.count(p.first) == 0) {
- return false;
- }
+ for (const auto& l : lhs.inst_to_users_) {
+ std::set<Instruction*> ul, ur;
+ lhs.ForEachUser(l.first, [&ul](Instruction* use) { ul.insert(use); });
+ rhs.ForEachUser(l.first, [&ur](Instruction* use) { ur.insert(use); });
+ if (ul.size() != ur.size()) {
+ printf("Diff in inst_to_users_: different number of users (%zu != %zu)",
+ ul.size(), ur.size());
+ same = false;
+ } else if (ul != ur) {
+ printf("Diff in inst_to_users_: different users\n");
+ same = false;
}
- for (auto p : rhs.inst_to_used_ids_) {
- if (lhs.inst_to_used_ids_.count(p.first) == 0) {
- return false;
- }
- }
- return false;
}
- return true;
+ for (const auto& r : rhs.inst_to_users_) {
+ auto iter_l = lhs.inst_to_users_.find(r.first);
+ if (r.second.empty() &&
+ !(iter_l == lhs.inst_to_users_.end() || iter_l->second.empty())) {
+ printf("Diff in inst_to_users_: unexpected instr in rhs\n");
+ same = false;
+ }
+ }
+ return same;
}
} // namespace analysis
diff --git a/third_party/SPIRV-Tools/source/opt/def_use_manager.h b/third_party/SPIRV-Tools/source/opt/def_use_manager.h
index 0499e82..cf6cbdf 100644
--- a/third_party/SPIRV-Tools/source/opt/def_use_manager.h
+++ b/third_party/SPIRV-Tools/source/opt/def_use_manager.h
@@ -15,14 +15,13 @@
#ifndef SOURCE_OPT_DEF_USE_MANAGER_H_
#define SOURCE_OPT_DEF_USE_MANAGER_H_
-#include <list>
#include <set>
#include <unordered_map>
-#include <utility>
#include <vector>
#include "source/opt/instruction.h"
#include "source/opt/module.h"
+#include "source/util/pooled_linked_list.h"
#include "spirv-tools/libspirv.hpp"
namespace spvtools {
@@ -51,59 +50,16 @@
return lhs.operand_index < rhs.operand_index;
}
-// Definition and user pair.
-//
-// The first element of the pair is the definition.
-// The second element of the pair is the user.
-//
-// Definition should never be null. User can be null, however, such an entry
-// should be used only for searching (e.g. all users of a particular definition)
-// and never stored in a container.
-using UserEntry = std::pair<Instruction*, Instruction*>;
-
-// Orders UserEntry for use in associative containers (i.e. less than ordering).
-//
-// The definition of an UserEntry is treated as the major key and the users as
-// the minor key so that all the users of a particular definition are
-// consecutive in a container.
-//
-// A null user always compares less than a real user. This is done to provide
-// easy values to search for the beginning of the users of a particular
-// definition (i.e. using {def, nullptr}).
-struct UserEntryLess {
- bool operator()(const UserEntry& lhs, const UserEntry& rhs) const {
- // If lhs.first and rhs.first are both null, fall through to checking the
- // second entries.
- if (!lhs.first && rhs.first) return true;
- if (lhs.first && !rhs.first) return false;
-
- // If neither definition is null, then compare unique ids.
- if (lhs.first && rhs.first) {
- if (lhs.first->unique_id() < rhs.first->unique_id()) return true;
- if (rhs.first->unique_id() < lhs.first->unique_id()) return false;
- }
-
- // Return false on equality.
- if (!lhs.second && !rhs.second) return false;
- if (!lhs.second) return true;
- if (!rhs.second) return false;
-
- // If neither user is null then compare unique ids.
- return lhs.second->unique_id() < rhs.second->unique_id();
- }
-};
-
// A class for analyzing and managing defs and uses in an Module.
class DefUseManager {
public:
using IdToDefMap = std::unordered_map<uint32_t, Instruction*>;
- using IdToUsersMap = std::set<UserEntry, UserEntryLess>;
// Constructs a def-use manager from the given |module|. All internal messages
// will be communicated to the outside via the given message |consumer|. This
// instance only keeps a reference to the |consumer|, so the |consumer| should
// outlive this instance.
- DefUseManager(Module* module) { AnalyzeDefUse(module); }
+ DefUseManager(Module* module) : DefUseManager() { AnalyzeDefUse(module); }
DefUseManager(const DefUseManager&) = delete;
DefUseManager(DefUseManager&&) = delete;
@@ -191,14 +147,12 @@
// Returns the annotation instrunctions which are a direct use of the given
// |id|. This means when the decorations are applied through decoration
// group(s), this function will just return the OpGroupDecorate
- // instrcution(s) which refer to the given id as an operand. The OpDecorate
+ // instruction(s) which refer to the given id as an operand. The OpDecorate
// instructions which decorate the decoration group will not be returned.
std::vector<Instruction*> GetAnnotations(uint32_t id) const;
// Returns the map from ids to their def instructions.
const IdToDefMap& id_to_defs() const { return id_to_def_; }
- // Returns the map from instructions to their users.
- const IdToUsersMap& id_to_users() const { return id_to_users_; }
// Clear the internal def-use record of the given instruction |inst|. This
// method will update the use information of the operand ids of |inst|. The
@@ -210,43 +164,43 @@
// Erases the records that a given instruction uses its operand ids.
void EraseUseRecordsOfOperandIds(const Instruction* inst);
- friend bool operator==(const DefUseManager&, const DefUseManager&);
- friend bool operator!=(const DefUseManager& lhs, const DefUseManager& rhs) {
- return !(lhs == rhs);
- }
+ friend bool CompareAndPrintDifferences(const DefUseManager&,
+ const DefUseManager&);
- // If |inst| has not already been analysed, then analyses its defintion and
+ // If |inst| has not already been analysed, then analyses its definition and
// uses.
void UpdateDefUse(Instruction* inst);
+ // Compacts any internal storage to save memory.
+ void CompactStorage();
+
private:
- using InstToUsedIdsMap =
- std::unordered_map<const Instruction*, std::vector<uint32_t>>;
+ using UseList = spvtools::utils::PooledLinkedList<Instruction*>;
+ using UseListPool = spvtools::utils::PooledLinkedListNodes<Instruction*>;
+ // Stores linked lists of Instructions using a def.
+ using InstToUsersMap = std::unordered_map<const Instruction*, UseList>;
- // Returns the first location that {|def|, nullptr} could be inserted into the
- // users map without violating ordering.
- IdToUsersMap::const_iterator UsersBegin(const Instruction* def) const;
+ using UsedIdList = spvtools::utils::PooledLinkedList<uint32_t>;
+ using UsedIdListPool = spvtools::utils::PooledLinkedListNodes<uint32_t>;
+ // Stores mapping from instruction to their UsedIdRange.
+ using InstToUsedIdMap = std::unordered_map<const Instruction*, UsedIdList>;
- // Returns true if |iter| has not reached the end of |def|'s users.
- //
- // In the first version |iter| is compared against the end of the map for
- // validity before other checks. In the second version, |iter| is compared
- // against |cached_end| for validity before other checks. This allows caching
- // the map's end which is a performance improvement on some platforms.
- bool UsersNotEnd(const IdToUsersMap::const_iterator& iter,
- const Instruction* def) const;
- bool UsersNotEnd(const IdToUsersMap::const_iterator& iter,
- const IdToUsersMap::const_iterator& cached_end,
- const Instruction* def) const;
+ DefUseManager();
// Analyzes the defs and uses in the given |module| and populates data
// structures in this class. Does nothing if |module| is nullptr.
void AnalyzeDefUse(Module* module);
- IdToDefMap id_to_def_; // Mapping from ids to their definitions
- IdToUsersMap id_to_users_; // Mapping from ids to their users
- // Mapping from instructions to the ids used in the instruction.
- InstToUsedIdsMap inst_to_used_ids_;
+ // Removes unused entries in used_records_ and used_ids_.
+ void CompactUseRecords();
+ void CompactUsedIds();
+
+ IdToDefMap id_to_def_; // Mapping from ids to their definitions
+ InstToUsersMap inst_to_users_; // Map from def to uses.
+ std::unique_ptr<UseListPool> use_pool_;
+
+ std::unique_ptr<UsedIdListPool> used_id_pool_;
+ InstToUsedIdMap inst_to_used_id_; // Map from instruction to used ids.
};
} // namespace analysis
diff --git a/third_party/SPIRV-Tools/source/opt/desc_sroa.cpp b/third_party/SPIRV-Tools/source/opt/desc_sroa.cpp
index 7263c12..b130ca8 100644
--- a/third_party/SPIRV-Tools/source/opt/desc_sroa.cpp
+++ b/third_party/SPIRV-Tools/source/opt/desc_sroa.cpp
@@ -118,7 +118,7 @@
if (use->NumInOperands() == 2) {
// We are not indexing into the replacement variable. We can replaces the
- // access chain with the replacement varibale itself.
+ // access chain with the replacement variable itself.
context()->ReplaceAllUsesWith(use->result_id(), replacement_var);
context()->KillInst(use);
return true;
@@ -135,8 +135,8 @@
// Use the replacement variable as the base address.
new_operands.push_back({SPV_OPERAND_TYPE_ID, {replacement_var}});
- // Drop the first index because it is consumed by the replacment, and copy the
- // rest.
+ // Drop the first index because it is consumed by the replacement, and copy
+ // the rest.
for (uint32_t i = 4; i < use->NumOperands(); i++) {
new_operands.emplace_back(use->GetOperand(i));
}
diff --git a/third_party/SPIRV-Tools/source/opt/desc_sroa.h b/third_party/SPIRV-Tools/source/opt/desc_sroa.h
index 383d441..6a24fd8 100644
--- a/third_party/SPIRV-Tools/source/opt/desc_sroa.h
+++ b/third_party/SPIRV-Tools/source/opt/desc_sroa.h
@@ -132,7 +132,7 @@
// A map from an OpVariable instruction to the set of variables that will be
// used to replace it. The entry |replacement_variables_[var][i]| is the id of
- // a variable that will be used in the place of the the ith element of the
+ // a variable that will be used in the place of the ith element of the
// array |var|. If the entry is |0|, then the variable has not been
// created yet.
std::map<Instruction*, std::vector<uint32_t>> replacement_variables_;
diff --git a/third_party/SPIRV-Tools/source/opt/dominator_tree.cpp b/third_party/SPIRV-Tools/source/opt/dominator_tree.cpp
index 55287f4..d86de15 100644
--- a/third_party/SPIRV-Tools/source/opt/dominator_tree.cpp
+++ b/third_party/SPIRV-Tools/source/opt/dominator_tree.cpp
@@ -48,7 +48,7 @@
// BBType - BasicBlock type. Will either be BasicBlock or DominatorTreeNode
// SuccessorLambda - Lamdba matching the signature of 'const
// std::vector<BBType>*(const BBType *A)'. Will return a vector of the nodes
-// succeding BasicBlock A.
+// succeeding BasicBlock A.
// PostLambda - Lamdba matching the signature of 'void (const BBType*)' will be
// called on each node traversed AFTER their children.
// PreLambda - Lamdba matching the signature of 'void (const BBType*)' will be
@@ -69,7 +69,7 @@
// BBType - BasicBlock type. Will either be BasicBlock or DominatorTreeNode
// SuccessorLambda - Lamdba matching the signature of 'const
// std::vector<BBType>*(const BBType *A)'. Will return a vector of the nodes
-// succeding BasicBlock A.
+// succeeding BasicBlock A.
// PostLambda - Lamdba matching the signature of 'void (const BBType*)' will be
// called on each node traversed after their children.
template <typename BBType, typename SuccessorLambda, typename PostLambda>
diff --git a/third_party/SPIRV-Tools/source/opt/dominator_tree.h b/third_party/SPIRV-Tools/source/opt/dominator_tree.h
index 0024bc5..1674b22 100644
--- a/third_party/SPIRV-Tools/source/opt/dominator_tree.h
+++ b/third_party/SPIRV-Tools/source/opt/dominator_tree.h
@@ -278,7 +278,7 @@
private:
// Wrapper function which gets the list of pairs of each BasicBlocks to its
- // immediately dominating BasicBlock and stores the result in the the edges
+ // immediately dominating BasicBlock and stores the result in the edges
// parameter.
//
// The |edges| vector will contain the dominator tree as pairs of nodes.
diff --git a/third_party/SPIRV-Tools/source/opt/eliminate_dead_members_pass.cpp b/third_party/SPIRV-Tools/source/opt/eliminate_dead_members_pass.cpp
index a24ba8f..52aca52 100644
--- a/third_party/SPIRV-Tools/source/opt/eliminate_dead_members_pass.cpp
+++ b/third_party/SPIRV-Tools/source/opt/eliminate_dead_members_pass.cpp
@@ -38,7 +38,7 @@
}
void EliminateDeadMembersPass::FindLiveMembers() {
- // Until we have implemented the rewritting of OpSpecConsantOp instructions,
+ // Until we have implemented the rewriting of OpSpecConsantOp instructions,
// we have to mark them as fully used just to be safe.
for (auto& inst : get_module()->types_values()) {
if (inst.opcode() == SpvOpSpecConstantOp) {
@@ -570,7 +570,7 @@
Instruction* type_inst = get_def_use_mgr()->GetDef(type_id);
switch (type_inst->opcode()) {
case SpvOpTypeStruct:
- // The type will have already been rewriten, so use the new member
+ // The type will have already been rewritten, so use the new member
// index.
type_id = type_inst->GetSingleWordInOperand(new_member_idx);
break;
diff --git a/third_party/SPIRV-Tools/source/opt/feature_manager.cpp b/third_party/SPIRV-Tools/source/opt/feature_manager.cpp
index 39a4a34..a590271 100644
--- a/third_party/SPIRV-Tools/source/opt/feature_manager.cpp
+++ b/third_party/SPIRV-Tools/source/opt/feature_manager.cpp
@@ -39,8 +39,7 @@
assert(ext->opcode() == SpvOpExtension &&
"Expecting an extension instruction.");
- const std::string name =
- reinterpret_cast<const char*>(ext->GetInOperand(0u).words.data());
+ const std::string name = ext->GetInOperand(0u).AsString();
Extension extension;
if (GetExtensionFromString(name.c_str(), &extension)) {
extensions_.Add(extension);
diff --git a/third_party/SPIRV-Tools/source/opt/fold.cpp b/third_party/SPIRV-Tools/source/opt/fold.cpp
index 6550fb4..b903da6 100644
--- a/third_party/SPIRV-Tools/source/opt/fold.cpp
+++ b/third_party/SPIRV-Tools/source/opt/fold.cpp
@@ -540,7 +540,7 @@
// in 32-bit words here. The reason of not using FoldScalars() here
// is that we do not create temporary null constants as components
// when the vector operand is a NullConstant because Constant creation
- // may need extra checks for the validity and that is not manageed in
+ // may need extra checks for the validity and that is not managed in
// here.
if (const analysis::ScalarConstant* scalar_component =
vector_operand->GetComponents().at(d)->AsScalarConstant()) {
diff --git a/third_party/SPIRV-Tools/source/opt/fold_spec_constant_op_and_composite_pass.cpp b/third_party/SPIRV-Tools/source/opt/fold_spec_constant_op_and_composite_pass.cpp
index 8ab717e..85f11fd 100644
--- a/third_party/SPIRV-Tools/source/opt/fold_spec_constant_op_and_composite_pass.cpp
+++ b/third_party/SPIRV-Tools/source/opt/fold_spec_constant_op_and_composite_pass.cpp
@@ -115,7 +115,7 @@
Instruction* folded_inst = nullptr;
assert(inst->GetInOperand(0).type ==
SPV_OPERAND_TYPE_SPEC_CONSTANT_OP_NUMBER &&
- "The first in-operand of OpSpecContantOp instruction must be of "
+ "The first in-operand of OpSpecConstantOp instruction must be of "
"SPV_OPERAND_TYPE_SPEC_CONSTANT_OP_NUMBER type");
switch (static_cast<SpvOp>(inst->GetSingleWordInOperand(0))) {
diff --git a/third_party/SPIRV-Tools/source/opt/graphics_robust_access_pass.cpp b/third_party/SPIRV-Tools/source/opt/graphics_robust_access_pass.cpp
index 1b28f9b..4652d72 100644
--- a/third_party/SPIRV-Tools/source/opt/graphics_robust_access_pass.cpp
+++ b/third_party/SPIRV-Tools/source/opt/graphics_robust_access_pass.cpp
@@ -13,7 +13,7 @@
// limitations under the License.
// This pass injects code in a graphics shader to implement guarantees
-// satisfying Vulkan's robustBufferAcces rules. Robust access rules permit
+// satisfying Vulkan's robustBufferAccess rules. Robust access rules permit
// an out-of-bounds access to be redirected to an access of the same type
// (load, store, etc.) but within the same root object.
//
@@ -74,7 +74,7 @@
// Pointers are always (correctly) typed and so the address and number of
// consecutive locations are fully determined by the pointer.
//
-// - A pointer value orginates as one of few cases:
+// - A pointer value originates as one of few cases:
//
// - OpVariable for an interface object or an array of them: image,
// buffer (UBO or SSBO), sampler, sampled-image, push-constant, input
@@ -559,21 +559,17 @@
if (module_status_.glsl_insts_id == 0) {
// This string serves double-duty as raw data for a string and for a vector
// of 32-bit words
- const char glsl[] = "GLSL.std.450\0\0\0\0";
- const size_t glsl_str_byte_len = 16;
+ const char glsl[] = "GLSL.std.450";
// Use an existing import if we can.
for (auto& inst : context()->module()->ext_inst_imports()) {
- const auto& name_words = inst.GetInOperand(0).words;
- if (0 == std::strncmp(reinterpret_cast<const char*>(name_words.data()),
- glsl, glsl_str_byte_len)) {
+ if (inst.GetInOperand(0).AsString() == glsl) {
module_status_.glsl_insts_id = inst.result_id();
}
}
if (module_status_.glsl_insts_id == 0) {
// Make a new import instruction.
module_status_.glsl_insts_id = TakeNextId();
- std::vector<uint32_t> words(glsl_str_byte_len / sizeof(uint32_t));
- std::memcpy(words.data(), glsl, glsl_str_byte_len);
+ std::vector<uint32_t> words = spvtools::utils::MakeVector(glsl);
auto import_inst = MakeUnique<Instruction>(
context(), SpvOpExtInstImport, 0, module_status_.glsl_insts_id,
std::initializer_list<Operand>{
@@ -962,7 +958,7 @@
constant_mgr->GetDefiningInstruction(component_0)->result_id();
// If the image is a cube array, then the last component of the queried
- // size is the layer count. In the query, we have to accomodate folding
+ // size is the layer count. In the query, we have to accommodate folding
// in the face index ranging from 0 through 5. The inclusive upper bound
// on the third coordinate therefore is multiplied by 6.
auto* query_size_including_faces = query_size;
diff --git a/third_party/SPIRV-Tools/source/opt/graphics_robust_access_pass.h b/third_party/SPIRV-Tools/source/opt/graphics_robust_access_pass.h
index 6fc692c..8f4c9dc 100644
--- a/third_party/SPIRV-Tools/source/opt/graphics_robust_access_pass.h
+++ b/third_party/SPIRV-Tools/source/opt/graphics_robust_access_pass.h
@@ -111,7 +111,7 @@
Instruction* max, Instruction* where);
// Returns a new instruction which evaluates to the length the runtime array
- // referenced by the access chain at the specfied index. The instruction is
+ // referenced by the access chain at the specified index. The instruction is
// inserted before the access chain instruction. Returns a null pointer in
// some cases if assumptions are violated (rather than asserting out).
opt::Instruction* MakeRuntimeArrayLengthInst(Instruction* access_chain,
diff --git a/third_party/SPIRV-Tools/source/opt/inst_bindless_check_pass.h b/third_party/SPIRV-Tools/source/opt/inst_bindless_check_pass.h
index cd96180..e6e6ef4 100644
--- a/third_party/SPIRV-Tools/source/opt/inst_bindless_check_pass.h
+++ b/third_party/SPIRV-Tools/source/opt/inst_bindless_check_pass.h
@@ -147,11 +147,11 @@
uint32_t GenLastByteIdx(RefAnalysis* ref, InstructionBuilder* builder);
// Clone original image computation starting at |image_id| into |builder|.
- // This may generate more than one instruction if neccessary.
+ // This may generate more than one instruction if necessary.
uint32_t CloneOriginalImage(uint32_t image_id, InstructionBuilder* builder);
// Clone original original reference encapsulated by |ref| into |builder|.
- // This may generate more than one instruction if neccessary.
+ // This may generate more than one instruction if necessary.
uint32_t CloneOriginalReference(RefAnalysis* ref,
InstructionBuilder* builder);
diff --git a/third_party/SPIRV-Tools/source/opt/inst_debug_printf_pass.cpp b/third_party/SPIRV-Tools/source/opt/inst_debug_printf_pass.cpp
index c0e6bc3..4218138 100644
--- a/third_party/SPIRV-Tools/source/opt/inst_debug_printf_pass.cpp
+++ b/third_party/SPIRV-Tools/source/opt/inst_debug_printf_pass.cpp
@@ -16,6 +16,7 @@
#include "inst_debug_printf_pass.h"
+#include "source/util/string_utils.h"
#include "spirv/unified1/NonSemanticDebugPrintf.h"
namespace spvtools {
@@ -231,10 +232,8 @@
bool non_sem_set_seen = false;
for (auto c_itr = context()->module()->ext_inst_import_begin();
c_itr != context()->module()->ext_inst_import_end(); ++c_itr) {
- const char* set_name =
- reinterpret_cast<const char*>(&c_itr->GetInOperand(0).words[0]);
- const char* non_sem_str = "NonSemantic.";
- if (!strncmp(set_name, non_sem_str, strlen(non_sem_str))) {
+ const std::string set_name = c_itr->GetInOperand(0).AsString();
+ if (spvtools::utils::starts_with(set_name, "NonSemantic.")) {
non_sem_set_seen = true;
break;
}
@@ -242,9 +241,8 @@
if (!non_sem_set_seen) {
for (auto c_itr = context()->module()->extension_begin();
c_itr != context()->module()->extension_end(); ++c_itr) {
- const char* ext_name =
- reinterpret_cast<const char*>(&c_itr->GetInOperand(0).words[0]);
- if (!strcmp(ext_name, "SPV_KHR_non_semantic_info")) {
+ const std::string ext_name = c_itr->GetInOperand(0).AsString();
+ if (ext_name == "SPV_KHR_non_semantic_info") {
context()->KillInst(&*c_itr);
break;
}
diff --git a/third_party/SPIRV-Tools/source/opt/instruction.cpp b/third_party/SPIRV-Tools/source/opt/instruction.cpp
index 2461e41..418f121 100644
--- a/third_party/SPIRV-Tools/source/opt/instruction.cpp
+++ b/third_party/SPIRV-Tools/source/opt/instruction.cpp
@@ -76,10 +76,9 @@
dbg_scope_(kNoDebugScope, kNoInlinedAt) {
for (uint32_t i = 0; i < inst.num_operands; ++i) {
const auto& current_payload = inst.operands[i];
- std::vector<uint32_t> words(
- inst.words + current_payload.offset,
+ operands_.emplace_back(
+ current_payload.type, inst.words + current_payload.offset,
inst.words + current_payload.offset + current_payload.num_words);
- operands_.emplace_back(current_payload.type, std::move(words));
}
assert((!IsLineInst() || dbg_line.empty()) &&
"Op(No)Line attaching to Op(No)Line found");
@@ -96,10 +95,9 @@
dbg_scope_(dbg_scope) {
for (uint32_t i = 0; i < inst.num_operands; ++i) {
const auto& current_payload = inst.operands[i];
- std::vector<uint32_t> words(
- inst.words + current_payload.offset,
+ operands_.emplace_back(
+ current_payload.type, inst.words + current_payload.offset,
inst.words + current_payload.offset + current_payload.num_words);
- operands_.emplace_back(current_payload.type, std::move(words));
}
}
diff --git a/third_party/SPIRV-Tools/source/opt/instruction.h b/third_party/SPIRV-Tools/source/opt/instruction.h
index ce568f6..2163d99 100644
--- a/third_party/SPIRV-Tools/source/opt/instruction.h
+++ b/third_party/SPIRV-Tools/source/opt/instruction.h
@@ -24,6 +24,7 @@
#include "NonSemanticShaderDebugInfo100.h"
#include "OpenCLDebugInfo100.h"
+#include "source/binary.h"
#include "source/common_debug_info.h"
#include "source/latest_version_glsl_std_450_header.h"
#include "source/latest_version_spirv_header.h"
@@ -32,6 +33,7 @@
#include "source/opt/reflect.h"
#include "source/util/ilist_node.h"
#include "source/util/small_vector.h"
+#include "source/util/string_utils.h"
#include "spirv-tools/libspirv.h"
const uint32_t kNoDebugScope = 0;
@@ -82,21 +84,32 @@
Operand(spv_operand_type_t t, const OperandData& w) : type(t), words(w) {}
+ template <class InputIt>
+ Operand(spv_operand_type_t t, InputIt firstOperandData,
+ InputIt lastOperandData)
+ : type(t), words(firstOperandData, lastOperandData) {}
+
spv_operand_type_t type; // Type of this logical operand.
OperandData words; // Binary segments of this logical operand.
- // Returns a string operand as a C-style string.
- const char* AsCString() const {
- assert(type == SPV_OPERAND_TYPE_LITERAL_STRING);
- return reinterpret_cast<const char*>(words.data());
+ uint32_t AsId() const {
+ assert(spvIsIdType(type));
+ assert(words.size() == 1);
+ return words[0];
}
// Returns a string operand as a std::string.
- std::string AsString() const { return AsCString(); }
+ std::string AsString() const {
+ assert(type == SPV_OPERAND_TYPE_LITERAL_STRING);
+ return spvtools::utils::MakeString(words);
+ }
// Returns a literal integer operand as a uint64_t
uint64_t AsLiteralUint64() const {
- assert(type == SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER);
+ assert(type == SPV_OPERAND_TYPE_LITERAL_INTEGER ||
+ type == SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER ||
+ type == SPV_OPERAND_TYPE_OPTIONAL_LITERAL_INTEGER ||
+ type == SPV_OPERAND_TYPE_OPTIONAL_TYPED_LITERAL_INTEGER);
assert(1 <= words.size());
assert(words.size() <= 2);
uint64_t result = 0;
@@ -123,7 +136,7 @@
}
// This structure is used to represent a DebugScope instruction from
-// the OpenCL.100.DebugInfo extened instruction set. Note that we can
+// the OpenCL.100.DebugInfo extended instruction set. Note that we can
// ignore the result id of DebugScope instruction because it is not
// used for anything. We do not keep it to reduce the size of
// structure.
@@ -295,6 +308,7 @@
inline void SetInOperands(OperandList&& new_operands);
// Sets the result type id.
inline void SetResultType(uint32_t ty_id);
+ inline bool HasResultType() const { return has_type_id_; }
// Sets the result id
inline void SetResultId(uint32_t res_id);
inline bool HasResultId() const { return has_result_id_; }
diff --git a/third_party/SPIRV-Tools/source/opt/instrument_pass.h b/third_party/SPIRV-Tools/source/opt/instrument_pass.h
index 12b939d..90c1dd4 100644
--- a/third_party/SPIRV-Tools/source/opt/instrument_pass.h
+++ b/third_party/SPIRV-Tools/source/opt/instrument_pass.h
@@ -50,7 +50,7 @@
// A validation pass may read or write multiple buffers. All such buffers
// are located in a single debug descriptor set whose index is passed at the
// creation of the instrumentation pass. The bindings of the buffers used by
-// a validation pass are permanantly assigned and fixed and documented by
+// a validation pass are permanently assigned and fixed and documented by
// the kDebugOutput* static consts.
namespace spvtools {
@@ -179,8 +179,8 @@
// the error. Every stage will write a fixed number of words. Vertex shaders
// will write the Vertex and Instance ID. Fragment shaders will write
// FragCoord.xy. Compute shaders will write the GlobalInvocation ID.
- // The tesselation eval shader will write the Primitive ID and TessCoords.uv.
- // The tesselation control shader and geometry shader will write the
+ // The tessellation eval shader will write the Primitive ID and TessCoords.uv.
+ // The tessellation control shader and geometry shader will write the
// Primitive ID and Invocation ID.
//
// The Validation Error Code specifies the exact error which has occurred.
diff --git a/third_party/SPIRV-Tools/source/opt/ir_context.cpp b/third_party/SPIRV-Tools/source/opt/ir_context.cpp
index 612a831..5b0beeb 100644
--- a/third_party/SPIRV-Tools/source/opt/ir_context.cpp
+++ b/third_party/SPIRV-Tools/source/opt/ir_context.cpp
@@ -106,7 +106,7 @@
analyses_to_invalidate |= kAnalysisDebugInfo;
}
- // The dominator analysis hold the psuedo entry and exit nodes from the CFG.
+ // The dominator analysis hold the pseudo entry and exit nodes from the CFG.
// Also if the CFG change the dominators many changed as well, so the
// dominator analysis should be invalidated as well.
if (analyses_to_invalidate & kAnalysisCFG) {
@@ -317,7 +317,7 @@
#else
if (AreAnalysesValid(kAnalysisDefUse)) {
analysis::DefUseManager new_def_use(module());
- if (*get_def_use_mgr() != new_def_use) {
+ if (!CompareAndPrintDifferences(*get_def_use_mgr(), new_def_use)) {
return false;
}
}
@@ -623,9 +623,8 @@
void IRContext::AddCombinatorsForExtension(Instruction* extension) {
assert(extension->opcode() == SpvOpExtInstImport &&
"Expecting an import of an extension's instruction set.");
- const char* extension_name =
- reinterpret_cast<const char*>(&extension->GetInOperand(0).words[0]);
- if (!strcmp(extension_name, "GLSL.std.450")) {
+ const std::string extension_name = extension->GetInOperand(0).AsString();
+ if (extension_name == "GLSL.std.450") {
combinator_ops_[extension->result_id()] = {GLSLstd450Round,
GLSLstd450RoundEven,
GLSLstd450Trunc,
@@ -944,11 +943,11 @@
uint32_t line_number = 0;
uint32_t col_number = 0;
- char* source = nullptr;
+ std::string source;
if (line_inst != nullptr) {
Instruction* file_name =
get_def_use_mgr()->GetDef(line_inst->GetSingleWordInOperand(0));
- source = reinterpret_cast<char*>(&file_name->GetInOperand(0).words[0]);
+ source = file_name->GetInOperand(0).AsString();
// Get the line number and column number.
line_number = line_inst->GetSingleWordInOperand(1);
@@ -957,7 +956,7 @@
message +=
"\n " + inst->PrettyPrint(SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES);
- consumer()(SPV_MSG_ERROR, source, {line_number, col_number, 0},
+ consumer()(SPV_MSG_ERROR, source.c_str(), {line_number, col_number, 0},
message.c_str());
}
diff --git a/third_party/SPIRV-Tools/source/opt/ir_context.h b/third_party/SPIRV-Tools/source/opt/ir_context.h
index 6585347..274dd14 100644
--- a/third_party/SPIRV-Tools/source/opt/ir_context.h
+++ b/third_party/SPIRV-Tools/source/opt/ir_context.h
@@ -43,6 +43,7 @@
#include "source/opt/type_manager.h"
#include "source/opt/value_number_table.h"
#include "source/util/make_unique.h"
+#include "source/util/string_utils.h"
namespace spvtools {
namespace opt {
@@ -301,7 +302,7 @@
}
}
- // Returns a pointer the decoration manager. If the decoration manger is
+ // Returns a pointer the decoration manager. If the decoration manager is
// invalid, it is rebuilt first.
analysis::DecorationManager* get_decoration_mgr() {
if (!AreAnalysesValid(kAnalysisDecorations)) {
@@ -384,7 +385,7 @@
// Deletes the instruction defining the given |id|. Returns true on
// success, false if the given |id| is not defined at all. This method also
- // erases the name, decorations, and defintion of |id|.
+ // erases the name, decorations, and definition of |id|.
//
// Pointers and iterators pointing to the deleted instructions become invalid.
// However other pointers and iterators are still valid.
@@ -518,6 +519,18 @@
std::string message = "ID overflow. Try running compact-ids.";
consumer()(SPV_MSG_ERROR, "", {0, 0, 0}, message.c_str());
}
+#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+ // If TakeNextId returns 0, it is very likely that execution will
+ // subsequently fail. Such failures are false alarms from a fuzzing point
+ // of view: they are due to the fact that too many ids were used, rather
+ // than being due to an actual bug. Thus, during a fuzzing build, it is
+ // preferable to bail out when ID overflow occurs.
+ //
+ // A zero exit code is returned here because a non-zero code would cause
+ // ClusterFuzz/OSS-Fuzz to regard the termination as a crash, and spurious
+ // crash reports is what this guard aims to avoid.
+ exit(0);
+#endif
}
return next_id;
}
@@ -789,7 +802,7 @@
// iterators to traverse instructions.
std::unordered_map<uint32_t, Function*> id_to_func_;
- // A bitset indicating which analyes are currently valid.
+ // A bitset indicating which analyzes are currently valid.
Analysis valid_analyses_;
// Opcodes of shader capability core executable instructions
@@ -1020,11 +1033,7 @@
}
void IRContext::AddExtension(const std::string& ext_name) {
- const auto num_chars = ext_name.size();
- // Compute num words, accommodate the terminating null character.
- const auto num_words = (num_chars + 1 + 3) / 4;
- std::vector<uint32_t> ext_words(num_words, 0u);
- std::memcpy(ext_words.data(), ext_name.data(), num_chars);
+ std::vector<uint32_t> ext_words = spvtools::utils::MakeVector(ext_name);
AddExtension(std::unique_ptr<Instruction>(
new Instruction(this, SpvOpExtension, 0u, 0u,
{{SPV_OPERAND_TYPE_LITERAL_STRING, ext_words}})));
@@ -1041,11 +1050,7 @@
}
void IRContext::AddExtInstImport(const std::string& name) {
- const auto num_chars = name.size();
- // Compute num words, accommodate the terminating null character.
- const auto num_words = (num_chars + 1 + 3) / 4;
- std::vector<uint32_t> ext_words(num_words, 0u);
- std::memcpy(ext_words.data(), name.data(), num_chars);
+ std::vector<uint32_t> ext_words = spvtools::utils::MakeVector(name);
AddExtInstImport(std::unique_ptr<Instruction>(
new Instruction(this, SpvOpExtInstImport, 0u, TakeNextId(),
{{SPV_OPERAND_TYPE_LITERAL_STRING, ext_words}})));
diff --git a/third_party/SPIRV-Tools/source/opt/ir_loader.cpp b/third_party/SPIRV-Tools/source/opt/ir_loader.cpp
index a82b530..97db9d8 100644
--- a/third_party/SPIRV-Tools/source/opt/ir_loader.cpp
+++ b/third_party/SPIRV-Tools/source/opt/ir_loader.cpp
@@ -189,7 +189,8 @@
module_->SetMemoryModel(std::move(spv_inst));
} else if (opcode == SpvOpEntryPoint) {
module_->AddEntryPoint(std::move(spv_inst));
- } else if (opcode == SpvOpExecutionMode) {
+ } else if (opcode == SpvOpExecutionMode ||
+ opcode == SpvOpExecutionModeId) {
module_->AddExecutionMode(std::move(spv_inst));
} else if (IsDebug1Inst(opcode)) {
module_->AddDebug1Inst(std::move(spv_inst));
diff --git a/third_party/SPIRV-Tools/source/opt/local_access_chain_convert_pass.cpp b/third_party/SPIRV-Tools/source/opt/local_access_chain_convert_pass.cpp
index da9ba8c..d2059f5 100644
--- a/third_party/SPIRV-Tools/source/opt/local_access_chain_convert_pass.cpp
+++ b/third_party/SPIRV-Tools/source/opt/local_access_chain_convert_pass.cpp
@@ -19,6 +19,7 @@
#include "ir_builder.h"
#include "ir_context.h"
#include "iterator.h"
+#include "source/util/string_utils.h"
namespace spvtools {
namespace opt {
@@ -328,8 +329,7 @@
return false;
// If any extension not in allowlist, return false
for (auto& ei : get_module()->extensions()) {
- const char* extName =
- reinterpret_cast<const char*>(&ei.GetInOperand(0).words[0]);
+ const std::string extName = ei.GetInOperand(0).AsString();
if (extensions_allowlist_.find(extName) == extensions_allowlist_.end())
return false;
}
@@ -339,11 +339,9 @@
for (auto& inst : context()->module()->ext_inst_imports()) {
assert(inst.opcode() == SpvOpExtInstImport &&
"Expecting an import of an extension's instruction set.");
- const char* extension_name =
- reinterpret_cast<const char*>(&inst.GetInOperand(0).words[0]);
- if (0 == std::strncmp(extension_name, "NonSemantic.", 12) &&
- 0 != std::strncmp(extension_name, "NonSemantic.Shader.DebugInfo.100",
- 32)) {
+ const std::string extension_name = inst.GetInOperand(0).AsString();
+ if (spvtools::utils::starts_with(extension_name, "NonSemantic.") &&
+ extension_name != "NonSemantic.Shader.DebugInfo.100") {
return false;
}
}
diff --git a/third_party/SPIRV-Tools/source/opt/local_access_chain_convert_pass.h b/third_party/SPIRV-Tools/source/opt/local_access_chain_convert_pass.h
index 552062e..a51660f 100644
--- a/third_party/SPIRV-Tools/source/opt/local_access_chain_convert_pass.h
+++ b/third_party/SPIRV-Tools/source/opt/local_access_chain_convert_pass.h
@@ -81,7 +81,7 @@
std::vector<Operand>* in_opnds);
// Create a load/insert/store equivalent to a store of
- // |valId| through (constant index) access chaing |ptrInst|.
+ // |valId| through (constant index) access chain |ptrInst|.
// Append to |newInsts|. Returns true if successful.
bool GenAccessChainStoreReplacement(
const Instruction* ptrInst, uint32_t valId,
diff --git a/third_party/SPIRV-Tools/source/opt/local_single_block_elim_pass.cpp b/third_party/SPIRV-Tools/source/opt/local_single_block_elim_pass.cpp
index 5fd4f65..f48c56a 100644
--- a/third_party/SPIRV-Tools/source/opt/local_single_block_elim_pass.cpp
+++ b/third_party/SPIRV-Tools/source/opt/local_single_block_elim_pass.cpp
@@ -19,6 +19,7 @@
#include <vector>
#include "source/opt/iterator.h"
+#include "source/util/string_utils.h"
namespace spvtools {
namespace opt {
@@ -183,8 +184,7 @@
bool LocalSingleBlockLoadStoreElimPass::AllExtensionsSupported() const {
// If any extension not in allowlist, return false
for (auto& ei : get_module()->extensions()) {
- const char* extName =
- reinterpret_cast<const char*>(&ei.GetInOperand(0).words[0]);
+ const std::string extName = ei.GetInOperand(0).AsString();
if (extensions_allowlist_.find(extName) == extensions_allowlist_.end())
return false;
}
@@ -194,11 +194,9 @@
for (auto& inst : context()->module()->ext_inst_imports()) {
assert(inst.opcode() == SpvOpExtInstImport &&
"Expecting an import of an extension's instruction set.");
- const char* extension_name =
- reinterpret_cast<const char*>(&inst.GetInOperand(0).words[0]);
- if (0 == std::strncmp(extension_name, "NonSemantic.", 12) &&
- 0 != std::strncmp(extension_name, "NonSemantic.Shader.DebugInfo.100",
- 32)) {
+ const std::string extension_name = inst.GetInOperand(0).AsString();
+ if (spvtools::utils::starts_with(extension_name, "NonSemantic.") &&
+ extension_name != "NonSemantic.Shader.DebugInfo.100") {
return false;
}
}
diff --git a/third_party/SPIRV-Tools/source/opt/local_single_store_elim_pass.cpp b/third_party/SPIRV-Tools/source/opt/local_single_store_elim_pass.cpp
index 051bcad..123d03b 100644
--- a/third_party/SPIRV-Tools/source/opt/local_single_store_elim_pass.cpp
+++ b/third_party/SPIRV-Tools/source/opt/local_single_store_elim_pass.cpp
@@ -19,6 +19,7 @@
#include "source/cfa.h"
#include "source/latest_version_glsl_std_450_header.h"
#include "source/opt/iterator.h"
+#include "source/util/string_utils.h"
namespace spvtools {
namespace opt {
@@ -48,8 +49,7 @@
bool LocalSingleStoreElimPass::AllExtensionsSupported() const {
// If any extension not in allowlist, return false
for (auto& ei : get_module()->extensions()) {
- const char* extName =
- reinterpret_cast<const char*>(&ei.GetInOperand(0).words[0]);
+ const std::string extName = ei.GetInOperand(0).AsString();
if (extensions_allowlist_.find(extName) == extensions_allowlist_.end())
return false;
}
@@ -59,11 +59,9 @@
for (auto& inst : context()->module()->ext_inst_imports()) {
assert(inst.opcode() == SpvOpExtInstImport &&
"Expecting an import of an extension's instruction set.");
- const char* extension_name =
- reinterpret_cast<const char*>(&inst.GetInOperand(0).words[0]);
- if (0 == std::strncmp(extension_name, "NonSemantic.", 12) &&
- 0 != std::strncmp(extension_name, "NonSemantic.Shader.DebugInfo.100",
- 32)) {
+ const std::string extension_name = inst.GetInOperand(0).AsString();
+ if (spvtools::utils::starts_with(extension_name, "NonSemantic.") &&
+ extension_name != "NonSemantic.Shader.DebugInfo.100") {
return false;
}
}
diff --git a/third_party/SPIRV-Tools/source/opt/loop_descriptor.cpp b/third_party/SPIRV-Tools/source/opt/loop_descriptor.cpp
index b5b5630..9bc495e 100644
--- a/third_party/SPIRV-Tools/source/opt/loop_descriptor.cpp
+++ b/third_party/SPIRV-Tools/source/opt/loop_descriptor.cpp
@@ -719,7 +719,7 @@
step_value = -step_value;
}
- // Find the inital value of the loop and make sure it is a constant integer.
+ // Find the initial value of the loop and make sure it is a constant integer.
int64_t init_value = 0;
if (!GetInductionInitValue(induction, &init_value)) return false;
@@ -751,7 +751,7 @@
// We retrieve the number of iterations using the following formula, diff /
// |step_value| where diff is calculated differently according to the
// |condition| and uses the |condition_value| and |init_value|. If diff /
-// |step_value| is NOT cleanly divisable then we add one to the sum.
+// |step_value| is NOT cleanly divisible then we add one to the sum.
int64_t Loop::GetIterations(SpvOp condition, int64_t condition_value,
int64_t init_value, int64_t step_value) const {
int64_t diff = 0;
@@ -795,7 +795,7 @@
// If the condition is not met to begin with the loop will never iterate.
if (!(init_value >= condition_value)) return 0;
- // We subract one to make it the same as SpvOpGreaterThan as it is
+ // We subtract one to make it the same as SpvOpGreaterThan as it is
// functionally equivalent.
diff = init_value - (condition_value - 1);
diff --git a/third_party/SPIRV-Tools/source/opt/loop_descriptor.h b/third_party/SPIRV-Tools/source/opt/loop_descriptor.h
index 4b4f8bc..e88ff93 100644
--- a/third_party/SPIRV-Tools/source/opt/loop_descriptor.h
+++ b/third_party/SPIRV-Tools/source/opt/loop_descriptor.h
@@ -395,7 +395,7 @@
// Sets |merge| as the loop merge block. No checks are performed here.
inline void SetMergeBlockImpl(BasicBlock* merge) { loop_merge_ = merge; }
- // Each differnt loop |condition| affects how we calculate the number of
+ // Each different loop |condition| affects how we calculate the number of
// iterations using the |condition_value|, |init_value|, and |step_values| of
// the induction variable. This method will return the number of iterations in
// a loop with those values for a given |condition|.
diff --git a/third_party/SPIRV-Tools/source/opt/loop_fission.cpp b/third_party/SPIRV-Tools/source/opt/loop_fission.cpp
index 0678113..b4df8c6 100644
--- a/third_party/SPIRV-Tools/source/opt/loop_fission.cpp
+++ b/third_party/SPIRV-Tools/source/opt/loop_fission.cpp
@@ -29,7 +29,7 @@
// 2 - For each loop in the list, group each instruction into a set of related
// instructions by traversing each instructions users and operands recursively.
// We stop if we encounter an instruction we have seen before or an instruction
-// which we don't consider relevent (i.e OpLoopMerge). We then group these
+// which we don't consider relevant (i.e OpLoopMerge). We then group these
// groups into two different sets, one for the first loop and one for the
// second.
//
@@ -453,7 +453,7 @@
for (Function& f : *context()->module()) {
// We collect all the inner most loops in the function and run the loop
// splitting util on each. The reason we do this is to allow us to iterate
- // over each, as creating new loops will invalidate the the loop iterator.
+ // over each, as creating new loops will invalidate the loop iterator.
std::vector<Loop*> inner_most_loops{};
LoopDescriptor& loop_descriptor = *context()->GetLoopDescriptor(&f);
for (Loop& loop : loop_descriptor) {
diff --git a/third_party/SPIRV-Tools/source/opt/loop_fission.h b/third_party/SPIRV-Tools/source/opt/loop_fission.h
index e7a59c1..9bc12c0 100644
--- a/third_party/SPIRV-Tools/source/opt/loop_fission.h
+++ b/third_party/SPIRV-Tools/source/opt/loop_fission.h
@@ -33,7 +33,7 @@
class LoopFissionPass : public Pass {
public:
- // Fuction used to determine if a given loop should be split. Takes register
+ // Function used to determine if a given loop should be split. Takes register
// pressure region for that loop as a parameter and returns true if the loop
// should be split.
using FissionCriteriaFunction =
diff --git a/third_party/SPIRV-Tools/source/opt/loop_fusion.cpp b/third_party/SPIRV-Tools/source/opt/loop_fusion.cpp
index 07d171a..f3aab28 100644
--- a/third_party/SPIRV-Tools/source/opt/loop_fusion.cpp
+++ b/third_party/SPIRV-Tools/source/opt/loop_fusion.cpp
@@ -165,7 +165,7 @@
// Check adjacency, |loop_0_| should come just before |loop_1_|.
// There is always at least one block between loops, even if it's empty.
- // We'll check at most 2 preceeding blocks.
+ // We'll check at most 2 preceding blocks.
auto pre_header_1 = loop_1_->GetPreHeaderBlock();
@@ -712,7 +712,7 @@
ld->RemoveLoop(loop_1_);
- // Kill unnessecary instructions and remove all empty blocks.
+ // Kill unnecessary instructions and remove all empty blocks.
for (auto inst : instr_to_delete) {
context_->KillInst(inst);
}
diff --git a/third_party/SPIRV-Tools/source/opt/loop_fusion.h b/third_party/SPIRV-Tools/source/opt/loop_fusion.h
index d61d678..769da5f 100644
--- a/third_party/SPIRV-Tools/source/opt/loop_fusion.h
+++ b/third_party/SPIRV-Tools/source/opt/loop_fusion.h
@@ -40,7 +40,7 @@
// That means:
// * they both have one induction variable
// * they have the same upper and lower bounds
- // - same inital value
+ // - same initial value
// - same condition
// * they have the same update step
// * they are adjacent, with |loop_0| appearing before |loop_1|
diff --git a/third_party/SPIRV-Tools/source/opt/loop_fusion_pass.h b/third_party/SPIRV-Tools/source/opt/loop_fusion_pass.h
index 3a0be60..9d5b7cc 100644
--- a/third_party/SPIRV-Tools/source/opt/loop_fusion_pass.h
+++ b/third_party/SPIRV-Tools/source/opt/loop_fusion_pass.h
@@ -33,7 +33,7 @@
// Processes the given |module|. Returns Status::Failure if errors occur when
// processing. Returns the corresponding Status::Success if processing is
- // succesful to indicate whether changes have been made to the modue.
+ // successful to indicate whether changes have been made to the module.
Status Process() override;
private:
diff --git a/third_party/SPIRV-Tools/source/opt/loop_peeling.h b/third_party/SPIRV-Tools/source/opt/loop_peeling.h
index 413f896..2a55fe4 100644
--- a/third_party/SPIRV-Tools/source/opt/loop_peeling.h
+++ b/third_party/SPIRV-Tools/source/opt/loop_peeling.h
@@ -261,7 +261,7 @@
// Processes the given |module|. Returns Status::Failure if errors occur when
// processing. Returns the corresponding Status::Success if processing is
- // succesful to indicate whether changes have been made to the modue.
+ // successful to indicate whether changes have been made to the module.
Pass::Status Process() override;
private:
diff --git a/third_party/SPIRV-Tools/source/opt/loop_unroller.cpp b/third_party/SPIRV-Tools/source/opt/loop_unroller.cpp
index aff191f..28ff072 100644
--- a/third_party/SPIRV-Tools/source/opt/loop_unroller.cpp
+++ b/third_party/SPIRV-Tools/source/opt/loop_unroller.cpp
@@ -163,7 +163,7 @@
};
// This class implements the actual unrolling. It uses a LoopUnrollState to
-// maintain the state of the unrolling inbetween steps.
+// maintain the state of the unrolling in between steps.
class LoopUnrollerUtilsImpl {
public:
using BasicBlockListTy = std::vector<std::unique_ptr<BasicBlock>>;
@@ -209,7 +209,7 @@
// Add all blocks_to_add_ to function_ at the |insert_point|.
void AddBlocksToFunction(const BasicBlock* insert_point);
- // Duplicates the |old_loop|, cloning each body and remaping the ids without
+ // Duplicates the |old_loop|, cloning each body and remapping the ids without
// removing instructions or changing relative structure. Result will be stored
// in |new_loop|.
void DuplicateLoop(Loop* old_loop, Loop* new_loop);
@@ -241,7 +241,7 @@
// Remap all the in |basic_block| to new IDs and keep the mapping of new ids
// to old
// ids. |loop| is used to identify special loop blocks (header, continue,
- // ect).
+ // etc).
void AssignNewResultIds(BasicBlock* basic_block);
// Using the map built by AssignNewResultIds, replace the uses in |inst|
@@ -320,7 +320,7 @@
// and then be remapped at the end.
std::vector<Instruction*> loop_phi_instructions_;
- // The number of loop iterations that the loop would preform pre-unroll.
+ // The number of loop iterations that the loop would perform pre-unroll.
size_t number_of_loop_iterations_;
// The amount that the loop steps each iteration.
@@ -839,7 +839,7 @@
new_loop->SetMergeBlock(new_merge);
}
-// Whenever the utility copies a block it stores it in a tempory buffer, this
+// Whenever the utility copies a block it stores it in a temporary buffer, this
// function adds the buffer into the Function. The blocks will be inserted
// after the block |insert_point|.
void LoopUnrollerUtilsImpl::AddBlocksToFunction(
diff --git a/third_party/SPIRV-Tools/source/opt/loop_unswitch_pass.cpp b/third_party/SPIRV-Tools/source/opt/loop_unswitch_pass.cpp
index d805ecf..1ee7e5e 100644
--- a/third_party/SPIRV-Tools/source/opt/loop_unswitch_pass.cpp
+++ b/third_party/SPIRV-Tools/source/opt/loop_unswitch_pass.cpp
@@ -118,7 +118,7 @@
// Find a value that can be used to select the default path.
// If none are possible, then it will just use 0. The value does not matter
- // because this path will never be taken becaues the new switch outside of
+ // because this path will never be taken because the new switch outside of
// the loop cannot select this path either.
std::vector<uint32_t> existing_values;
for (uint32_t i = 2; i < switch_inst->NumInOperands(); i += 2) {
diff --git a/third_party/SPIRV-Tools/source/opt/loop_unswitch_pass.h b/third_party/SPIRV-Tools/source/opt/loop_unswitch_pass.h
index 3ecdd61..4f7295d 100644
--- a/third_party/SPIRV-Tools/source/opt/loop_unswitch_pass.h
+++ b/third_party/SPIRV-Tools/source/opt/loop_unswitch_pass.h
@@ -30,7 +30,7 @@
// Processes the given |module|. Returns Status::Failure if errors occur when
// processing. Returns the corresponding Status::Success if processing is
- // succesful to indicate whether changes have been made to the modue.
+ // successful to indicate whether changes have been made to the module.
Pass::Status Process() override;
private:
diff --git a/third_party/SPIRV-Tools/source/opt/loop_utils.h b/third_party/SPIRV-Tools/source/opt/loop_utils.h
index a4e6190..70060fc 100644
--- a/third_party/SPIRV-Tools/source/opt/loop_utils.h
+++ b/third_party/SPIRV-Tools/source/opt/loop_utils.h
@@ -123,7 +123,7 @@
// Clone the |loop_| and make the new loop branch to the second loop on exit.
Loop* CloneAndAttachLoopToHeader(LoopCloningResult* cloning_result);
- // Perfom a partial unroll of |loop| by given |factor|. This will copy the
+ // Perform a partial unroll of |loop| by given |factor|. This will copy the
// body of the loop |factor| times. So a |factor| of one would give a new loop
// with the original body plus one unrolled copy body.
bool PartiallyUnroll(size_t factor);
@@ -139,7 +139,7 @@
// 1. That the loop is in structured order.
// 2. That the continue block is a branch to the header.
// 3. That the only phi used in the loop is the induction variable.
- // TODO([email protected]): This is a temporary mesure, after the loop is
+ // TODO([email protected]): This is a temporary measure, after the loop is
// converted into LCSAA form and has a single entry and exit we can rewrite
// the other phis.
// 4. That this is an inner most loop, or that loops contained within this
diff --git a/third_party/SPIRV-Tools/source/opt/merge_return_pass.h b/third_party/SPIRV-Tools/source/opt/merge_return_pass.h
index 4096ce7..a35cf26 100644
--- a/third_party/SPIRV-Tools/source/opt/merge_return_pass.h
+++ b/third_party/SPIRV-Tools/source/opt/merge_return_pass.h
@@ -247,7 +247,7 @@
// Add new phi nodes for any id that no longer dominate all of it uses. A phi
// node is added to a block |bb| for an id if the id is defined between the
- // original immediate dominator of |bb| and its new immidiate dominator. It
+ // original immediate dominator of |bb| and its new immediate dominator. It
// is assumed that at this point there are no unreachable blocks in the
// control flow graph.
void AddNewPhiNodes();
@@ -273,7 +273,7 @@
void InsertAfterElement(BasicBlock* element, BasicBlock* new_element,
std::list<BasicBlock*>* list);
- // Creates a single case switch around all of the exectuable code of the
+ // Creates a single case switch around all of the executable code of the
// current function where the switch and case value are both zero and the
// default is the merge block. Returns after the switch is executed. Sets
// |final_return_block_|.
diff --git a/third_party/SPIRV-Tools/source/opt/module.cpp b/third_party/SPIRV-Tools/source/opt/module.cpp
index f97defb..5983abb 100644
--- a/third_party/SPIRV-Tools/source/opt/module.cpp
+++ b/third_party/SPIRV-Tools/source/opt/module.cpp
@@ -139,7 +139,7 @@
// TODO(antiagainst): should we change the generator number?
binary->push_back(header_.generator);
binary->push_back(header_.bound);
- binary->push_back(header_.reserved);
+ binary->push_back(header_.schema);
size_t bound_idx = binary->size() - 2;
DebugScope last_scope(kNoDebugScope, kNoInlinedAt);
@@ -260,9 +260,7 @@
uint32_t Module::GetExtInstImportId(const char* extstr) {
for (auto& ei : ext_inst_imports_)
- if (!strcmp(extstr,
- reinterpret_cast<const char*>(&(ei.GetInOperand(0).words[0]))))
- return ei.result_id();
+ if (!ei.GetInOperand(0).AsString().compare(extstr)) return ei.result_id();
return 0;
}
diff --git a/third_party/SPIRV-Tools/source/opt/module.h b/third_party/SPIRV-Tools/source/opt/module.h
index 0360b7d..230be70 100644
--- a/third_party/SPIRV-Tools/source/opt/module.h
+++ b/third_party/SPIRV-Tools/source/opt/module.h
@@ -36,7 +36,7 @@
uint32_t version;
uint32_t generator;
uint32_t bound;
- uint32_t reserved;
+ uint32_t schema;
};
// A SPIR-V module. It contains all the information for a SPIR-V module and
@@ -61,7 +61,7 @@
}
// Returns the Id bound.
- uint32_t IdBound() { return header_.bound; }
+ uint32_t IdBound() const { return header_.bound; }
// Returns the current Id bound and increases it to the next available value.
// If the id bound has already reached its maximum value, then 0 is returned.
@@ -141,6 +141,8 @@
inline uint32_t id_bound() const { return header_.bound; }
inline uint32_t version() const { return header_.version; }
+ inline uint32_t generator() const { return header_.generator; }
+ inline uint32_t schema() const { return header_.schema; }
inline void set_version(uint32_t v) { header_.version = v; }
diff --git a/third_party/SPIRV-Tools/source/opt/optimizer.cpp b/third_party/SPIRV-Tools/source/opt/optimizer.cpp
index e74db26..330093e 100644
--- a/third_party/SPIRV-Tools/source/opt/optimizer.cpp
+++ b/third_party/SPIRV-Tools/source/opt/optimizer.cpp
@@ -288,6 +288,8 @@
RegisterPass(CreateStripDebugInfoPass());
} else if (pass_name == "strip-reflect") {
RegisterPass(CreateStripReflectInfoPass());
+ } else if (pass_name == "strip-nonsemantic") {
+ RegisterPass(CreateStripNonSemanticInfoPass());
} else if (pass_name == "set-spec-const-default-value") {
if (pass_args.size() > 0) {
auto spec_ids_vals =
@@ -322,6 +324,8 @@
RegisterPass(CreateLocalAccessChainConvertPass());
} else if (pass_name == "replace-desc-array-access-using-var-index") {
RegisterPass(CreateReplaceDescArrayAccessUsingVarIndexPass());
+ } else if (pass_name == "spread-volatile-semantics") {
+ RegisterPass(CreateSpreadVolatileSemanticsPass());
} else if (pass_name == "descriptor-scalar-replacement") {
RegisterPass(CreateDescriptorScalarReplacementPass());
} else if (pass_name == "eliminate-dead-code-aggressive") {
@@ -653,8 +657,12 @@
}
Optimizer::PassToken CreateStripReflectInfoPass() {
+ return CreateStripNonSemanticInfoPass();
+}
+
+Optimizer::PassToken CreateStripNonSemanticInfoPass() {
return MakeUnique<Optimizer::PassToken::Impl>(
- MakeUnique<opt::StripReflectInfoPass>());
+ MakeUnique<opt::StripNonSemanticInfoPass>());
}
Optimizer::PassToken CreateEliminateDeadFunctionsPass() {
@@ -764,6 +772,11 @@
MakeUnique<opt::SSARewritePass>());
}
+Optimizer::PassToken CreateAggressiveDCEPass() {
+ return MakeUnique<Optimizer::PassToken::Impl>(
+ MakeUnique<opt::AggressiveDCEPass>(false));
+}
+
Optimizer::PassToken CreateAggressiveDCEPass(bool preserve_interface) {
return MakeUnique<Optimizer::PassToken::Impl>(
MakeUnique<opt::AggressiveDCEPass>(preserve_interface));
@@ -965,6 +978,11 @@
MakeUnique<opt::ReplaceDescArrayAccessUsingVarIndex>());
}
+Optimizer::PassToken CreateSpreadVolatileSemanticsPass() {
+ return MakeUnique<Optimizer::PassToken::Impl>(
+ MakeUnique<opt::SpreadVolatileSemantics>());
+}
+
Optimizer::PassToken CreateDescriptorScalarReplacementPass() {
return MakeUnique<Optimizer::PassToken::Impl>(
MakeUnique<opt::DescriptorScalarReplacement>());
diff --git a/third_party/SPIRV-Tools/source/opt/pass.h b/third_party/SPIRV-Tools/source/opt/pass.h
index a8c9c4b..4a8ea67 100644
--- a/third_party/SPIRV-Tools/source/opt/pass.h
+++ b/third_party/SPIRV-Tools/source/opt/pass.h
@@ -129,7 +129,7 @@
// Processes the given |module|. Returns Status::Failure if errors occur when
// processing. Returns the corresponding Status::Success if processing is
- // succesful to indicate whether changes are made to the module.
+ // successful to indicate whether changes are made to the module.
virtual Status Process() = 0;
// Return the next available SSA id and increment it.
diff --git a/third_party/SPIRV-Tools/source/opt/pass_manager.cpp b/third_party/SPIRV-Tools/source/opt/pass_manager.cpp
index be53d34..a73ff7c 100644
--- a/third_party/SPIRV-Tools/source/opt/pass_manager.cpp
+++ b/third_party/SPIRV-Tools/source/opt/pass_manager.cpp
@@ -35,10 +35,18 @@
if (print_all_stream_) {
std::vector<uint32_t> binary;
context->module()->ToBinary(&binary, false);
- SpirvTools t(SPV_ENV_UNIVERSAL_1_2);
+ SpirvTools t(target_env_);
+ t.SetMessageConsumer(consumer());
std::string disassembly;
- t.Disassemble(binary, &disassembly, 0);
- *print_all_stream_ << preamble << (pass ? pass->name() : "") << "\n"
+ std::string pass_name = (pass ? pass->name() : "");
+ if (!t.Disassemble(binary, &disassembly, 0)) {
+ std::string msg = "Disassembly failed before pass ";
+ msg += pass_name + "\n";
+ spv_position_t null_pos{0, 0, 0};
+ consumer()(SPV_MSG_WARNING, "", null_pos, msg.c_str());
+ return;
+ }
+ *print_all_stream_ << preamble << pass_name << "\n"
<< disassembly << std::endl;
}
};
diff --git a/third_party/SPIRV-Tools/source/opt/pass_manager.h b/third_party/SPIRV-Tools/source/opt/pass_manager.h
index 9686ddd..11961a3 100644
--- a/third_party/SPIRV-Tools/source/opt/pass_manager.h
+++ b/third_party/SPIRV-Tools/source/opt/pass_manager.h
@@ -54,7 +54,7 @@
// Adds an externally constructed pass.
void AddPass(std::unique_ptr<Pass> pass);
// Uses the argument |args| to construct a pass instance of type |T|, and adds
- // the pass instance to this pass manger. The pass added will use this pass
+ // the pass instance to this pass manager. The pass added will use this pass
// manager's message consumer.
template <typename T, typename... Args>
void AddPass(Args&&... args);
@@ -70,7 +70,7 @@
// Runs all passes on the given |module|. Returns Status::Failure if errors
// occur when processing using one of the registered passes. All passes
// registered after the error-reporting pass will be skipped. Returns the
- // corresponding Status::Success if processing is succesful to indicate
+ // corresponding Status::Success if processing is successful to indicate
// whether changes are made to the module.
//
// After running all the passes, they are removed from the list.
diff --git a/third_party/SPIRV-Tools/source/opt/passes.h b/third_party/SPIRV-Tools/source/opt/passes.h
index f3c30d5..d51c306 100644
--- a/third_party/SPIRV-Tools/source/opt/passes.h
+++ b/third_party/SPIRV-Tools/source/opt/passes.h
@@ -71,10 +71,11 @@
#include "source/opt/scalar_replacement_pass.h"
#include "source/opt/set_spec_constant_default_value_pass.h"
#include "source/opt/simplification_pass.h"
+#include "source/opt/spread_volatile_semantics.h"
#include "source/opt/ssa_rewrite_pass.h"
#include "source/opt/strength_reduction_pass.h"
#include "source/opt/strip_debug_info_pass.h"
-#include "source/opt/strip_reflect_info_pass.h"
+#include "source/opt/strip_nonsemantic_info_pass.h"
#include "source/opt/unify_const_pass.h"
#include "source/opt/upgrade_memory_model.h"
#include "source/opt/vector_dce.h"
diff --git a/third_party/SPIRV-Tools/source/opt/private_to_local_pass.h b/third_party/SPIRV-Tools/source/opt/private_to_local_pass.h
index c6127d6..e96a965 100644
--- a/third_party/SPIRV-Tools/source/opt/private_to_local_pass.h
+++ b/third_party/SPIRV-Tools/source/opt/private_to_local_pass.h
@@ -44,7 +44,7 @@
// class of |function|. Returns false if the variable could not be moved.
bool MoveVariable(Instruction* variable, Function* function);
- // |inst| is an instruction declaring a varible. If that variable is
+ // |inst| is an instruction declaring a variable. If that variable is
// referenced in a single function and all of uses are valid as defined by
// |IsValidUse|, then that function is returned. Otherwise, the return
// value is |nullptr|.
diff --git a/third_party/SPIRV-Tools/source/opt/redundancy_elimination.h b/third_party/SPIRV-Tools/source/opt/redundancy_elimination.h
index 91809b5..40451f4 100644
--- a/third_party/SPIRV-Tools/source/opt/redundancy_elimination.h
+++ b/third_party/SPIRV-Tools/source/opt/redundancy_elimination.h
@@ -41,7 +41,7 @@
// in the function containing |bb|.
//
// |value_to_ids| is a map from value number to ids. If {vn, id} is in
- // |value_to_ids| then vn is the value number of id, and the defintion of id
+ // |value_to_ids| then vn is the value number of id, and the definition of id
// dominates |bb|.
//
// Returns true if at least one instruction is deleted.
diff --git a/third_party/SPIRV-Tools/source/opt/register_pressure.cpp b/third_party/SPIRV-Tools/source/opt/register_pressure.cpp
index 5750c6d..1ad3373 100644
--- a/third_party/SPIRV-Tools/source/opt/register_pressure.cpp
+++ b/third_party/SPIRV-Tools/source/opt/register_pressure.cpp
@@ -378,7 +378,7 @@
// The loop fusion is injecting the l1 before the l2, the latch of l1 will be
// connected to the header of l2.
// To compute the register usage, we inject the loop live-in (union of l1 and
- // l2 live-in header blocks) into the the live in/out of each basic block of
+ // l2 live-in header blocks) into the live in/out of each basic block of
// l1 to get the peak register usage. We then repeat the operation to for l2
// basic blocks but in this case we inject the live-out of the latch of l1.
auto live_loop = MakeFilterIteratorRange(
diff --git a/third_party/SPIRV-Tools/source/opt/remove_duplicates_pass.cpp b/third_party/SPIRV-Tools/source/opt/remove_duplicates_pass.cpp
index 0e65cc8..1ed8e2a 100644
--- a/third_party/SPIRV-Tools/source/opt/remove_duplicates_pass.cpp
+++ b/third_party/SPIRV-Tools/source/opt/remove_duplicates_pass.cpp
@@ -72,9 +72,8 @@
std::unordered_map<std::string, SpvId> ext_inst_imports;
for (auto* i = &*context()->ext_inst_import_begin(); i;) {
- auto res = ext_inst_imports.emplace(
- reinterpret_cast<const char*>(i->GetInOperand(0u).words.data()),
- i->result_id());
+ auto res = ext_inst_imports.emplace(i->GetInOperand(0u).AsString(),
+ i->result_id());
if (res.second) {
// Never seen before, keep it.
i = i->NextNode();
diff --git a/third_party/SPIRV-Tools/source/opt/replace_desc_array_access_using_var_index.cpp b/third_party/SPIRV-Tools/source/opt/replace_desc_array_access_using_var_index.cpp
index 1082e67..4cadf60 100644
--- a/third_party/SPIRV-Tools/source/opt/replace_desc_array_access_using_var_index.cpp
+++ b/third_party/SPIRV-Tools/source/opt/replace_desc_array_access_using_var_index.cpp
@@ -253,8 +253,12 @@
Instruction* access_chain_final_user, Instruction* access_chain,
uint32_t number_of_elements,
const std::deque<Instruction*>& insts_to_be_cloned) const {
- // Create merge block and add terminator
auto* block = context()->get_instr_block(access_chain_final_user);
+ // If the instruction does not belong to a block (i.e. in the case of
+ // OpDecorate), no replacement is needed.
+ if (!block) return;
+
+ // Create merge block and add terminator
auto* merge_block = SeparateInstructionsIntoNewBlock(
block, access_chain_final_user->NextNode());
diff --git a/third_party/SPIRV-Tools/source/opt/replace_desc_array_access_using_var_index.h b/third_party/SPIRV-Tools/source/opt/replace_desc_array_access_using_var_index.h
index e18222c..0c97f7e 100644
--- a/third_party/SPIRV-Tools/source/opt/replace_desc_array_access_using_var_index.h
+++ b/third_party/SPIRV-Tools/source/opt/replace_desc_array_access_using_var_index.h
@@ -47,7 +47,7 @@
}
private:
- // Replaces all acceses to |var| using variable indices with constant
+ // Replaces all accesses to |var| using variable indices with constant
// elements of the array |var|. Creates switch-case statements to determine
// the value of the variable index for all the possible cases. Returns
// whether replacement is done or not.
@@ -170,7 +170,7 @@
// Creates and adds an OpSwitch used for the selection of OpAccessChain whose
// first Indexes operand is |access_chain_index_var_id|. The OpSwitch will be
// added at the end of |parent_block|. It will jump to |default_id| for the
- // default case and jumps to one of case blocks whoes ids are |case_block_ids|
+ // default case and jumps to one of case blocks whose ids are |case_block_ids|
// if |access_chain_index_var_id| matches the case number. |merge_id| is the
// merge block id.
void AddSwitchForAccessChain(
diff --git a/third_party/SPIRV-Tools/source/opt/replace_invalid_opc.cpp b/third_party/SPIRV-Tools/source/opt/replace_invalid_opc.cpp
index e3b9d3e..1dcd06f 100644
--- a/third_party/SPIRV-Tools/source/opt/replace_invalid_opc.cpp
+++ b/third_party/SPIRV-Tools/source/opt/replace_invalid_opc.cpp
@@ -112,8 +112,7 @@
}
Instruction* file_name =
context()->get_def_use_mgr()->GetDef(file_name_id);
- const char* source = reinterpret_cast<const char*>(
- &file_name->GetInOperand(0).words[0]);
+ const std::string source = file_name->GetInOperand(0).AsString();
// Get the line number and column number.
uint32_t line_number =
@@ -121,7 +120,7 @@
uint32_t col_number = last_line_dbg_inst->GetSingleWordInOperand(2);
// Replace the instruction.
- ReplaceInstruction(inst, source, line_number, col_number);
+ ReplaceInstruction(inst, source.c_str(), line_number, col_number);
}
}
},
diff --git a/third_party/SPIRV-Tools/source/opt/scalar_analysis.cpp b/third_party/SPIRV-Tools/source/opt/scalar_analysis.cpp
index 38555e6..2b0a824 100644
--- a/third_party/SPIRV-Tools/source/opt/scalar_analysis.cpp
+++ b/third_party/SPIRV-Tools/source/opt/scalar_analysis.cpp
@@ -581,7 +581,7 @@
// Implements the hashing of SENodes.
size_t SENodeHash::operator()(const SENode* node) const {
- // Concatinate the terms into a string which we can hash.
+ // Concatenate the terms into a string which we can hash.
std::u32string hash_string{};
// Hashing the type as a string is safer than hashing the enum as the enum is
diff --git a/third_party/SPIRV-Tools/source/opt/scalar_analysis_nodes.h b/third_party/SPIRV-Tools/source/opt/scalar_analysis_nodes.h
index b0e3fef..91ce446 100644
--- a/third_party/SPIRV-Tools/source/opt/scalar_analysis_nodes.h
+++ b/third_party/SPIRV-Tools/source/opt/scalar_analysis_nodes.h
@@ -167,7 +167,7 @@
const ChildContainerType& GetChildren() const { return children_; }
ChildContainerType& GetChildren() { return children_; }
- // Return true if this node is a cant compute node.
+ // Return true if this node is a can't compute node.
bool IsCantCompute() const { return GetType() == CanNotCompute; }
// Implements a casting method for each type.
diff --git a/third_party/SPIRV-Tools/source/opt/scalar_analysis_simplification.cpp b/third_party/SPIRV-Tools/source/opt/scalar_analysis_simplification.cpp
index 52f2d6a..3c1ecc0 100644
--- a/third_party/SPIRV-Tools/source/opt/scalar_analysis_simplification.cpp
+++ b/third_party/SPIRV-Tools/source/opt/scalar_analysis_simplification.cpp
@@ -88,7 +88,7 @@
private:
// Recursively descend through the graph to build up the accumulator objects
- // which are used to flatten the graph. |child| is the node currenty being
+ // which are used to flatten the graph. |child| is the node currently being
// traversed and the |negation| flag is used to signify that this operation
// was preceded by a unary negative operation and as such the result should be
// negated.
@@ -134,7 +134,7 @@
// offset.
SENode* EliminateZeroCoefficientRecurrents(SENode* node);
- // A reference the the analysis which requested the simplification.
+ // A reference the analysis which requested the simplification.
ScalarEvolutionAnalysis& analysis_;
// The node being simplified.
diff --git a/third_party/SPIRV-Tools/source/opt/scalar_replacement_pass.cpp b/third_party/SPIRV-Tools/source/opt/scalar_replacement_pass.cpp
index 4d6a7aa..e27c828 100644
--- a/third_party/SPIRV-Tools/source/opt/scalar_replacement_pass.cpp
+++ b/third_party/SPIRV-Tools/source/opt/scalar_replacement_pass.cpp
@@ -24,6 +24,7 @@
#include "source/opt/reflect.h"
#include "source/opt/types.h"
#include "source/util/make_unique.h"
+#include "types.h"
static const uint32_t kDebugValueOperandValueIndex = 5;
static const uint32_t kDebugValueOperandExpressionIndex = 6;
@@ -395,7 +396,7 @@
if (!components_used || components_used->count(elem)) {
CreateVariable(*id, inst, elem, replacements);
} else {
- replacements->push_back(CreateNullConstant(*id));
+ replacements->push_back(GetUndef(*id));
}
elem++;
});
@@ -406,8 +407,8 @@
CreateVariable(type->GetSingleWordInOperand(0u), inst, i,
replacements);
} else {
- replacements->push_back(
- CreateNullConstant(type->GetSingleWordInOperand(0u)));
+ uint32_t element_type_id = type->GetSingleWordInOperand(0);
+ replacements->push_back(GetUndef(element_type_id));
}
}
break;
@@ -429,6 +430,10 @@
replacements->end();
}
+Instruction* ScalarReplacementPass::GetUndef(uint32_t type_id) {
+ return get_def_use_mgr()->GetDef(Type2Undef(type_id));
+}
+
void ScalarReplacementPass::TransferAnnotations(
const Instruction* source, std::vector<Instruction*>* replacements) {
// Only transfer invariant and restrict decorations on the variable. There are
@@ -981,20 +986,6 @@
return result;
}
-Instruction* ScalarReplacementPass::CreateNullConstant(uint32_t type_id) {
- analysis::TypeManager* type_mgr = context()->get_type_mgr();
- analysis::ConstantManager* const_mgr = context()->get_constant_mgr();
-
- const analysis::Type* type = type_mgr->GetType(type_id);
- const analysis::Constant* null_const = const_mgr->GetConstant(type, {});
- Instruction* null_inst =
- const_mgr->GetDefiningInstruction(null_const, type_id);
- if (null_inst != nullptr) {
- context()->UpdateDefUse(null_inst);
- }
- return null_inst;
-}
-
uint64_t ScalarReplacementPass::GetMaxLegalIndex(
const Instruction* var_inst) const {
assert(var_inst->opcode() == SpvOpVariable &&
diff --git a/third_party/SPIRV-Tools/source/opt/scalar_replacement_pass.h b/third_party/SPIRV-Tools/source/opt/scalar_replacement_pass.h
index 0928830..76afc26 100644
--- a/third_party/SPIRV-Tools/source/opt/scalar_replacement_pass.h
+++ b/third_party/SPIRV-Tools/source/opt/scalar_replacement_pass.h
@@ -23,14 +23,14 @@
#include <vector>
#include "source/opt/function.h"
-#include "source/opt/pass.h"
+#include "source/opt/mem_pass.h"
#include "source/opt/type_manager.h"
namespace spvtools {
namespace opt {
// Documented in optimizer.hpp
-class ScalarReplacementPass : public Pass {
+class ScalarReplacementPass : public MemPass {
private:
static const uint32_t kDefaultLimit = 100;
@@ -234,10 +234,8 @@
std::unique_ptr<std::unordered_set<int64_t>> GetUsedComponents(
Instruction* inst);
- // Returns an instruction defining a null constant with type |type_id|. If
- // one already exists, it is returned. Otherwise a new one is created.
- // Returns |nullptr| if the new constant could not be created.
- Instruction* CreateNullConstant(uint32_t type_id);
+ // Returns an instruction defining an undefined value type |type_id|.
+ Instruction* GetUndef(uint32_t type_id);
// Maps storage type to a pointer type enclosing that type.
std::unordered_map<uint32_t, uint32_t> pointee_to_pointer_;
diff --git a/third_party/SPIRV-Tools/source/opt/spread_volatile_semantics.cpp b/third_party/SPIRV-Tools/source/opt/spread_volatile_semantics.cpp
new file mode 100644
index 0000000..17a4c72
--- /dev/null
+++ b/third_party/SPIRV-Tools/source/opt/spread_volatile_semantics.cpp
@@ -0,0 +1,314 @@
+// Copyright (c) 2022 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "source/opt/spread_volatile_semantics.h"
+
+#include "source/opt/decoration_manager.h"
+#include "source/opt/ir_builder.h"
+#include "source/spirv_constant.h"
+
+namespace spvtools {
+namespace opt {
+namespace {
+
+const uint32_t kOpDecorateInOperandBuiltinDecoration = 2u;
+const uint32_t kOpLoadInOperandMemoryOperands = 1u;
+const uint32_t kOpEntryPointInOperandEntryPoint = 1u;
+const uint32_t kOpEntryPointInOperandInterface = 3u;
+
+bool HasBuiltinDecoration(analysis::DecorationManager* decoration_manager,
+ uint32_t var_id, uint32_t built_in) {
+ return decoration_manager->FindDecoration(
+ var_id, SpvDecorationBuiltIn, [built_in](const Instruction& inst) {
+ return built_in == inst.GetSingleWordInOperand(
+ kOpDecorateInOperandBuiltinDecoration);
+ });
+}
+
+bool IsBuiltInForRayTracingVolatileSemantics(uint32_t built_in) {
+ switch (built_in) {
+ case SpvBuiltInSMIDNV:
+ case SpvBuiltInWarpIDNV:
+ case SpvBuiltInSubgroupSize:
+ case SpvBuiltInSubgroupLocalInvocationId:
+ case SpvBuiltInSubgroupEqMask:
+ case SpvBuiltInSubgroupGeMask:
+ case SpvBuiltInSubgroupGtMask:
+ case SpvBuiltInSubgroupLeMask:
+ case SpvBuiltInSubgroupLtMask:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool HasBuiltinForRayTracingVolatileSemantics(
+ analysis::DecorationManager* decoration_manager, uint32_t var_id) {
+ return decoration_manager->FindDecoration(
+ var_id, SpvDecorationBuiltIn, [](const Instruction& inst) {
+ uint32_t built_in =
+ inst.GetSingleWordInOperand(kOpDecorateInOperandBuiltinDecoration);
+ return IsBuiltInForRayTracingVolatileSemantics(built_in);
+ });
+}
+
+bool HasVolatileDecoration(analysis::DecorationManager* decoration_manager,
+ uint32_t var_id) {
+ return decoration_manager->HasDecoration(var_id, SpvDecorationVolatile);
+}
+
+bool HasOnlyEntryPointsAsFunctions(IRContext* context, Module* module) {
+ std::unordered_set<uint32_t> entry_function_ids;
+ for (Instruction& entry_point : module->entry_points()) {
+ entry_function_ids.insert(
+ entry_point.GetSingleWordInOperand(kOpEntryPointInOperandEntryPoint));
+ }
+ for (auto& function : *module) {
+ if (entry_function_ids.find(function.result_id()) ==
+ entry_function_ids.end()) {
+ std::string message(
+ "Functions of SPIR-V for spread-volatile-semantics pass input must "
+ "be inlined except entry points");
+ message += "\n " + function.DefInst().PrettyPrint(
+ SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES);
+ context->consumer()(SPV_MSG_ERROR, "", {0, 0, 0}, message.c_str());
+ return false;
+ }
+ }
+ return true;
+}
+
+} // namespace
+
+Pass::Status SpreadVolatileSemantics::Process() {
+ if (!HasOnlyEntryPointsAsFunctions(context(), get_module())) {
+ return Status::Failure;
+ }
+
+ const bool is_vk_memory_model_enabled =
+ context()->get_feature_mgr()->HasCapability(
+ SpvCapabilityVulkanMemoryModel);
+ CollectTargetsForVolatileSemantics(is_vk_memory_model_enabled);
+
+ // If VulkanMemoryModel capability is not enabled, we have to set Volatile
+ // decoration for interface variables instead of setting Volatile for load
+ // instructions. If an interface (or pointers to it) is used by two load
+ // instructions in two entry points and one must be volatile while another
+ // is not, we have to report an error for the conflict.
+ if (!is_vk_memory_model_enabled &&
+ HasInterfaceInConflictOfVolatileSemantics()) {
+ return Status::Failure;
+ }
+
+ return SpreadVolatileSemanticsToVariables(is_vk_memory_model_enabled);
+}
+
+Pass::Status SpreadVolatileSemantics::SpreadVolatileSemanticsToVariables(
+ const bool is_vk_memory_model_enabled) {
+ Status status = Status::SuccessWithoutChange;
+ for (Instruction& var : context()->types_values()) {
+ auto entry_function_ids =
+ EntryFunctionsToSpreadVolatileSemanticsForVar(var.result_id());
+ if (entry_function_ids.empty()) {
+ continue;
+ }
+
+ if (is_vk_memory_model_enabled) {
+ SetVolatileForLoadsInEntries(&var, entry_function_ids);
+ } else {
+ DecorateVarWithVolatile(&var);
+ }
+ status = Status::SuccessWithChange;
+ }
+ return status;
+}
+
+bool SpreadVolatileSemantics::IsTargetUsedByNonVolatileLoadInEntryPoint(
+ uint32_t var_id, Instruction* entry_point) {
+ uint32_t entry_function_id =
+ entry_point->GetSingleWordInOperand(kOpEntryPointInOperandEntryPoint);
+ return !VisitLoadsOfPointersToVariableInEntries(
+ var_id,
+ [](Instruction* load) {
+ // If it has a load without volatile memory operand, finish traversal
+ // and return false.
+ if (load->NumInOperands() <= kOpLoadInOperandMemoryOperands) {
+ return false;
+ }
+ uint32_t memory_operands =
+ load->GetSingleWordInOperand(kOpLoadInOperandMemoryOperands);
+ return (memory_operands & SpvMemoryAccessVolatileMask) != 0;
+ },
+ {entry_function_id});
+}
+
+bool SpreadVolatileSemantics::HasInterfaceInConflictOfVolatileSemantics() {
+ for (Instruction& entry_point : get_module()->entry_points()) {
+ SpvExecutionModel execution_model =
+ static_cast<SpvExecutionModel>(entry_point.GetSingleWordInOperand(0));
+ for (uint32_t operand_index = kOpEntryPointInOperandInterface;
+ operand_index < entry_point.NumInOperands(); ++operand_index) {
+ uint32_t var_id = entry_point.GetSingleWordInOperand(operand_index);
+ if (!EntryFunctionsToSpreadVolatileSemanticsForVar(var_id).empty() &&
+ !IsTargetForVolatileSemantics(var_id, execution_model) &&
+ IsTargetUsedByNonVolatileLoadInEntryPoint(var_id, &entry_point)) {
+ Instruction* inst = context()->get_def_use_mgr()->GetDef(var_id);
+ context()->EmitErrorMessage(
+ "Variable is a target for Volatile semantics for an entry point, "
+ "but it is not for another entry point",
+ inst);
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+void SpreadVolatileSemantics::MarkVolatileSemanticsForVariable(
+ uint32_t var_id, Instruction* entry_point) {
+ uint32_t entry_function_id =
+ entry_point->GetSingleWordInOperand(kOpEntryPointInOperandEntryPoint);
+ auto itr = var_ids_to_entry_fn_for_volatile_semantics_.find(var_id);
+ if (itr == var_ids_to_entry_fn_for_volatile_semantics_.end()) {
+ var_ids_to_entry_fn_for_volatile_semantics_[var_id] = {entry_function_id};
+ return;
+ }
+ itr->second.insert(entry_function_id);
+}
+
+void SpreadVolatileSemantics::CollectTargetsForVolatileSemantics(
+ const bool is_vk_memory_model_enabled) {
+ for (Instruction& entry_point : get_module()->entry_points()) {
+ SpvExecutionModel execution_model =
+ static_cast<SpvExecutionModel>(entry_point.GetSingleWordInOperand(0));
+ for (uint32_t operand_index = kOpEntryPointInOperandInterface;
+ operand_index < entry_point.NumInOperands(); ++operand_index) {
+ uint32_t var_id = entry_point.GetSingleWordInOperand(operand_index);
+ if (!IsTargetForVolatileSemantics(var_id, execution_model)) {
+ continue;
+ }
+ if (is_vk_memory_model_enabled ||
+ IsTargetUsedByNonVolatileLoadInEntryPoint(var_id, &entry_point)) {
+ MarkVolatileSemanticsForVariable(var_id, &entry_point);
+ }
+ }
+ }
+}
+
+void SpreadVolatileSemantics::DecorateVarWithVolatile(Instruction* var) {
+ analysis::DecorationManager* decoration_manager =
+ context()->get_decoration_mgr();
+ uint32_t var_id = var->result_id();
+ if (HasVolatileDecoration(decoration_manager, var_id)) {
+ return;
+ }
+ get_decoration_mgr()->AddDecoration(
+ SpvOpDecorate, {{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {var_id}},
+ {spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER,
+ {SpvDecorationVolatile}}});
+}
+
+bool SpreadVolatileSemantics::VisitLoadsOfPointersToVariableInEntries(
+ uint32_t var_id, const std::function<bool(Instruction*)>& handle_load,
+ const std::unordered_set<uint32_t>& entry_function_ids) {
+ std::vector<uint32_t> worklist({var_id});
+ auto* def_use_mgr = context()->get_def_use_mgr();
+ while (!worklist.empty()) {
+ uint32_t ptr_id = worklist.back();
+ worklist.pop_back();
+ bool finish_traversal = !def_use_mgr->WhileEachUser(
+ ptr_id, [this, &worklist, &ptr_id, handle_load,
+ &entry_function_ids](Instruction* user) {
+ BasicBlock* block = context()->get_instr_block(user);
+ if (block == nullptr ||
+ entry_function_ids.find(block->GetParent()->result_id()) ==
+ entry_function_ids.end()) {
+ return true;
+ }
+
+ if (user->opcode() == SpvOpAccessChain ||
+ user->opcode() == SpvOpInBoundsAccessChain ||
+ user->opcode() == SpvOpPtrAccessChain ||
+ user->opcode() == SpvOpInBoundsPtrAccessChain ||
+ user->opcode() == SpvOpCopyObject) {
+ if (ptr_id == user->GetSingleWordInOperand(0))
+ worklist.push_back(user->result_id());
+ return true;
+ }
+
+ if (user->opcode() != SpvOpLoad) {
+ return true;
+ }
+
+ return handle_load(user);
+ });
+ if (finish_traversal) return false;
+ }
+ return true;
+}
+
+void SpreadVolatileSemantics::SetVolatileForLoadsInEntries(
+ Instruction* var, const std::unordered_set<uint32_t>& entry_function_ids) {
+ // Set Volatile memory operand for all load instructions if they do not have
+ // it.
+ VisitLoadsOfPointersToVariableInEntries(
+ var->result_id(),
+ [](Instruction* load) {
+ if (load->NumInOperands() <= kOpLoadInOperandMemoryOperands) {
+ load->AddOperand(
+ {SPV_OPERAND_TYPE_MEMORY_ACCESS, {SpvMemoryAccessVolatileMask}});
+ return true;
+ }
+ uint32_t memory_operands =
+ load->GetSingleWordInOperand(kOpLoadInOperandMemoryOperands);
+ memory_operands |= SpvMemoryAccessVolatileMask;
+ load->SetInOperand(kOpLoadInOperandMemoryOperands, {memory_operands});
+ return true;
+ },
+ entry_function_ids);
+}
+
+bool SpreadVolatileSemantics::IsTargetForVolatileSemantics(
+ uint32_t var_id, SpvExecutionModel execution_model) {
+ analysis::DecorationManager* decoration_manager =
+ context()->get_decoration_mgr();
+ if (execution_model == SpvExecutionModelFragment) {
+ return get_module()->version() >= SPV_SPIRV_VERSION_WORD(1, 6) &&
+ HasBuiltinDecoration(decoration_manager, var_id,
+ SpvBuiltInHelperInvocation);
+ }
+
+ if (execution_model == SpvExecutionModelIntersectionKHR ||
+ execution_model == SpvExecutionModelIntersectionNV) {
+ if (HasBuiltinDecoration(decoration_manager, var_id,
+ SpvBuiltInRayTmaxKHR)) {
+ return true;
+ }
+ }
+
+ switch (execution_model) {
+ case SpvExecutionModelRayGenerationKHR:
+ case SpvExecutionModelClosestHitKHR:
+ case SpvExecutionModelMissKHR:
+ case SpvExecutionModelCallableKHR:
+ case SpvExecutionModelIntersectionKHR:
+ return HasBuiltinForRayTracingVolatileSemantics(decoration_manager,
+ var_id);
+ default:
+ return false;
+ }
+}
+
+} // namespace opt
+} // namespace spvtools
diff --git a/third_party/SPIRV-Tools/source/opt/spread_volatile_semantics.h b/third_party/SPIRV-Tools/source/opt/spread_volatile_semantics.h
new file mode 100644
index 0000000..3d0a183
--- /dev/null
+++ b/third_party/SPIRV-Tools/source/opt/spread_volatile_semantics.h
@@ -0,0 +1,110 @@
+// Copyright (c) 2022 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SOURCE_OPT_SPREAD_VOLATILE_SEMANTICS_H_
+#define SOURCE_OPT_SPREAD_VOLATILE_SEMANTICS_H_
+
+#include "source/opt/pass.h"
+
+namespace spvtools {
+namespace opt {
+
+// See optimizer.hpp for documentation.
+class SpreadVolatileSemantics : public Pass {
+ public:
+ SpreadVolatileSemantics() {}
+
+ const char* name() const override { return "spread-volatile-semantics"; }
+
+ Status Process() override;
+
+ IRContext::Analysis GetPreservedAnalyses() override {
+ return IRContext::kAnalysisDefUse | IRContext::kAnalysisDecorations |
+ IRContext::kAnalysisInstrToBlockMapping;
+ }
+
+ private:
+ // Iterates interface variables and spreads the Volatile semantics if it has
+ // load instructions for the Volatile semantics.
+ Pass::Status SpreadVolatileSemanticsToVariables(
+ const bool is_vk_memory_model_enabled);
+
+ // Returns whether |var_id| is the result id of a target builtin variable for
+ // the volatile semantics for |execution_model| based on the Vulkan spec
+ // VUID-StandaloneSpirv-VulkanMemoryModel-04678 or
+ // VUID-StandaloneSpirv-VulkanMemoryModel-04679.
+ bool IsTargetForVolatileSemantics(uint32_t var_id,
+ SpvExecutionModel execution_model);
+
+ // Collects interface variables that need the volatile semantics.
+ // |is_vk_memory_model_enabled| is true if VulkanMemoryModel capability is
+ // enabled.
+ void CollectTargetsForVolatileSemantics(
+ const bool is_vk_memory_model_enabled);
+
+ // Reports an error if an interface variable is used by two entry points and
+ // it needs the Volatile decoration for one but not for another. Returns true
+ // if the error must be reported.
+ bool HasInterfaceInConflictOfVolatileSemantics();
+
+ // Returns whether the variable whose result is |var_id| is used by a
+ // non-volatile load or a pointer to it is used by a non-volatile load in
+ // |entry_point| or not.
+ bool IsTargetUsedByNonVolatileLoadInEntryPoint(uint32_t var_id,
+ Instruction* entry_point);
+
+ // Visits load instructions of pointers to variable whose result id is
+ // |var_id| if the load instructions are in entry points whose
+ // function id is one of |entry_function_ids|. |handle_load| is a function to
+ // do some actions for the load instructions. Finishes the traversal and
+ // returns false if |handle_load| returns false for a load instruction.
+ // Otherwise, returns true after running |handle_load| for all the load
+ // instructions.
+ bool VisitLoadsOfPointersToVariableInEntries(
+ uint32_t var_id, const std::function<bool(Instruction*)>& handle_load,
+ const std::unordered_set<uint32_t>& entry_function_ids);
+
+ // Sets Memory Operands of OpLoad instructions that load |var| or pointers
+ // of |var| as Volatile if the function id of the OpLoad instruction is
+ // included in |entry_function_ids|.
+ void SetVolatileForLoadsInEntries(
+ Instruction* var, const std::unordered_set<uint32_t>& entry_function_ids);
+
+ // Adds OpDecorate Volatile for |var| if it does not exist.
+ void DecorateVarWithVolatile(Instruction* var);
+
+ // Returns a set of entry function ids to spread the volatile semantics for
+ // the variable with the result id |var_id|.
+ std::unordered_set<uint32_t> EntryFunctionsToSpreadVolatileSemanticsForVar(
+ uint32_t var_id) {
+ auto itr = var_ids_to_entry_fn_for_volatile_semantics_.find(var_id);
+ if (itr == var_ids_to_entry_fn_for_volatile_semantics_.end()) return {};
+ return itr->second;
+ }
+
+ // Specifies that we have to spread the volatile semantics for the
+ // variable with the result id |var_id| for the entry point |entry_point|.
+ void MarkVolatileSemanticsForVariable(uint32_t var_id,
+ Instruction* entry_point);
+
+ // Result ids of variables to entry function ids for the volatile semantics
+ // spread.
+ std::unordered_map<uint32_t, std::unordered_set<uint32_t>>
+ var_ids_to_entry_fn_for_volatile_semantics_;
+};
+
+} // namespace opt
+} // namespace spvtools
+
+#endif // SOURCE_OPT_SPREAD_VOLATILE_SEMANTICS_H_
diff --git a/third_party/SPIRV-Tools/source/opt/strength_reduction_pass.h b/third_party/SPIRV-Tools/source/opt/strength_reduction_pass.h
index 8dfeb30..1cbbbcc 100644
--- a/third_party/SPIRV-Tools/source/opt/strength_reduction_pass.h
+++ b/third_party/SPIRV-Tools/source/opt/strength_reduction_pass.h
@@ -34,7 +34,7 @@
// Returns true if something changed.
bool ReplaceMultiplyByPowerOf2(BasicBlock::iterator*);
- // Scan the types and constants in the module looking for the the integer
+ // Scan the types and constants in the module looking for the integer
// types that we are
// interested in. The shift operation needs a small unsigned integer. We
// need to find
diff --git a/third_party/SPIRV-Tools/source/opt/strip_debug_info_pass.cpp b/third_party/SPIRV-Tools/source/opt/strip_debug_info_pass.cpp
index c86ce57..6a0ebf2 100644
--- a/third_party/SPIRV-Tools/source/opt/strip_debug_info_pass.cpp
+++ b/third_party/SPIRV-Tools/source/opt/strip_debug_info_pass.cpp
@@ -14,6 +14,7 @@
#include "source/opt/strip_debug_info_pass.h"
#include "source/opt/ir_context.h"
+#include "source/util/string_utils.h"
namespace spvtools {
namespace opt {
@@ -21,9 +22,8 @@
Pass::Status StripDebugInfoPass::Process() {
bool uses_non_semantic_info = false;
for (auto& inst : context()->module()->extensions()) {
- const char* ext_name =
- reinterpret_cast<const char*>(&inst.GetInOperand(0).words[0]);
- if (0 == std::strcmp(ext_name, "SPV_KHR_non_semantic_info")) {
+ const std::string ext_name = inst.GetInOperand(0).AsString();
+ if (ext_name == "SPV_KHR_non_semantic_info") {
uses_non_semantic_info = true;
}
}
@@ -46,9 +46,10 @@
if (use->opcode() == SpvOpExtInst) {
auto ext_inst_set =
def_use->GetDef(use->GetSingleWordInOperand(0u));
- const char* extension_name = reinterpret_cast<const char*>(
- &ext_inst_set->GetInOperand(0).words[0]);
- if (0 == std::strncmp(extension_name, "NonSemantic.", 12)) {
+ const std::string extension_name =
+ ext_inst_set->GetInOperand(0).AsString();
+ if (spvtools::utils::starts_with(extension_name,
+ "NonSemantic.")) {
// found a non-semantic use, return false as we cannot
// remove this OpString
return false;
diff --git a/third_party/SPIRV-Tools/source/opt/strip_reflect_info_pass.cpp b/third_party/SPIRV-Tools/source/opt/strip_nonsemantic_info_pass.cpp
similarity index 65%
rename from third_party/SPIRV-Tools/source/opt/strip_reflect_info_pass.cpp
rename to third_party/SPIRV-Tools/source/opt/strip_nonsemantic_info_pass.cpp
index 8b0f2db..cd1fbb6 100644
--- a/third_party/SPIRV-Tools/source/opt/strip_reflect_info_pass.cpp
+++ b/third_party/SPIRV-Tools/source/opt/strip_nonsemantic_info_pass.cpp
@@ -12,18 +12,19 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include "source/opt/strip_reflect_info_pass.h"
+#include "source/opt/strip_nonsemantic_info_pass.h"
#include <cstring>
#include <vector>
#include "source/opt/instruction.h"
#include "source/opt/ir_context.h"
+#include "source/util/string_utils.h"
namespace spvtools {
namespace opt {
-Pass::Status StripReflectInfoPass::Process() {
+Pass::Status StripNonSemanticInfoPass::Process() {
bool modified = false;
std::vector<Instruction*> to_remove;
@@ -32,7 +33,8 @@
for (auto& inst : context()->module()->annotations()) {
switch (inst.opcode()) {
case SpvOpDecorateStringGOOGLE:
- if (inst.GetSingleWordInOperand(1) == SpvDecorationHlslSemanticGOOGLE) {
+ if (inst.GetSingleWordInOperand(1) == SpvDecorationHlslSemanticGOOGLE ||
+ inst.GetSingleWordInOperand(1) == SpvDecorationUserTypeGOOGLE) {
to_remove.push_back(&inst);
} else {
other_uses_for_decorate_string = true;
@@ -40,7 +42,8 @@
break;
case SpvOpMemberDecorateStringGOOGLE:
- if (inst.GetSingleWordInOperand(2) == SpvDecorationHlslSemanticGOOGLE) {
+ if (inst.GetSingleWordInOperand(2) == SpvDecorationHlslSemanticGOOGLE ||
+ inst.GetSingleWordInOperand(2) == SpvDecorationUserTypeGOOGLE) {
to_remove.push_back(&inst);
} else {
other_uses_for_decorate_string = true;
@@ -60,33 +63,26 @@
}
for (auto& inst : context()->module()->extensions()) {
- const char* ext_name =
- reinterpret_cast<const char*>(&inst.GetInOperand(0).words[0]);
- if (0 == std::strcmp(ext_name, "SPV_GOOGLE_hlsl_functionality1")) {
+ const std::string ext_name = inst.GetInOperand(0).AsString();
+ if (ext_name == "SPV_GOOGLE_hlsl_functionality1") {
+ to_remove.push_back(&inst);
+ } else if (ext_name == "SPV_GOOGLE_user_type") {
to_remove.push_back(&inst);
} else if (!other_uses_for_decorate_string &&
- 0 == std::strcmp(ext_name, "SPV_GOOGLE_decorate_string")) {
+ ext_name == "SPV_GOOGLE_decorate_string") {
to_remove.push_back(&inst);
- } else if (0 == std::strcmp(ext_name, "SPV_KHR_non_semantic_info")) {
+ } else if (ext_name == "SPV_KHR_non_semantic_info") {
to_remove.push_back(&inst);
}
}
- // clear all debug data now if it hasn't been cleared already, to remove any
- // remaining OpString that may have been referenced by non-semantic extinsts
- for (auto& dbg : context()->debugs1()) to_remove.push_back(&dbg);
- for (auto& dbg : context()->debugs2()) to_remove.push_back(&dbg);
- for (auto& dbg : context()->debugs3()) to_remove.push_back(&dbg);
- for (auto& dbg : context()->ext_inst_debuginfo()) to_remove.push_back(&dbg);
-
// remove any extended inst imports that are non semantic
std::unordered_set<uint32_t> non_semantic_sets;
for (auto& inst : context()->module()->ext_inst_imports()) {
assert(inst.opcode() == SpvOpExtInstImport &&
"Expecting an import of an extension's instruction set.");
- const char* extension_name =
- reinterpret_cast<const char*>(&inst.GetInOperand(0).words[0]);
- if (0 == std::strncmp(extension_name, "NonSemantic.", 12)) {
+ const std::string extension_name = inst.GetInOperand(0).AsString();
+ if (spvtools::utils::starts_with(extension_name, "NonSemantic.")) {
non_semantic_sets.insert(inst.result_id());
to_remove.push_back(&inst);
}
@@ -103,19 +99,10 @@
to_remove.push_back(inst);
}
}
- });
+ },
+ true);
}
- // OpName must come first, since they may refer to other debug instructions.
- // If they are after the instructions that refer to, then they will be killed
- // when that instruction is killed, which will lead to a double kill.
- std::sort(to_remove.begin(), to_remove.end(),
- [](Instruction* lhs, Instruction* rhs) -> bool {
- if (lhs->opcode() == SpvOpName && rhs->opcode() != SpvOpName)
- return true;
- return false;
- });
-
for (auto* inst : to_remove) {
modified = true;
context()->KillInst(inst);
diff --git a/third_party/SPIRV-Tools/source/opt/strip_reflect_info_pass.h b/third_party/SPIRV-Tools/source/opt/strip_nonsemantic_info_pass.h
similarity index 82%
rename from third_party/SPIRV-Tools/source/opt/strip_reflect_info_pass.h
rename to third_party/SPIRV-Tools/source/opt/strip_nonsemantic_info_pass.h
index 4e1999e..ff4e2e1 100644
--- a/third_party/SPIRV-Tools/source/opt/strip_reflect_info_pass.h
+++ b/third_party/SPIRV-Tools/source/opt/strip_nonsemantic_info_pass.h
@@ -12,8 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#ifndef SOURCE_OPT_STRIP_REFLECT_INFO_PASS_H_
-#define SOURCE_OPT_STRIP_REFLECT_INFO_PASS_H_
+#ifndef SOURCE_OPT_STRIP_NONSEMANTIC_INFO_PASS_H_
+#define SOURCE_OPT_STRIP_NONSEMANTIC_INFO_PASS_H_
#include "source/opt/ir_context.h"
#include "source/opt/module.h"
@@ -23,9 +23,9 @@
namespace opt {
// See optimizer.hpp for documentation.
-class StripReflectInfoPass : public Pass {
+class StripNonSemanticInfoPass : public Pass {
public:
- const char* name() const override { return "strip-reflect"; }
+ const char* name() const override { return "strip-nonsemantic"; }
Status Process() override;
// Return the mask of preserved Analyses.
@@ -41,4 +41,4 @@
} // namespace opt
} // namespace spvtools
-#endif // SOURCE_OPT_STRIP_REFLECT_INFO_PASS_H_
+#endif // SOURCE_OPT_STRIP_NONSEMANTIC_INFO_PASS_H_
diff --git a/third_party/SPIRV-Tools/source/opt/type_manager.cpp b/third_party/SPIRV-Tools/source/opt/type_manager.cpp
index 7935ad3..a0006f5 100644
--- a/third_party/SPIRV-Tools/source/opt/type_manager.cpp
+++ b/third_party/SPIRV-Tools/source/opt/type_manager.cpp
@@ -23,6 +23,7 @@
#include "source/opt/log.h"
#include "source/opt/reflect.h"
#include "source/util/make_unique.h"
+#include "source/util/string_utils.h"
namespace spvtools {
namespace opt {
@@ -234,6 +235,7 @@
DefineParameterlessCase(PipeStorage);
DefineParameterlessCase(NamedBarrier);
DefineParameterlessCase(AccelerationStructureNV);
+ DefineParameterlessCase(RayQueryKHR);
#undef DefineParameterlessCase
case Type::kInteger:
typeInst = MakeUnique<Instruction>(
@@ -349,11 +351,8 @@
}
case Type::kOpaque: {
const Opaque* opaque = type->AsOpaque();
- size_t size = opaque->name().size();
// Convert to null-terminated packed UTF-8 string.
- std::vector<uint32_t> words(size / 4 + 1, 0);
- char* dst = reinterpret_cast<char*>(words.data());
- strncpy(dst, opaque->name().c_str(), size);
+ std::vector<uint32_t> words = spvtools::utils::MakeVector(opaque->name());
typeInst = MakeUnique<Instruction>(
context(), SpvOpTypeOpaque, 0, id,
std::initializer_list<Operand>{
@@ -529,6 +528,7 @@
DefineNoSubtypeCase(PipeStorage);
DefineNoSubtypeCase(NamedBarrier);
DefineNoSubtypeCase(AccelerationStructureNV);
+ DefineNoSubtypeCase(RayQueryKHR);
#undef DefineNoSubtypeCase
case Type::kVector: {
const Vector* vec_ty = type.AsVector();
@@ -781,8 +781,7 @@
}
} break;
case SpvOpTypeOpaque: {
- const uint32_t* data = inst.GetInOperand(0).words.data();
- type = new Opaque(reinterpret_cast<const char*>(data));
+ type = new Opaque(inst.GetInOperand(0).AsString());
} break;
case SpvOpTypePointer: {
uint32_t pointee_type_id = inst.GetSingleWordInOperand(1);
diff --git a/third_party/SPIRV-Tools/source/opt/types.cpp b/third_party/SPIRV-Tools/source/opt/types.cpp
index b1eb3a5..47abd41 100644
--- a/third_party/SPIRV-Tools/source/opt/types.cpp
+++ b/third_party/SPIRV-Tools/source/opt/types.cpp
@@ -21,6 +21,7 @@
#include <string>
#include <unordered_set>
+#include "source/util/hash_combine.h"
#include "source/util/make_unique.h"
#include "spirv/unified1/spirv.h"
@@ -28,6 +29,7 @@
namespace opt {
namespace analysis {
+using spvtools::utils::hash_combine;
using U32VecVec = std::vector<std::vector<uint32_t>>;
namespace {
@@ -182,23 +184,26 @@
}
}
-void Type::GetHashWords(std::vector<uint32_t>* words,
- std::unordered_set<const Type*>* seen) const {
- if (!seen->insert(this).second) {
- return;
+size_t Type::ComputeHashValue(size_t hash, SeenTypes* seen) const {
+ // Linear search through a dense, cache coherent vector is faster than O(log
+ // n) search in a complex data structure (eg std::set) for the generally small
+ // number of nodes. It also skips the overhead of an new/delete per Type
+ // (when inserting/removing from a set).
+ if (std::find(seen->begin(), seen->end(), this) != seen->end()) {
+ return hash;
}
- words->push_back(kind_);
+ seen->push_back(this);
+
+ hash = hash_combine(hash, uint32_t(kind_));
for (const auto& d : decorations_) {
- for (auto w : d) {
- words->push_back(w);
- }
+ hash = hash_combine(hash, d);
}
switch (kind_) {
-#define DeclareKindCase(type) \
- case k##type: \
- As##type()->GetExtraHashWords(words, seen); \
+#define DeclareKindCase(type) \
+ case k##type: \
+ hash = As##type()->ComputeExtraStateHash(hash, seen); \
break
DeclareKindCase(Void);
DeclareKindCase(Bool);
@@ -232,18 +237,13 @@
break;
}
- seen->erase(this);
+ seen->pop_back();
+ return hash;
}
size_t Type::HashValue() const {
- std::u32string h;
- std::vector<uint32_t> words;
- GetHashWords(&words);
- for (auto w : words) {
- h.push_back(w);
- }
-
- return std::hash<std::u32string>()(h);
+ SeenTypes seen;
+ return ComputeHashValue(0, &seen);
}
bool Integer::IsSameImpl(const Type* that, IsSameCache*) const {
@@ -258,10 +258,8 @@
return oss.str();
}
-void Integer::GetExtraHashWords(std::vector<uint32_t>* words,
- std::unordered_set<const Type*>*) const {
- words->push_back(width_);
- words->push_back(signed_);
+size_t Integer::ComputeExtraStateHash(size_t hash, SeenTypes*) const {
+ return hash_combine(hash, width_, signed_);
}
bool Float::IsSameImpl(const Type* that, IsSameCache*) const {
@@ -275,9 +273,8 @@
return oss.str();
}
-void Float::GetExtraHashWords(std::vector<uint32_t>* words,
- std::unordered_set<const Type*>*) const {
- words->push_back(width_);
+size_t Float::ComputeExtraStateHash(size_t hash, SeenTypes*) const {
+ return hash_combine(hash, width_);
}
Vector::Vector(const Type* type, uint32_t count)
@@ -299,10 +296,11 @@
return oss.str();
}
-void Vector::GetExtraHashWords(std::vector<uint32_t>* words,
- std::unordered_set<const Type*>* seen) const {
- element_type_->GetHashWords(words, seen);
- words->push_back(count_);
+size_t Vector::ComputeExtraStateHash(size_t hash, SeenTypes* seen) const {
+ // prefer form that doesn't require push/pop from stack: add state and
+ // make tail call.
+ hash = hash_combine(hash, count_);
+ return element_type_->ComputeHashValue(hash, seen);
}
Matrix::Matrix(const Type* type, uint32_t count)
@@ -324,10 +322,9 @@
return oss.str();
}
-void Matrix::GetExtraHashWords(std::vector<uint32_t>* words,
- std::unordered_set<const Type*>* seen) const {
- element_type_->GetHashWords(words, seen);
- words->push_back(count_);
+size_t Matrix::ComputeExtraStateHash(size_t hash, SeenTypes* seen) const {
+ hash = hash_combine(hash, count_);
+ return element_type_->ComputeHashValue(hash, seen);
}
Image::Image(Type* type, SpvDim dimen, uint32_t d, bool array, bool multisample,
@@ -362,16 +359,10 @@
return oss.str();
}
-void Image::GetExtraHashWords(std::vector<uint32_t>* words,
- std::unordered_set<const Type*>* seen) const {
- sampled_type_->GetHashWords(words, seen);
- words->push_back(dim_);
- words->push_back(depth_);
- words->push_back(arrayed_);
- words->push_back(ms_);
- words->push_back(sampled_);
- words->push_back(format_);
- words->push_back(access_qualifier_);
+size_t Image::ComputeExtraStateHash(size_t hash, SeenTypes* seen) const {
+ hash = hash_combine(hash, uint32_t(dim_), depth_, arrayed_, ms_, sampled_,
+ uint32_t(format_), uint32_t(access_qualifier_));
+ return sampled_type_->ComputeHashValue(hash, seen);
}
bool SampledImage::IsSameImpl(const Type* that, IsSameCache* seen) const {
@@ -387,9 +378,8 @@
return oss.str();
}
-void SampledImage::GetExtraHashWords(
- std::vector<uint32_t>* words, std::unordered_set<const Type*>* seen) const {
- image_type_->GetHashWords(words, seen);
+size_t SampledImage::ComputeExtraStateHash(size_t hash, SeenTypes* seen) const {
+ return image_type_->ComputeHashValue(hash, seen);
}
Array::Array(const Type* type, const Array::LengthInfo& length_info_arg)
@@ -422,12 +412,9 @@
return oss.str();
}
-void Array::GetExtraHashWords(std::vector<uint32_t>* words,
- std::unordered_set<const Type*>* seen) const {
- element_type_->GetHashWords(words, seen);
- // This should mirror the logic in IsSameImpl
- words->insert(words->end(), length_info_.words.begin(),
- length_info_.words.end());
+size_t Array::ComputeExtraStateHash(size_t hash, SeenTypes* seen) const {
+ hash = hash_combine(hash, length_info_.words);
+ return element_type_->ComputeHashValue(hash, seen);
}
void Array::ReplaceElementType(const Type* type) { element_type_ = type; }
@@ -450,9 +437,8 @@
return oss.str();
}
-void RuntimeArray::GetExtraHashWords(
- std::vector<uint32_t>* words, std::unordered_set<const Type*>* seen) const {
- element_type_->GetHashWords(words, seen);
+size_t RuntimeArray::ComputeExtraStateHash(size_t hash, SeenTypes* seen) const {
+ return element_type_->ComputeHashValue(hash, seen);
}
void RuntimeArray::ReplaceElementType(const Type* type) {
@@ -509,19 +495,14 @@
return oss.str();
}
-void Struct::GetExtraHashWords(std::vector<uint32_t>* words,
- std::unordered_set<const Type*>* seen) const {
+size_t Struct::ComputeExtraStateHash(size_t hash, SeenTypes* seen) const {
for (auto* t : element_types_) {
- t->GetHashWords(words, seen);
+ hash = t->ComputeHashValue(hash, seen);
}
for (const auto& pair : element_decorations_) {
- words->push_back(pair.first);
- for (const auto& d : pair.second) {
- for (auto w : d) {
- words->push_back(w);
- }
- }
+ hash = hash_combine(hash, pair.first, pair.second);
}
+ return hash;
}
bool Opaque::IsSameImpl(const Type* that, IsSameCache*) const {
@@ -536,11 +517,8 @@
return oss.str();
}
-void Opaque::GetExtraHashWords(std::vector<uint32_t>* words,
- std::unordered_set<const Type*>*) const {
- for (auto c : name_) {
- words->push_back(static_cast<char32_t>(c));
- }
+size_t Opaque::ComputeExtraStateHash(size_t hash, SeenTypes*) const {
+ return hash_combine(hash, name_);
}
Pointer::Pointer(const Type* type, SpvStorageClass sc)
@@ -569,10 +547,9 @@
return os.str();
}
-void Pointer::GetExtraHashWords(std::vector<uint32_t>* words,
- std::unordered_set<const Type*>* seen) const {
- pointee_type_->GetHashWords(words, seen);
- words->push_back(storage_class_);
+size_t Pointer::ComputeExtraStateHash(size_t hash, SeenTypes* seen) const {
+ hash = hash_combine(hash, uint32_t(storage_class_));
+ return pointee_type_->ComputeHashValue(hash, seen);
}
void Pointer::SetPointeeType(const Type* type) { pointee_type_ = type; }
@@ -606,12 +583,11 @@
return oss.str();
}
-void Function::GetExtraHashWords(std::vector<uint32_t>* words,
- std::unordered_set<const Type*>* seen) const {
- return_type_->GetHashWords(words, seen);
+size_t Function::ComputeExtraStateHash(size_t hash, SeenTypes* seen) const {
for (const auto* t : param_types_) {
- t->GetHashWords(words, seen);
+ hash = t->ComputeHashValue(hash, seen);
}
+ return return_type_->ComputeHashValue(hash, seen);
}
void Function::SetReturnType(const Type* type) { return_type_ = type; }
@@ -628,9 +604,8 @@
return oss.str();
}
-void Pipe::GetExtraHashWords(std::vector<uint32_t>* words,
- std::unordered_set<const Type*>*) const {
- words->push_back(access_qualifier_);
+size_t Pipe::ComputeExtraStateHash(size_t hash, SeenTypes*) const {
+ return hash_combine(hash, uint32_t(access_qualifier_));
}
bool ForwardPointer::IsSameImpl(const Type* that, IsSameCache*) const {
@@ -653,11 +628,11 @@
return oss.str();
}
-void ForwardPointer::GetExtraHashWords(
- std::vector<uint32_t>* words, std::unordered_set<const Type*>* seen) const {
- words->push_back(target_id_);
- words->push_back(storage_class_);
- if (pointer_) pointer_->GetHashWords(words, seen);
+size_t ForwardPointer::ComputeExtraStateHash(size_t hash,
+ SeenTypes* seen) const {
+ hash = hash_combine(hash, target_id_, uint32_t(storage_class_));
+ if (pointer_) hash = pointer_->ComputeHashValue(hash, seen);
+ return hash;
}
CooperativeMatrixNV::CooperativeMatrixNV(const Type* type, const uint32_t scope,
@@ -681,12 +656,10 @@
return oss.str();
}
-void CooperativeMatrixNV::GetExtraHashWords(
- std::vector<uint32_t>* words, std::unordered_set<const Type*>* pSet) const {
- component_type_->GetHashWords(words, pSet);
- words->push_back(scope_id_);
- words->push_back(rows_id_);
- words->push_back(columns_id_);
+size_t CooperativeMatrixNV::ComputeExtraStateHash(size_t hash,
+ SeenTypes* seen) const {
+ hash = hash_combine(hash, scope_id_, rows_id_, columns_id_);
+ return component_type_->ComputeHashValue(hash, seen);
}
bool CooperativeMatrixNV::IsSameImpl(const Type* that,
diff --git a/third_party/SPIRV-Tools/source/opt/types.h b/third_party/SPIRV-Tools/source/opt/types.h
index 9ecd41a..01e8f3c 100644
--- a/third_party/SPIRV-Tools/source/opt/types.h
+++ b/third_party/SPIRV-Tools/source/opt/types.h
@@ -28,6 +28,7 @@
#include "source/latest_version_spirv_header.h"
#include "source/opt/instruction.h"
+#include "source/util/small_vector.h"
#include "spirv-tools/libspirv.h"
namespace spvtools {
@@ -67,6 +68,8 @@
public:
typedef std::set<std::pair<const Pointer*, const Pointer*>> IsSameCache;
+ using SeenTypes = spvtools::utils::SmallVector<const Type*, 8>;
+
// Available subtypes.
//
// When adding a new derived class of Type, please add an entry to the enum.
@@ -96,7 +99,8 @@
kNamedBarrier,
kAccelerationStructureNV,
kCooperativeMatrixNV,
- kRayQueryKHR
+ kRayQueryKHR,
+ kLast
};
Type(Kind k) : kind_(k) {}
@@ -154,21 +158,7 @@
// Returns the hash value of this type.
size_t HashValue() const;
- // Adds the necessary words to compute a hash value of this type to |words|.
- void GetHashWords(std::vector<uint32_t>* words) const {
- std::unordered_set<const Type*> seen;
- GetHashWords(words, &seen);
- }
-
- // Adds the necessary words to compute a hash value of this type to |words|.
- void GetHashWords(std::vector<uint32_t>* words,
- std::unordered_set<const Type*>* seen) const;
-
- // Adds necessary extra words for a subtype to calculate a hash value into
- // |words|.
- virtual void GetExtraHashWords(
- std::vector<uint32_t>* words,
- std::unordered_set<const Type*>* pSet) const = 0;
+ size_t ComputeHashValue(size_t hash, SeenTypes* seen) const;
// A bunch of methods for casting this type to a given type. Returns this if the
// cast can be done, nullptr otherwise.
@@ -204,6 +194,10 @@
DeclareCastMethod(RayQueryKHR)
#undef DeclareCastMethod
+protected:
+ // Add any type-specific state to |hash| and returns new hash.
+ virtual size_t ComputeExtraStateHash(size_t hash, SeenTypes* seen) const = 0;
+
protected:
// Decorations attached to this type. Each decoration is encoded as a vector
// of uint32_t numbers. The first uint32_t number is the decoration value,
@@ -232,8 +226,7 @@
uint32_t width() const { return width_; }
bool IsSigned() const { return signed_; }
- void GetExtraHashWords(std::vector<uint32_t>* words,
- std::unordered_set<const Type*>* pSet) const override;
+ size_t ComputeExtraStateHash(size_t hash, SeenTypes* seen) const override;
private:
bool IsSameImpl(const Type* that, IsSameCache*) const override;
@@ -253,8 +246,7 @@
const Float* AsFloat() const override { return this; }
uint32_t width() const { return width_; }
- void GetExtraHashWords(std::vector<uint32_t>* words,
- std::unordered_set<const Type*>* pSet) const override;
+ size_t ComputeExtraStateHash(size_t hash, SeenTypes* seen) const override;
private:
bool IsSameImpl(const Type* that, IsSameCache*) const override;
@@ -274,8 +266,7 @@
Vector* AsVector() override { return this; }
const Vector* AsVector() const override { return this; }
- void GetExtraHashWords(std::vector<uint32_t>* words,
- std::unordered_set<const Type*>* pSet) const override;
+ size_t ComputeExtraStateHash(size_t hash, SeenTypes* seen) const override;
private:
bool IsSameImpl(const Type* that, IsSameCache*) const override;
@@ -296,8 +287,7 @@
Matrix* AsMatrix() override { return this; }
const Matrix* AsMatrix() const override { return this; }
- void GetExtraHashWords(std::vector<uint32_t>* words,
- std::unordered_set<const Type*>* pSet) const override;
+ size_t ComputeExtraStateHash(size_t hash, SeenTypes* seen) const override;
private:
bool IsSameImpl(const Type* that, IsSameCache*) const override;
@@ -327,8 +317,7 @@
SpvImageFormat format() const { return format_; }
SpvAccessQualifier access_qualifier() const { return access_qualifier_; }
- void GetExtraHashWords(std::vector<uint32_t>* words,
- std::unordered_set<const Type*>* pSet) const override;
+ size_t ComputeExtraStateHash(size_t hash, SeenTypes* seen) const override;
private:
bool IsSameImpl(const Type* that, IsSameCache*) const override;
@@ -355,8 +344,7 @@
const Type* image_type() const { return image_type_; }
- void GetExtraHashWords(std::vector<uint32_t>* words,
- std::unordered_set<const Type*>* pSet) const override;
+ size_t ComputeExtraStateHash(size_t hash, SeenTypes* seen) const override;
private:
bool IsSameImpl(const Type* that, IsSameCache*) const override;
@@ -399,8 +387,7 @@
Array* AsArray() override { return this; }
const Array* AsArray() const override { return this; }
- void GetExtraHashWords(std::vector<uint32_t>* words,
- std::unordered_set<const Type*>* pSet) const override;
+ size_t ComputeExtraStateHash(size_t hash, SeenTypes* seen) const override;
void ReplaceElementType(const Type* element_type);
@@ -422,8 +409,7 @@
RuntimeArray* AsRuntimeArray() override { return this; }
const RuntimeArray* AsRuntimeArray() const override { return this; }
- void GetExtraHashWords(std::vector<uint32_t>* words,
- std::unordered_set<const Type*>* pSet) const override;
+ size_t ComputeExtraStateHash(size_t hash, SeenTypes* seen) const override;
void ReplaceElementType(const Type* element_type);
@@ -459,8 +445,7 @@
Struct* AsStruct() override { return this; }
const Struct* AsStruct() const override { return this; }
- void GetExtraHashWords(std::vector<uint32_t>* words,
- std::unordered_set<const Type*>* pSet) const override;
+ size_t ComputeExtraStateHash(size_t hash, SeenTypes* seen) const override;
private:
bool IsSameImpl(const Type* that, IsSameCache*) const override;
@@ -491,8 +476,7 @@
const std::string& name() const { return name_; }
- void GetExtraHashWords(std::vector<uint32_t>* words,
- std::unordered_set<const Type*>* pSet) const override;
+ size_t ComputeExtraStateHash(size_t hash, SeenTypes* seen) const override;
private:
bool IsSameImpl(const Type* that, IsSameCache*) const override;
@@ -512,8 +496,7 @@
Pointer* AsPointer() override { return this; }
const Pointer* AsPointer() const override { return this; }
- void GetExtraHashWords(std::vector<uint32_t>* words,
- std::unordered_set<const Type*>* pSet) const override;
+ size_t ComputeExtraStateHash(size_t hash, SeenTypes* seen) const override;
void SetPointeeType(const Type* type);
@@ -539,8 +522,7 @@
const std::vector<const Type*>& param_types() const { return param_types_; }
std::vector<const Type*>& param_types() { return param_types_; }
- void GetExtraHashWords(std::vector<uint32_t>* words,
- std::unordered_set<const Type*>*) const override;
+ size_t ComputeExtraStateHash(size_t hash, SeenTypes* seen) const override;
void SetReturnType(const Type* type);
@@ -564,8 +546,7 @@
SpvAccessQualifier access_qualifier() const { return access_qualifier_; }
- void GetExtraHashWords(std::vector<uint32_t>* words,
- std::unordered_set<const Type*>* pSet) const override;
+ size_t ComputeExtraStateHash(size_t hash, SeenTypes* seen) const override;
private:
bool IsSameImpl(const Type* that, IsSameCache*) const override;
@@ -592,8 +573,7 @@
ForwardPointer* AsForwardPointer() override { return this; }
const ForwardPointer* AsForwardPointer() const override { return this; }
- void GetExtraHashWords(std::vector<uint32_t>* words,
- std::unordered_set<const Type*>* pSet) const override;
+ size_t ComputeExtraStateHash(size_t hash, SeenTypes* seen) const override;
private:
bool IsSameImpl(const Type* that, IsSameCache*) const override;
@@ -616,8 +596,7 @@
return this;
}
- void GetExtraHashWords(std::vector<uint32_t>*,
- std::unordered_set<const Type*>*) const override;
+ size_t ComputeExtraStateHash(size_t hash, SeenTypes* seen) const override;
const Type* component_type() const { return component_type_; }
uint32_t scope_id() const { return scope_id_; }
@@ -633,24 +612,25 @@
const uint32_t columns_id_;
};
-#define DefineParameterlessType(type, name) \
- class type : public Type { \
- public: \
- type() : Type(k##type) {} \
- type(const type&) = default; \
- \
- std::string str() const override { return #name; } \
- \
- type* As##type() override { return this; } \
- const type* As##type() const override { return this; } \
- \
- void GetExtraHashWords(std::vector<uint32_t>*, \
- std::unordered_set<const Type*>*) const override {} \
- \
- private: \
- bool IsSameImpl(const Type* that, IsSameCache*) const override { \
- return that->As##type() && HasSameDecorations(that); \
- } \
+#define DefineParameterlessType(type, name) \
+ class type : public Type { \
+ public: \
+ type() : Type(k##type) {} \
+ type(const type&) = default; \
+ \
+ std::string str() const override { return #name; } \
+ \
+ type* As##type() override { return this; } \
+ const type* As##type() const override { return this; } \
+ \
+ size_t ComputeExtraStateHash(size_t hash, SeenTypes*) const override { \
+ return hash; \
+ } \
+ \
+ private: \
+ bool IsSameImpl(const Type* that, IsSameCache*) const override { \
+ return that->As##type() && HasSameDecorations(that); \
+ } \
}
DefineParameterlessType(Void, void);
DefineParameterlessType(Bool, bool);
diff --git a/third_party/SPIRV-Tools/source/opt/unify_const_pass.cpp b/third_party/SPIRV-Tools/source/opt/unify_const_pass.cpp
index 227fd61..6bfa11a 100644
--- a/third_party/SPIRV-Tools/source/opt/unify_const_pass.cpp
+++ b/third_party/SPIRV-Tools/source/opt/unify_const_pass.cpp
@@ -151,7 +151,7 @@
// 'SpecId' decoration and all of them should be treated as unique.
// 'SpecId' is not applicable to SpecConstants defined with
// OpSpecConstant{Op|Composite}, their values are not necessary to be
- // unique. When all the operands/compoents are the same between two
+ // unique. When all the operands/components are the same between two
// OpSpecConstant{Op|Composite} results, their result values must be the
// same so are unifiable.
case SpvOp::SpvOpSpecConstantOp:
diff --git a/third_party/SPIRV-Tools/source/opt/upgrade_memory_model.cpp b/third_party/SPIRV-Tools/source/opt/upgrade_memory_model.cpp
index ab25205..9d6a5bc 100644
--- a/third_party/SPIRV-Tools/source/opt/upgrade_memory_model.cpp
+++ b/third_party/SPIRV-Tools/source/opt/upgrade_memory_model.cpp
@@ -20,6 +20,7 @@
#include "source/opt/ir_context.h"
#include "source/spirv_constant.h"
#include "source/util/make_unique.h"
+#include "source/util/string_utils.h"
namespace spvtools {
namespace opt {
@@ -58,9 +59,7 @@
std::initializer_list<Operand>{
{SPV_OPERAND_TYPE_CAPABILITY, {SpvCapabilityVulkanMemoryModelKHR}}}));
const std::string extension = "SPV_KHR_vulkan_memory_model";
- std::vector<uint32_t> words(extension.size() / 4 + 1, 0);
- char* dst = reinterpret_cast<char*>(words.data());
- strncpy(dst, extension.c_str(), extension.size());
+ std::vector<uint32_t> words = spvtools::utils::MakeVector(extension);
context()->AddExtension(
MakeUnique<Instruction>(context(), SpvOpExtension, 0, 0,
std::initializer_list<Operand>{
@@ -85,8 +84,7 @@
if (ext_inst == GLSLstd450Modf || ext_inst == GLSLstd450Frexp) {
auto import =
get_def_use_mgr()->GetDef(inst->GetSingleWordInOperand(0u));
- if (reinterpret_cast<char*>(import->GetInOperand(0u).words.data()) ==
- std::string("GLSL.std.450")) {
+ if (import->GetInOperand(0u).AsString() == "GLSL.std.450") {
UpgradeExtInst(inst);
}
}
diff --git a/third_party/SPIRV-Tools/source/opt/vector_dce.h b/third_party/SPIRV-Tools/source/opt/vector_dce.h
index 4d30b92..a55bda6 100644
--- a/third_party/SPIRV-Tools/source/opt/vector_dce.h
+++ b/third_party/SPIRV-Tools/source/opt/vector_dce.h
@@ -73,7 +73,7 @@
bool RewriteInstructions(Function* function,
const LiveComponentMap& live_components);
- // Makrs all DebugValue instructions that use |composite| for their values as
+ // Makes all DebugValue instructions that use |composite| for their values as
// dead instructions by putting them into |dead_dbg_value|.
void MarkDebugValueUsesAsDead(Instruction* composite,
std::vector<Instruction*>* dead_dbg_value);
diff --git a/third_party/SPIRV-Tools/source/parsed_operand.cpp b/third_party/SPIRV-Tools/source/parsed_operand.cpp
index 7ad369c..5f8e94d 100644
--- a/third_party/SPIRV-Tools/source/parsed_operand.cpp
+++ b/third_party/SPIRV-Tools/source/parsed_operand.cpp
@@ -24,7 +24,9 @@
void EmitNumericLiteral(std::ostream* out, const spv_parsed_instruction_t& inst,
const spv_parsed_operand_t& operand) {
if (operand.type != SPV_OPERAND_TYPE_LITERAL_INTEGER &&
- operand.type != SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER)
+ operand.type != SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER &&
+ operand.type != SPV_OPERAND_TYPE_OPTIONAL_LITERAL_INTEGER &&
+ operand.type != SPV_OPERAND_TYPE_OPTIONAL_TYPED_LITERAL_INTEGER)
return;
if (operand.num_words < 1) return;
// TODO(dneto): Support more than 64-bits at a time.
diff --git a/third_party/SPIRV-Tools/source/reduce/remove_struct_member_reduction_opportunity.cpp b/third_party/SPIRV-Tools/source/reduce/remove_struct_member_reduction_opportunity.cpp
index da096e1..e72ed35 100644
--- a/third_party/SPIRV-Tools/source/reduce/remove_struct_member_reduction_opportunity.cpp
+++ b/third_party/SPIRV-Tools/source/reduce/remove_struct_member_reduction_opportunity.cpp
@@ -153,7 +153,7 @@
next_type = type_inst->GetSingleWordInOperand(0);
break;
case SpvOpTypeStruct: {
- // Struct types are special becuase (a) we may need to adjust the index
+ // Struct types are special because (a) we may need to adjust the index
// being used, if the struct type is the one from which we are removing
// a member, and (b) the type encountered by following the current index
// is dependent on the value of the index.
diff --git a/third_party/SPIRV-Tools/source/reduce/remove_unused_struct_member_reduction_opportunity_finder.cpp b/third_party/SPIRV-Tools/source/reduce/remove_unused_struct_member_reduction_opportunity_finder.cpp
index e72be62..cd0c4e4 100644
--- a/third_party/SPIRV-Tools/source/reduce/remove_unused_struct_member_reduction_opportunity_finder.cpp
+++ b/third_party/SPIRV-Tools/source/reduce/remove_unused_struct_member_reduction_opportunity_finder.cpp
@@ -136,9 +136,9 @@
}
}
- // We now know those struct indices that are unsed, and we make a reduction
+ // We now know those struct indices that are unused, and we make a reduction
// opportunity for each of them. By mapping each relevant member index to the
- // structs in which it is unsed, we will group all opportunities to remove
+ // structs in which it is unused, we will group all opportunities to remove
// member k of a struct (for some k) together. This reduces the likelihood
// that opportunities to remove members from the same struct will be adjacent,
// which is good because such opportunities mutually disable one another.
diff --git a/third_party/SPIRV-Tools/source/reduce/structured_construct_to_block_reduction_opportunity_finder.cpp b/third_party/SPIRV-Tools/source/reduce/structured_construct_to_block_reduction_opportunity_finder.cpp
index dc20f68..29fbe55 100644
--- a/third_party/SPIRV-Tools/source/reduce/structured_construct_to_block_reduction_opportunity_finder.cpp
+++ b/third_party/SPIRV-Tools/source/reduce/structured_construct_to_block_reduction_opportunity_finder.cpp
@@ -96,7 +96,7 @@
// This also means that we don't add a region.
continue;
}
- // We have a reachable header block with a rechable merge that
+ // We have a reachable header block with a reachable merge that
// postdominates the header: this means we have a new region.
regions.emplace(&block, std::unordered_set<opt::BasicBlock*>());
}
@@ -128,7 +128,7 @@
if (!block->WhileEachInst(
[context, &header, ®ion](opt::Instruction* inst) -> bool {
if (inst->result_id() == 0) {
- // The instruction does not genreate a result id, thus it cannot
+ // The instruction does not generate a result id, thus it cannot
// be referred to outside the region - this is fine.
return true;
}
diff --git a/third_party/SPIRV-Tools/source/spirv_definition.h b/third_party/SPIRV-Tools/source/spirv_definition.h
index 63a4ef0..5dbd6ab 100644
--- a/third_party/SPIRV-Tools/source/spirv_definition.h
+++ b/third_party/SPIRV-Tools/source/spirv_definition.h
@@ -27,7 +27,7 @@
uint32_t generator;
uint32_t bound;
uint32_t schema; // NOTE: Reserved
- const uint32_t* instructions; // NOTE: Unfixed pointer to instruciton stream
+ const uint32_t* instructions; // NOTE: Unfixed pointer to instruction stream
} spv_header_t;
#endif // SOURCE_SPIRV_DEFINITION_H_
diff --git a/third_party/SPIRV-Tools/source/spirv_endian.h b/third_party/SPIRV-Tools/source/spirv_endian.h
index c2540be..b4927f3 100644
--- a/third_party/SPIRV-Tools/source/spirv_endian.h
+++ b/third_party/SPIRV-Tools/source/spirv_endian.h
@@ -31,7 +31,7 @@
spv_result_t spvBinaryEndianness(const spv_const_binary binary,
spv_endianness_t* endian);
-// Returns true if the given endianness matches the host's native endiannes.
+// Returns true if the given endianness matches the host's native endianness.
bool spvIsHostEndian(spv_endianness_t endian);
#endif // SOURCE_SPIRV_ENDIAN_H_
diff --git a/third_party/SPIRV-Tools/source/spirv_target_env.cpp b/third_party/SPIRV-Tools/source/spirv_target_env.cpp
index 187ab61..9a03817 100644
--- a/third_party/SPIRV-Tools/source/spirv_target_env.cpp
+++ b/third_party/SPIRV-Tools/source/spirv_target_env.cpp
@@ -72,6 +72,10 @@
return "SPIR-V 1.5";
case SPV_ENV_VULKAN_1_2:
return "SPIR-V 1.5 (under Vulkan 1.2 semantics)";
+ case SPV_ENV_UNIVERSAL_1_6:
+ return "SPIR-V 1.6";
+ case SPV_ENV_VULKAN_1_3:
+ return "SPIR-V 1.6 (under Vulkan 1.3 semantics)";
case SPV_ENV_MAX:
assert(false && "Invalid target environment value.");
break;
@@ -113,6 +117,9 @@
case SPV_ENV_UNIVERSAL_1_5:
case SPV_ENV_VULKAN_1_2:
return SPV_SPIRV_VERSION_WORD(1, 5);
+ case SPV_ENV_UNIVERSAL_1_6:
+ case SPV_ENV_VULKAN_1_3:
+ return SPV_SPIRV_VERSION_WORD(1, 6);
case SPV_ENV_MAX:
assert(false && "Invalid target environment value.");
break;
@@ -125,12 +132,14 @@
{"vulkan1.0", SPV_ENV_VULKAN_1_0},
{"vulkan1.1", SPV_ENV_VULKAN_1_1},
{"vulkan1.2", SPV_ENV_VULKAN_1_2},
+ {"vulkan1.3", SPV_ENV_VULKAN_1_3},
{"spv1.0", SPV_ENV_UNIVERSAL_1_0},
{"spv1.1", SPV_ENV_UNIVERSAL_1_1},
{"spv1.2", SPV_ENV_UNIVERSAL_1_2},
{"spv1.3", SPV_ENV_UNIVERSAL_1_3},
{"spv1.4", SPV_ENV_UNIVERSAL_1_4},
{"spv1.5", SPV_ENV_UNIVERSAL_1_5},
+ {"spv1.6", SPV_ENV_UNIVERSAL_1_6},
{"opencl1.2embedded", SPV_ENV_OPENCL_EMBEDDED_1_2},
{"opencl1.2", SPV_ENV_OPENCL_1_2},
{"opencl2.0embedded", SPV_ENV_OPENCL_EMBEDDED_2_0},
@@ -177,7 +186,8 @@
{SPV_ENV_VULKAN_1_0, VULKAN_VER(1, 0), SPIRV_VER(1, 0)},
{SPV_ENV_VULKAN_1_1, VULKAN_VER(1, 1), SPIRV_VER(1, 3)},
{SPV_ENV_VULKAN_1_1_SPIRV_1_4, VULKAN_VER(1, 1), SPIRV_VER(1, 4)},
- {SPV_ENV_VULKAN_1_2, VULKAN_VER(1, 2), SPIRV_VER(1, 5)}};
+ {SPV_ENV_VULKAN_1_2, VULKAN_VER(1, 2), SPIRV_VER(1, 5)},
+ {SPV_ENV_VULKAN_1_3, VULKAN_VER(1, 3), SPIRV_VER(1, 6)}};
bool spvParseVulkanEnv(uint32_t vulkan_ver, uint32_t spirv_ver,
spv_target_env* env) {
@@ -211,11 +221,13 @@
case SPV_ENV_UNIVERSAL_1_3:
case SPV_ENV_UNIVERSAL_1_4:
case SPV_ENV_UNIVERSAL_1_5:
+ case SPV_ENV_UNIVERSAL_1_6:
return false;
case SPV_ENV_VULKAN_1_0:
case SPV_ENV_VULKAN_1_1:
case SPV_ENV_VULKAN_1_1_SPIRV_1_4:
case SPV_ENV_VULKAN_1_2:
+ case SPV_ENV_VULKAN_1_3:
return true;
case SPV_ENV_WEBGPU_0:
assert(false && "Deprecated target environment value.");
@@ -244,6 +256,8 @@
case SPV_ENV_VULKAN_1_1_SPIRV_1_4:
case SPV_ENV_UNIVERSAL_1_5:
case SPV_ENV_VULKAN_1_2:
+ case SPV_ENV_UNIVERSAL_1_6:
+ case SPV_ENV_VULKAN_1_3:
return false;
case SPV_ENV_OPENCL_1_2:
case SPV_ENV_OPENCL_EMBEDDED_1_2:
@@ -284,6 +298,8 @@
case SPV_ENV_VULKAN_1_1_SPIRV_1_4:
case SPV_ENV_UNIVERSAL_1_5:
case SPV_ENV_VULKAN_1_2:
+ case SPV_ENV_UNIVERSAL_1_6:
+ case SPV_ENV_VULKAN_1_3:
return false;
case SPV_ENV_OPENGL_4_0:
case SPV_ENV_OPENGL_4_1:
@@ -321,6 +337,8 @@
case SPV_ENV_VULKAN_1_1_SPIRV_1_4:
case SPV_ENV_UNIVERSAL_1_5:
case SPV_ENV_VULKAN_1_2:
+ case SPV_ENV_UNIVERSAL_1_6:
+ case SPV_ENV_VULKAN_1_3:
case SPV_ENV_OPENGL_4_0:
case SPV_ENV_OPENGL_4_1:
case SPV_ENV_OPENGL_4_2:
@@ -355,16 +373,18 @@
}
case SPV_ENV_VULKAN_1_0:
case SPV_ENV_VULKAN_1_1:
- case SPV_ENV_VULKAN_1_1_SPIRV_1_4: {
- case SPV_ENV_VULKAN_1_2:
- return "Vulkan";
+ case SPV_ENV_VULKAN_1_1_SPIRV_1_4:
+ case SPV_ENV_VULKAN_1_2:
+ case SPV_ENV_VULKAN_1_3: {
+ return "Vulkan";
}
case SPV_ENV_UNIVERSAL_1_0:
case SPV_ENV_UNIVERSAL_1_1:
case SPV_ENV_UNIVERSAL_1_2:
case SPV_ENV_UNIVERSAL_1_3:
case SPV_ENV_UNIVERSAL_1_4:
- case SPV_ENV_UNIVERSAL_1_5: {
+ case SPV_ENV_UNIVERSAL_1_5:
+ case SPV_ENV_UNIVERSAL_1_6: {
return "Universal";
}
case SPV_ENV_WEBGPU_0:
diff --git a/third_party/SPIRV-Tools/source/spirv_target_env.h b/third_party/SPIRV-Tools/source/spirv_target_env.h
index cc06dec..f3b0c2f 100644
--- a/third_party/SPIRV-Tools/source/spirv_target_env.h
+++ b/third_party/SPIRV-Tools/source/spirv_target_env.h
@@ -40,7 +40,7 @@
// Returns a formatted list of all SPIR-V target environment names that
// can be parsed by spvParseTargetEnv.
-// |pad| is the number of space characters that the begining of each line
+// |pad| is the number of space characters that the beginning of each line
// except the first one will be padded with.
// |wrap| is the max length of lines the user desires. Word-wrapping will
// occur to satisfy this limit.
diff --git a/third_party/SPIRV-Tools/source/table.cpp b/third_party/SPIRV-Tools/source/table.cpp
index d4a2d7e..822cefe 100644
--- a/third_party/SPIRV-Tools/source/table.cpp
+++ b/third_party/SPIRV-Tools/source/table.cpp
@@ -41,6 +41,8 @@
case SPV_ENV_UNIVERSAL_1_4:
case SPV_ENV_UNIVERSAL_1_5:
case SPV_ENV_VULKAN_1_2:
+ case SPV_ENV_UNIVERSAL_1_6:
+ case SPV_ENV_VULKAN_1_3:
break;
default:
return nullptr;
diff --git a/third_party/SPIRV-Tools/source/text.cpp b/third_party/SPIRV-Tools/source/text.cpp
index 88a8e8f..415c059 100644
--- a/third_party/SPIRV-Tools/source/text.cpp
+++ b/third_party/SPIRV-Tools/source/text.cpp
@@ -715,6 +715,12 @@
while (context.hasText()) {
spv_instruction_t inst;
+ // Operand parsing sometimes involves knowing the opcode of the instruction
+ // being parsed. A malformed input might feature such an operand *before*
+ // the opcode is known. To guard against accessing an uninitialized opcode,
+ // the instruction's opcode is initialized to a default value.
+ inst.opcode = SpvOpMax;
+
if (spvTextEncodeOpcode(grammar, &context, &inst)) {
return SPV_ERROR_INVALID_TEXT;
}
diff --git a/third_party/SPIRV-Tools/source/text_handler.cpp b/third_party/SPIRV-Tools/source/text_handler.cpp
index 46b9845..fe12a26 100644
--- a/third_party/SPIRV-Tools/source/text_handler.cpp
+++ b/third_party/SPIRV-Tools/source/text_handler.cpp
@@ -29,6 +29,7 @@
#include "source/util/bitutils.h"
#include "source/util/hex_float.h"
#include "source/util/parse_number.h"
+#include "source/util/string_utils.h"
namespace spvtools {
namespace {
@@ -307,14 +308,8 @@
<< SPV_LIMIT_INSTRUCTION_WORD_COUNT_MAX << " words.";
}
- pInst->words.resize(newWordCount);
-
- // Make sure all the bytes in the last word are 0, in case we only
- // write a partial word at the end.
- pInst->words.back() = 0;
-
- char* dest = (char*)&pInst->words[oldWordCount];
- strncpy(dest, value, length + 1);
+ pInst->words.reserve(newWordCount);
+ spvtools::utils::AppendToVector(value, &pInst->words);
return SPV_SUCCESS;
}
diff --git a/third_party/SPIRV-Tools/source/util/bit_vector.h b/third_party/SPIRV-Tools/source/util/bit_vector.h
index 3e189cb..826d62f 100644
--- a/third_party/SPIRV-Tools/source/util/bit_vector.h
+++ b/third_party/SPIRV-Tools/source/util/bit_vector.h
@@ -32,7 +32,7 @@
enum { kInitialNumBits = 1024 };
public:
- // Creates a bit vector contianing 0s.
+ // Creates a bit vector containing 0s.
BitVector(uint32_t reserved_size = kInitialNumBits)
: bits_((reserved_size - 1) / kBitContainerSize + 1, 0) {}
diff --git a/third_party/SPIRV-Tools/source/util/hash_combine.h b/third_party/SPIRV-Tools/source/util/hash_combine.h
new file mode 100644
index 0000000..1a2dbc3
--- /dev/null
+++ b/third_party/SPIRV-Tools/source/util/hash_combine.h
@@ -0,0 +1,53 @@
+// Copyright (c) 2022 The Khronos Group Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SOURCE_UTIL_HASH_COMBINE_H_
+#define SOURCE_UTIL_HASH_COMBINE_H_
+
+#include <cstddef>
+#include <functional>
+#include <vector>
+
+namespace spvtools {
+namespace utils {
+
+// Helpers for incrementally computing hashes.
+// For reference, see
+// http://open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3876.pdf
+
+template <typename T>
+inline size_t hash_combine(std::size_t seed, const T& val) {
+ return seed ^ (std::hash<T>()(val) + 0x9e3779b9 + (seed << 6) + (seed >> 2));
+}
+
+template <typename T>
+inline size_t hash_combine(std::size_t hash, const std::vector<T>& vals) {
+ for (const T& val : vals) {
+ hash = hash_combine(hash, val);
+ }
+ return hash;
+}
+
+inline size_t hash_combine(std::size_t hash) { return hash; }
+
+template <typename T, typename... Types>
+inline size_t hash_combine(std::size_t hash, const T& val,
+ const Types&... args) {
+ return hash_combine(hash_combine(hash, val), args...);
+}
+
+} // namespace utils
+} // namespace spvtools
+
+#endif // SOURCE_UTIL_HASH_COMBINE_H_
diff --git a/third_party/SPIRV-Tools/source/util/hex_float.h b/third_party/SPIRV-Tools/source/util/hex_float.h
index be28eae..903b628 100644
--- a/third_party/SPIRV-Tools/source/util/hex_float.h
+++ b/third_party/SPIRV-Tools/source/util/hex_float.h
@@ -199,7 +199,7 @@
// Reads a FloatProxy value as a normal float from a stream.
template <typename T>
std::istream& operator>>(std::istream& is, FloatProxy<T>& value) {
- T float_val;
+ T float_val = static_cast<T>(0.0);
is >> float_val;
value = FloatProxy<T>(float_val);
return is;
diff --git a/third_party/SPIRV-Tools/source/util/ilist.h b/third_party/SPIRV-Tools/source/util/ilist.h
index 9837b09..b7ecf01 100644
--- a/third_party/SPIRV-Tools/source/util/ilist.h
+++ b/third_party/SPIRV-Tools/source/util/ilist.h
@@ -59,7 +59,7 @@
// Moves the contents of the given list to the list being constructed.
IntrusiveList(IntrusiveList&&);
- // Destorys the list. Note that the elements of the list will not be deleted,
+ // Destroys the list. Note that the elements of the list will not be deleted,
// but they will be removed from the list.
virtual ~IntrusiveList();
diff --git a/third_party/SPIRV-Tools/source/util/parse_number.h b/third_party/SPIRV-Tools/source/util/parse_number.h
index 729aac5..d0f2a09 100644
--- a/third_party/SPIRV-Tools/source/util/parse_number.h
+++ b/third_party/SPIRV-Tools/source/util/parse_number.h
@@ -220,7 +220,7 @@
std::function<void(uint32_t)> emit, std::string* error_msg);
// Parses a floating point value of a given |type| from the given |text| and
-// encodes the number by the given |emit| funciton. On success, returns
+// encodes the number by the given |emit| function. On success, returns
// EncodeNumberStatus::kSuccess and the parsed number will be consumed by the
// given |emit| function word by word (least significant word first). On
// failure, this function returns the error code of the encoding status and
diff --git a/third_party/SPIRV-Tools/source/util/pooled_linked_list.h b/third_party/SPIRV-Tools/source/util/pooled_linked_list.h
new file mode 100644
index 0000000..faaa4c4
--- /dev/null
+++ b/third_party/SPIRV-Tools/source/util/pooled_linked_list.h
@@ -0,0 +1,236 @@
+// Copyright (c) 2021 The Khronos Group Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SOURCE_UTIL_POOLED_LINKED_LIST_H_
+#define SOURCE_UTIL_POOLED_LINKED_LIST_H_
+
+#include <cstdint>
+#include <vector>
+
+namespace spvtools {
+namespace utils {
+
+// Shared storage of nodes for PooledLinkedList.
+template <typename T>
+class PooledLinkedListNodes {
+ public:
+ struct Node {
+ Node(T e, int32_t n = -1) : element(e), next(n) {}
+
+ T element = {};
+ int32_t next = -1;
+ };
+
+ PooledLinkedListNodes() = default;
+ PooledLinkedListNodes(const PooledLinkedListNodes&) = delete;
+ PooledLinkedListNodes& operator=(const PooledLinkedListNodes&) = delete;
+
+ PooledLinkedListNodes(PooledLinkedListNodes&& that) {
+ *this = std::move(that);
+ }
+
+ PooledLinkedListNodes& operator=(PooledLinkedListNodes&& that) {
+ vec_ = std::move(that.vec_);
+ free_nodes_ = that.free_nodes_;
+ return *this;
+ }
+
+ size_t total_nodes() { return vec_.size(); }
+ size_t free_nodes() { return free_nodes_; }
+ size_t used_nodes() { return total_nodes() - free_nodes(); }
+
+ private:
+ template <typename ListT>
+ friend class PooledLinkedList;
+
+ Node& at(int32_t index) { return vec_[index]; }
+ const Node& at(int32_t index) const { return vec_[index]; }
+
+ int32_t insert(T element) {
+ int32_t index = int32_t(vec_.size());
+ vec_.emplace_back(element);
+ return index;
+ }
+
+ std::vector<Node> vec_;
+ size_t free_nodes_ = 0;
+};
+
+// Implements a linked-list where list nodes come from a shared pool. This is
+// meant to be used in scenarios where it is desirable to avoid many small
+// allocations.
+//
+// Instead of pointers, the list uses indices to allow the underlying storage
+// to be modified without needing to modify the list. When removing elements
+// from the list, nodes are not deleted or recycled: to reclaim unused space,
+// perform a sequence of |move_nodes| operations into a temporary pool, which
+// then is moved into the old pool.
+//
+// This does *not* attempt to implement a full stl-compatible interface.
+template <typename T>
+class PooledLinkedList {
+ public:
+ using NodePool = PooledLinkedListNodes<T>;
+ using Node = typename NodePool::Node;
+
+ PooledLinkedList() = delete;
+ PooledLinkedList(NodePool* nodes) : nodes_(nodes) {}
+
+ // Shared iterator implementation (for iterator and const_iterator).
+ template <typename ElementT, typename PoolT>
+ class iterator_base {
+ public:
+ iterator_base(const iterator_base& i)
+ : nodes_(i.nodes_), index_(i.index_) {}
+
+ iterator_base& operator++() {
+ index_ = nodes_->at(index_).next;
+ return *this;
+ }
+
+ iterator_base& operator=(const iterator_base& i) {
+ nodes_ = i.nodes_;
+ index_ = i.index_;
+ return *this;
+ }
+
+ ElementT& operator*() const { return nodes_->at(index_).element; }
+ ElementT* operator->() const { return &nodes_->at(index_).element; }
+
+ friend inline bool operator==(const iterator_base& lhs,
+ const iterator_base& rhs) {
+ return lhs.nodes_ == rhs.nodes_ && lhs.index_ == rhs.index_;
+ }
+ friend inline bool operator!=(const iterator_base& lhs,
+ const iterator_base& rhs) {
+ return lhs.nodes_ != rhs.nodes_ || lhs.index_ != rhs.index_;
+ }
+
+ // Define standard iterator types needs so this class can be
+ // used with <algorithms>.
+ using iterator_category = std::forward_iterator_tag;
+ using difference_type = std::ptrdiff_t;
+ using value_type = ElementT;
+ using pointer = ElementT*;
+ using const_pointer = const ElementT*;
+ using reference = ElementT&;
+ using const_reference = const ElementT&;
+ using size_type = size_t;
+
+ private:
+ friend PooledLinkedList;
+
+ iterator_base(PoolT* pool, int32_t index) : nodes_(pool), index_(index) {}
+
+ PoolT* nodes_;
+ int32_t index_ = -1;
+ };
+
+ using iterator = iterator_base<T, std::vector<Node>>;
+ using const_iterator = iterator_base<const T, const std::vector<Node>>;
+
+ bool empty() const { return head_ == -1; }
+
+ T& front() { return nodes_->at(head_).element; }
+ T& back() { return nodes_->at(tail_).element; }
+ const T& front() const { return nodes_->at(head_).element; }
+ const T& back() const { return nodes_->at(tail_).element; }
+
+ iterator begin() { return iterator(&nodes_->vec_, head_); }
+ iterator end() { return iterator(&nodes_->vec_, -1); }
+ const_iterator begin() const { return const_iterator(&nodes_->vec_, head_); }
+ const_iterator end() const { return const_iterator(&nodes_->vec_, -1); }
+
+ // Inserts |element| at the back of the list.
+ void push_back(T element) {
+ int32_t new_tail = nodes_->insert(element);
+ if (head_ == -1) {
+ head_ = new_tail;
+ tail_ = new_tail;
+ } else {
+ nodes_->at(tail_).next = new_tail;
+ tail_ = new_tail;
+ }
+ }
+
+ // Removes the first occurrence of |element| from the list.
+ // Returns if |element| was removed.
+ bool remove_first(T element) {
+ int32_t* prev_next = &head_;
+ for (int32_t prev_index = -1, index = head_; index != -1; /**/) {
+ auto& node = nodes_->at(index);
+ if (node.element == element) {
+ // Snip from of the list, optionally fixing up tail pointer.
+ if (tail_ == index) {
+ assert(node.next == -1);
+ tail_ = prev_index;
+ }
+ *prev_next = node.next;
+ nodes_->free_nodes_++;
+ return true;
+ } else {
+ prev_next = &node.next;
+ }
+ prev_index = index;
+ index = node.next;
+ }
+ return false;
+ }
+
+ // Returns the PooledLinkedListNodes that owns this list's nodes.
+ NodePool* pool() { return nodes_; }
+
+ // Moves the nodes in this list into |new_pool|, providing a way to compact
+ // storage and reclaim unused space.
+ //
+ // Upon completing a sequence of |move_nodes| calls, you must ensure you
+ // retain ownership of the new storage your lists point to. Example usage:
+ //
+ // unique_ptr<NodePool> new_pool = ...;
+ // for (PooledLinkedList& list : lists) {
+ // list.move_to(new_pool);
+ // }
+ // my_pool_ = std::move(new_pool);
+ void move_nodes(NodePool* new_pool) {
+ // Be sure to construct the list in the same order, instead of simply
+ // doing a sequence of push_backs.
+ int32_t prev_entry = -1;
+ int32_t nodes_freed = 0;
+ for (int32_t index = head_; index != -1; nodes_freed++) {
+ const auto& node = nodes_->at(index);
+ int32_t this_entry = new_pool->insert(node.element);
+ index = node.next;
+ if (prev_entry == -1) {
+ head_ = this_entry;
+ } else {
+ new_pool->at(prev_entry).next = this_entry;
+ }
+ prev_entry = this_entry;
+ }
+ tail_ = prev_entry;
+ // Update our old pool's free count, now we're a member of the new pool.
+ nodes_->free_nodes_ += nodes_freed;
+ nodes_ = new_pool;
+ }
+
+ private:
+ NodePool* nodes_;
+ int32_t head_ = -1;
+ int32_t tail_ = -1;
+};
+
+} // namespace utils
+} // namespace spvtools
+
+#endif // SOURCE_UTIL_POOLED_LINKED_LIST_H_
\ No newline at end of file
diff --git a/third_party/SPIRV-Tools/source/util/small_vector.h b/third_party/SPIRV-Tools/source/util/small_vector.h
index f2c1147..648a348 100644
--- a/third_party/SPIRV-Tools/source/util/small_vector.h
+++ b/third_party/SPIRV-Tools/source/util/small_vector.h
@@ -64,6 +64,11 @@
}
}
+ template <class InputIt>
+ SmallVector(InputIt first, InputIt last) : SmallVector() {
+ insert(end(), first, last);
+ }
+
SmallVector(std::vector<T>&& vec) : SmallVector() {
if (vec.size() > small_size) {
large_data_ = MakeUnique<std::vector<T>>(std::move(vec));
@@ -175,9 +180,12 @@
return true;
}
+// Avoid infinite recursion from rewritten operators in C++20
+#if __cplusplus <= 201703L
friend bool operator==(const std::vector<T>& lhs, const SmallVector& rhs) {
return rhs == lhs;
}
+#endif
friend bool operator!=(const SmallVector& lhs, const std::vector<T>& rhs) {
return !(lhs == rhs);
@@ -325,6 +333,15 @@
++size_;
}
+ void pop_back() {
+ if (large_data_) {
+ large_data_->pop_back();
+ } else {
+ --size_;
+ small_data_[size_].~T();
+ }
+ }
+
template <class InputIt>
iterator insert(iterator pos, InputIt first, InputIt last) {
size_t element_idx = (pos - begin());
@@ -363,7 +380,7 @@
}
}
- // Upate the size.
+ // Update the size.
size_ += num_of_new_elements;
return pos;
}
@@ -449,7 +466,7 @@
T* small_data_;
// The actual data used to store the array elements. It must never be used
- // directly, but must only be accesed through |small_data_|.
+ // directly, but must only be accessed through |small_data_|.
typename std::aligned_storage<sizeof(T), std::alignment_of<T>::value>::type
buffer[small_size];
diff --git a/third_party/SPIRV-Tools/source/util/string_utils.h b/third_party/SPIRV-Tools/source/util/string_utils.h
index 4282aa9..03e20b3 100644
--- a/third_party/SPIRV-Tools/source/util/string_utils.h
+++ b/third_party/SPIRV-Tools/source/util/string_utils.h
@@ -16,6 +16,8 @@
#define SOURCE_UTIL_STRING_UTILS_H_
#include <assert.h>
+
+#include <cstring>
#include <sstream>
#include <string>
#include <vector>
@@ -44,9 +46,10 @@
// string will be empty.
std::pair<std::string, std::string> SplitFlagArgs(const std::string& flag);
-// Encodes a string as a sequence of words, using the SPIR-V encoding.
-inline std::vector<uint32_t> MakeVector(std::string input) {
- std::vector<uint32_t> result;
+// Encodes a string as a sequence of words, using the SPIR-V encoding, appending
+// to an existing vector.
+inline void AppendToVector(const std::string& input,
+ std::vector<uint32_t>* result) {
uint32_t word = 0;
size_t num_bytes = input.size();
// SPIR-V strings are null-terminated. The byte_index == num_bytes
@@ -56,24 +59,36 @@
(byte_index < num_bytes ? uint8_t(input[byte_index]) : uint8_t(0));
word |= (new_byte << (8 * (byte_index % sizeof(uint32_t))));
if (3 == (byte_index % sizeof(uint32_t))) {
- result.push_back(word);
+ result->push_back(word);
word = 0;
}
}
// Emit a trailing partial word.
if ((num_bytes + 1) % sizeof(uint32_t)) {
- result.push_back(word);
+ result->push_back(word);
}
+}
+
+// Encodes a string as a sequence of words, using the SPIR-V encoding.
+inline std::vector<uint32_t> MakeVector(const std::string& input) {
+ std::vector<uint32_t> result;
+ AppendToVector(input, &result);
return result;
}
-// Decode a string from a sequence of words, using the SPIR-V encoding.
-template <class VectorType>
-inline std::string MakeString(const VectorType& words) {
+// Decode a string from a sequence of words between first and last, using the
+// SPIR-V encoding. Assert that a terminating 0-byte was found (unless
+// assert_found_terminating_null is passed as false).
+template <class InputIt>
+inline std::string MakeString(InputIt first, InputIt last,
+ bool assert_found_terminating_null = true) {
std::string result;
+ constexpr size_t kCharsPerWord = sizeof(*first);
+ static_assert(kCharsPerWord == 4, "expect 4-byte word");
- for (uint32_t word : words) {
- for (int byte_index = 0; byte_index < 4; byte_index++) {
+ for (InputIt pos = first; pos != last; ++pos) {
+ uint32_t word = *pos;
+ for (size_t byte_index = 0; byte_index < kCharsPerWord; byte_index++) {
uint32_t extracted_word = (word >> (8 * byte_index)) & 0xFF;
char c = static_cast<char>(extracted_word);
if (c == 0) {
@@ -82,9 +97,33 @@
result += c;
}
}
- assert(false && "Did not find terminating null for the string.");
+ assert(!assert_found_terminating_null &&
+ "Did not find terminating null for the string.");
+ (void)assert_found_terminating_null; /* No unused parameters in release
+ builds. */
return result;
-} // namespace utils
+}
+
+// Decode a string from a sequence of words in a vector, using the SPIR-V
+// encoding.
+template <class VectorType>
+inline std::string MakeString(const VectorType& words,
+ bool assert_found_terminating_null = true) {
+ return MakeString(words.cbegin(), words.cend(),
+ assert_found_terminating_null);
+}
+
+// Decode a string from array words, consuming up to count words, using the
+// SPIR-V encoding.
+inline std::string MakeString(const uint32_t* words, size_t num_words,
+ bool assert_found_terminating_null = true) {
+ return MakeString(words, words + num_words, assert_found_terminating_null);
+}
+
+// Check if str starts with prefix (only included since C++20)
+inline bool starts_with(const std::string& str, const char* prefix) {
+ return 0 == str.compare(0, std::strlen(prefix), prefix);
+}
} // namespace utils
} // namespace spvtools
diff --git a/third_party/SPIRV-Tools/source/util/timer.h b/third_party/SPIRV-Tools/source/util/timer.h
index fc4b747..0808311 100644
--- a/third_party/SPIRV-Tools/source/util/timer.h
+++ b/third_party/SPIRV-Tools/source/util/timer.h
@@ -206,16 +206,16 @@
// Variable to save the result of clock_gettime(CLOCK_PROCESS_CPUTIME_ID) when
// Timer::Stop() is called. It is used as the last status of CPU time. The
- // resouce usage is measured by subtracting |cpu_before_| from it.
+ // resource usage is measured by subtracting |cpu_before_| from it.
timespec cpu_after_;
// Variable to save the result of clock_gettime(CLOCK_MONOTONIC) when
// Timer::Stop() is called. It is used as the last status of WALL time. The
- // resouce usage is measured by subtracting |wall_before_| from it.
+ // resource usage is measured by subtracting |wall_before_| from it.
timespec wall_after_;
// Variable to save the result of getrusage() when Timer::Stop() is called. It
- // is used as the last status of USR time, SYS time, and RSS. Those resouce
+ // is used as the last status of USR time, SYS time, and RSS. Those resource
// usages are measured by subtracting |usage_before_| from it.
rusage usage_after_;
diff --git a/third_party/SPIRV-Tools/source/val/basic_block.h b/third_party/SPIRV-Tools/source/val/basic_block.h
index 5af4b9e..47cd06d 100644
--- a/third_party/SPIRV-Tools/source/val/basic_block.h
+++ b/third_party/SPIRV-Tools/source/val/basic_block.h
@@ -84,26 +84,26 @@
type_.set(type);
}
- /// Sets the immedate dominator of this basic block
+ /// Sets the immediate dominator of this basic block
///
/// @param[in] dom_block The dominator block
void SetImmediateDominator(BasicBlock* dom_block);
- /// Sets the immedate post dominator of this basic block
+ /// Sets the immediate post dominator of this basic block
///
/// @param[in] pdom_block The post dominator block
void SetImmediatePostDominator(BasicBlock* pdom_block);
- /// Returns the immedate dominator of this basic block
+ /// Returns the immediate dominator of this basic block
BasicBlock* immediate_dominator();
- /// Returns the immedate dominator of this basic block
+ /// Returns the immediate dominator of this basic block
const BasicBlock* immediate_dominator() const;
- /// Returns the immedate post dominator of this basic block
+ /// Returns the immediate post dominator of this basic block
BasicBlock* immediate_post_dominator();
- /// Returns the immedate post dominator of this basic block
+ /// Returns the immediate post dominator of this basic block
const BasicBlock* immediate_post_dominator() const;
/// Returns the label instruction for the block, or nullptr if not set.
diff --git a/third_party/SPIRV-Tools/source/val/function.cpp b/third_party/SPIRV-Tools/source/val/function.cpp
index 9ad68e8..f3292b0 100644
--- a/third_party/SPIRV-Tools/source/val/function.cpp
+++ b/third_party/SPIRV-Tools/source/val/function.cpp
@@ -57,7 +57,7 @@
uint32_t type_id) {
assert(current_block_ == nullptr &&
"RegisterFunctionParameter can only be called when parsing the binary "
- "ouside of a block");
+ "outside of a block");
// TODO(umar): Validate function parameter type order and count
// TODO(umar): Use these variables to validate parameter type
(void)parameter_id;
@@ -130,7 +130,7 @@
undefined_blocks_.erase(block_id);
current_block_ = &inserted_block->second;
ordered_blocks_.push_back(current_block_);
- } else if (success) { // Block doesn't exsist but this is not a definition
+ } else if (success) { // Block doesn't exist but this is not a definition
undefined_blocks_.insert(block_id);
}
diff --git a/third_party/SPIRV-Tools/source/val/function.h b/third_party/SPIRV-Tools/source/val/function.h
index 400bb63..2fe30bd 100644
--- a/third_party/SPIRV-Tools/source/val/function.h
+++ b/third_party/SPIRV-Tools/source/val/function.h
@@ -73,8 +73,8 @@
/// Registers a variable in the current block
///
- /// @param[in] type_id The type ID of the varaible
- /// @param[in] id The ID of the varaible
+ /// @param[in] type_id The type ID of the variable
+ /// @param[in] id The ID of the variable
/// @param[in] storage The storage of the variable
/// @param[in] init_id The initializer ID of the variable
///
@@ -197,10 +197,10 @@
/// been identified and dominators have been computed.
int GetBlockDepth(BasicBlock* bb);
- /// Prints a GraphViz digraph of the CFG of the current funciton
+ /// Prints a GraphViz digraph of the CFG of the current function
void PrintDotGraph() const;
- /// Prints a directed graph of the CFG of the current funciton
+ /// Prints a directed graph of the CFG of the current function
void PrintBlocks() const;
/// Registers execution model limitation such as "Feature X is only available
@@ -285,7 +285,7 @@
/// The type of the return value
uint32_t result_type_id_;
- /// The control fo the funciton
+ /// The control fo the function
SpvFunctionControlMask function_control_;
/// The type of declaration of each function
diff --git a/third_party/SPIRV-Tools/source/val/instruction.cpp b/third_party/SPIRV-Tools/source/val/instruction.cpp
index b915589..f16fcd7 100644
--- a/third_party/SPIRV-Tools/source/val/instruction.cpp
+++ b/third_party/SPIRV-Tools/source/val/instruction.cpp
@@ -16,6 +16,9 @@
#include <utility>
+#include "source/binary.h"
+#include "source/util/string_utils.h"
+
namespace spvtools {
namespace val {
@@ -41,5 +44,12 @@
return lhs.id() == rhs;
}
+template <>
+std::string Instruction::GetOperandAs<std::string>(size_t index) const {
+ const spv_parsed_operand_t& o = operands_.at(index);
+ assert(o.offset + o.num_words <= inst_.num_words);
+ return spvtools::utils::MakeString(words_.data() + o.offset, o.num_words);
+}
+
} // namespace val
} // namespace spvtools
diff --git a/third_party/SPIRV-Tools/source/val/instruction.h b/third_party/SPIRV-Tools/source/val/instruction.h
index 617cb06..6d1f9f4 100644
--- a/third_party/SPIRV-Tools/source/val/instruction.h
+++ b/third_party/SPIRV-Tools/source/val/instruction.h
@@ -133,6 +133,9 @@
bool operator==(const Instruction& lhs, const Instruction& rhs);
bool operator==(const Instruction& lhs, uint32_t rhs);
+template <>
+std::string Instruction::GetOperandAs<std::string>(size_t index) const;
+
} // namespace val
} // namespace spvtools
diff --git a/third_party/SPIRV-Tools/source/val/validate.cpp b/third_party/SPIRV-Tools/source/val/validate.cpp
index 45b6a46..ecc9fdb 100644
--- a/third_party/SPIRV-Tools/source/val/validate.cpp
+++ b/third_party/SPIRV-Tools/source/val/validate.cpp
@@ -202,7 +202,7 @@
/* diagnostic = */ nullptr);
// Parse the module and perform inline validation checks. These checks do
- // not require the the knowledge of the whole module.
+ // not require the knowledge of the whole module.
if (auto error = spvBinaryParse(&context, vstate, words, num_words,
/*parsed_header =*/nullptr,
ProcessInstruction, pDiagnostic)) {
@@ -219,9 +219,7 @@
if (inst->opcode() == SpvOpEntryPoint) {
const auto entry_point = inst->GetOperandAs<uint32_t>(1);
const auto execution_model = inst->GetOperandAs<SpvExecutionModel>(0);
- const char* str = reinterpret_cast<const char*>(
- inst->words().data() + inst->operand(2).offset);
- const std::string desc_name(str);
+ const std::string desc_name = inst->GetOperandAs<std::string>(2);
ValidationState_t::EntryPointDescription desc;
desc.name = desc_name;
@@ -237,9 +235,8 @@
for (const Instruction* check_inst : visited_entry_points) {
const auto check_execution_model =
check_inst->GetOperandAs<SpvExecutionModel>(0);
- const char* check_str = reinterpret_cast<const char*>(
- check_inst->words().data() + inst->operand(2).offset);
- const std::string check_name(check_str);
+ const std::string check_name =
+ check_inst->GetOperandAs<std::string>(2);
if (desc_name == check_name &&
execution_model == check_execution_model) {
@@ -351,7 +348,7 @@
}
// Validate the preconditions involving adjacent instructions. e.g. SpvOpPhi
- // must only be preceeded by SpvOpLabel, SpvOpPhi, or SpvOpLine.
+ // must only be preceded by SpvOpLabel, SpvOpPhi, or SpvOpLine.
if (auto error = ValidateAdjacency(*vstate)) return error;
if (auto error = ValidateEntryPoints(*vstate)) return error;
diff --git a/third_party/SPIRV-Tools/source/val/validate.h b/third_party/SPIRV-Tools/source/val/validate.h
index 3fc183d..cb1d05a 100644
--- a/third_party/SPIRV-Tools/source/val/validate.h
+++ b/third_party/SPIRV-Tools/source/val/validate.h
@@ -70,7 +70,7 @@
///
/// This function will iterate over all instructions and check for any required
/// predecessor and/or successor instructions. e.g. SpvOpPhi must only be
-/// preceeded by SpvOpLabel, SpvOpPhi, or SpvOpLine.
+/// preceded by SpvOpLabel, SpvOpPhi, or SpvOpLine.
///
/// @param[in] _ the validation state of the module
///
diff --git a/third_party/SPIRV-Tools/source/val/validate_arithmetics.cpp b/third_party/SPIRV-Tools/source/val/validate_arithmetics.cpp
index 433330d..bae9b5d 100644
--- a/third_party/SPIRV-Tools/source/val/validate_arithmetics.cpp
+++ b/third_party/SPIRV-Tools/source/val/validate_arithmetics.cpp
@@ -155,7 +155,7 @@
first_vector_num_components = num_components;
} else if (num_components != first_vector_num_components) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
- << "Expected operands to have the same number of componenets: "
+ << "Expected operands to have the same number of components: "
<< spvOpcodeString(opcode);
}
}
diff --git a/third_party/SPIRV-Tools/source/val/validate_cfg.cpp b/third_party/SPIRV-Tools/source/val/validate_cfg.cpp
index 7842e56..88abd75 100644
--- a/third_party/SPIRV-Tools/source/val/validate_cfg.cpp
+++ b/third_party/SPIRV-Tools/source/val/validate_cfg.cpp
@@ -27,6 +27,7 @@
#include "source/cfa.h"
#include "source/opcode.h"
+#include "source/spirv_constant.h"
#include "source/spirv_target_env.h"
#include "source/spirv_validator_options.h"
#include "source/val/basic_block.h"
@@ -191,6 +192,12 @@
"ID of an OpLabel instruction";
}
+ if (_.version() >= SPV_SPIRV_VERSION_WORD(1, 6) && true_id == false_id) {
+ return _.diag(SPV_ERROR_INVALID_ID, inst)
+ << "In SPIR-V 1.6 or later, True Label and False Label must be "
+ "different labels";
+ }
+
return SPV_SUCCESS;
}
@@ -668,7 +675,7 @@
} else if (terminator->opcode() == SpvOpSwitch) {
if (!merge) {
return _.diag(SPV_ERROR_INVALID_CFG, terminator)
- << "OpSwitch must be preceeded by an OpSelectionMerge "
+ << "OpSwitch must be preceded by an OpSelectionMerge "
"instruction";
}
// Mark the targets as seen.
@@ -910,7 +917,7 @@
}
}
}
- // If we have structed control flow, check that no block has a control
+ // If we have structured control flow, check that no block has a control
// flow nesting depth larger than the limit.
if (_.HasCapability(SpvCapabilityShader)) {
const int control_flow_nesting_depth_limit =
diff --git a/third_party/SPIRV-Tools/source/val/validate_decorations.cpp b/third_party/SPIRV-Tools/source/val/validate_decorations.cpp
index 3cdb471..eb6caf0 100644
--- a/third_party/SPIRV-Tools/source/val/validate_decorations.cpp
+++ b/third_party/SPIRV-Tools/source/val/validate_decorations.cpp
@@ -21,11 +21,13 @@
#include <utility>
#include <vector>
+#include "source/binary.h"
#include "source/diagnostic.h"
#include "source/opcode.h"
#include "source/spirv_constant.h"
#include "source/spirv_target_env.h"
#include "source/spirv_validator_options.h"
+#include "source/util/string_utils.h"
#include "source/val/validate_scopes.h"
#include "source/val/validation_state.h"
@@ -96,6 +98,14 @@
});
}
+// Returns true if the given structure type has a Block decoration.
+bool isBlock(uint32_t struct_id, ValidationState_t& vstate) {
+ const auto& decorations = vstate.id_decorations(struct_id);
+ return std::any_of(
+ decorations.begin(), decorations.end(),
+ [](const Decoration& d) { return SpvDecorationBlock == d.dec_type(); });
+}
+
// Returns true if the given ID has the Import LinkageAttributes decoration.
bool hasImportLinkageAttribute(uint32_t id, ValidationState_t& vstate) {
const auto& decorations = vstate.id_decorations(id);
@@ -455,7 +465,7 @@
return lhs.offset < rhs.offset;
});
- // Now scan from lowest offest to highest offset.
+ // Now scan from lowest offset to highest offset.
uint32_t nextValidOffset = 0;
for (size_t ordered_member_idx = 0;
ordered_member_idx < member_offsets.size(); ordered_member_idx++) {
@@ -702,7 +712,7 @@
if (d.dec_type() == SpvDecorationLocation ||
d.dec_type() == SpvDecorationComponent) {
return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(var_id))
- << "A BuiltIn variable (id " << var_id
+ << vstate.VkErrorID(4915) << "A BuiltIn variable (id " << var_id
<< ") cannot have any Location or Component decorations";
}
}
@@ -710,12 +720,12 @@
return SPV_SUCCESS;
}
-// Checks whether proper decorations have been appied to the entry points.
+// Checks whether proper decorations have been applied to the entry points.
spv_result_t CheckDecorationsOfEntryPoints(ValidationState_t& vstate) {
for (uint32_t entry_point : vstate.entry_points()) {
const auto& descs = vstate.entry_point_descriptions(entry_point);
- int num_builtin_inputs = 0;
- int num_builtin_outputs = 0;
+ int num_builtin_block_inputs = 0;
+ int num_builtin_block_outputs = 0;
int num_workgroup_variables = 0;
int num_workgroup_variables_with_block = 0;
int num_workgroup_variables_with_aliased = 0;
@@ -766,9 +776,20 @@
Instruction* type_instr = vstate.FindDef(type_id);
if (type_instr && SpvOpTypeStruct == type_instr->opcode() &&
isBuiltInStruct(type_id, vstate)) {
- if (storage_class == SpvStorageClassInput) ++num_builtin_inputs;
- if (storage_class == SpvStorageClassOutput) ++num_builtin_outputs;
- if (num_builtin_inputs > 1 || num_builtin_outputs > 1) break;
+ if (!isBlock(type_id, vstate)) {
+ return vstate.diag(SPV_ERROR_INVALID_DATA, vstate.FindDef(type_id))
+ << vstate.VkErrorID(4919)
+ << "Interface struct has no Block decoration but has "
+ "BuiltIn members. "
+ "Location decorations must be used on each member of "
+ "OpVariable with a structure type that is a block not "
+ "decorated with Location.";
+ }
+ if (storage_class == SpvStorageClassInput) ++num_builtin_block_inputs;
+ if (storage_class == SpvStorageClassOutput)
+ ++num_builtin_block_outputs;
+ if (num_builtin_block_inputs > 1 || num_builtin_block_outputs > 1)
+ break;
if (auto error = CheckBuiltInVariable(interface, vstate))
return error;
} else if (isBuiltInVar(interface, vstate)) {
@@ -786,7 +807,7 @@
}
}
}
- if (num_builtin_inputs > 1 || num_builtin_outputs > 1) {
+ if (num_builtin_block_inputs > 1 || num_builtin_block_outputs > 1) {
return vstate.diag(SPV_ERROR_INVALID_BINARY,
vstate.FindDef(entry_point))
<< "There must be at most one object per Storage Class that can "
@@ -798,8 +819,8 @@
// targeted by an OpEntryPoint instruction
for (auto& decoration : vstate.id_decorations(entry_point)) {
if (SpvDecorationLinkageAttributes == decoration.dec_type()) {
- const char* linkage_name =
- reinterpret_cast<const char*>(&decoration.params()[0]);
+ const std::string linkage_name =
+ spvtools::utils::MakeString(decoration.params());
return vstate.diag(SPV_ERROR_INVALID_BINARY,
vstate.FindDef(entry_point))
<< "The LinkageAttributes Decoration (Linkage name: "
diff --git a/third_party/SPIRV-Tools/source/val/validate_extensions.cpp b/third_party/SPIRV-Tools/source/val/validate_extensions.cpp
index dccbe14..f1e0ab9 100644
--- a/third_party/SPIRV-Tools/source/val/validate_extensions.cpp
+++ b/third_party/SPIRV-Tools/source/val/validate_extensions.cpp
@@ -129,7 +129,7 @@
}
// True if the operand of a debug info instruction |inst| at |word_index|
-// satisifies |expectation| that is given as a function. Otherwise,
+// satisfies |expectation| that is given as a function. Otherwise,
// returns false.
bool DoesDebugInfoOperandMatchExpectation(
const ValidationState_t& _,
@@ -280,8 +280,7 @@
return _.diag(SPV_ERROR_INVALID_ID, inst) << "Name must be an OpString";
}
- const std::string name_str = reinterpret_cast<const char*>(
- name->words().data() + name->operands()[1].offset);
+ const std::string name_str = name->GetOperandAs<std::string>(1);
bool found = false;
for (auto& desc : _.entry_point_descriptions(kernel_id)) {
if (name_str == desc.name) {
@@ -740,9 +739,9 @@
spv_result_t ValidateExtInstImport(ValidationState_t& _,
const Instruction* inst) {
const auto name_id = 1;
- if (!_.HasExtension(kSPV_KHR_non_semantic_info)) {
- const std::string name(reinterpret_cast<const char*>(
- inst->words().data() + inst->operands()[name_id].offset));
+ if (_.version() <= SPV_SPIRV_VERSION_WORD(1, 5) &&
+ !_.HasExtension(kSPV_KHR_non_semantic_info)) {
+ const std::string name = inst->GetOperandAs<std::string>(name_id);
if (name.find("NonSemantic.") == 0) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "NonSemantic extended instruction sets cannot be declared "
@@ -774,7 +773,7 @@
assert(import_inst);
std::ostringstream ss;
- ss << reinterpret_cast<const char*>(import_inst->words().data() + 2);
+ ss << import_inst->GetOperandAs<std::string>(1);
ss << " ";
ss << desc->name;
@@ -2805,8 +2804,9 @@
bool invalid = false;
auto* component_count = _.FindDef(inst->word(i));
if (IsConstIntScalarTypeWith32Or64Bits(_, component_count)) {
- // TODO: We need a spec discussion for the bindless array.
- if (!component_count->word(3)) {
+ // TODO: We need a spec discussion for the runtime array for
+ // OpenCL.
+ if (!vulkanDebugInfo && !component_count->word(3)) {
invalid = true;
}
} else if (component_count->words().size() > 6 &&
@@ -3264,8 +3264,7 @@
}
} else if (ext_inst_type == SPV_EXT_INST_TYPE_NONSEMANTIC_CLSPVREFLECTION) {
auto import_inst = _.FindDef(inst->GetOperandAs<uint32_t>(2));
- const std::string name(reinterpret_cast<const char*>(
- import_inst->words().data() + import_inst->operands()[1].offset));
+ const std::string name = import_inst->GetOperandAs<std::string>(1);
const std::string reflection = "NonSemantic.ClspvReflection.";
char* end_ptr;
auto version_string = name.substr(reflection.size());
diff --git a/third_party/SPIRV-Tools/source/val/validate_image.cpp b/third_party/SPIRV-Tools/source/val/validate_image.cpp
index 64f6ba7..b12d1e8 100644
--- a/third_party/SPIRV-Tools/source/val/validate_image.cpp
+++ b/third_party/SPIRV-Tools/source/val/validate_image.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017 Google Inc.
+// Copyright (c) 2017 Google Inc.
// Modifications Copyright (C) 2020 Advanced Micro Devices, Inc. All rights
// reserved.
//
@@ -20,6 +20,7 @@
#include "source/diagnostic.h"
#include "source/opcode.h"
+#include "source/spirv_constant.h"
#include "source/spirv_target_env.h"
#include "source/util/bitutils.h"
#include "source/val/instruction.h"
@@ -71,6 +72,7 @@
// blocks other PRs.
// https://github.com/KhronosGroup/SPIRV-Tools/issues/4565
case SpvImageOperandsOffsetsMask:
+ case SpvImageOperandsNontemporalMask:
return true;
}
return false;
@@ -258,7 +260,8 @@
mask & ~uint32_t(SpvImageOperandsNonPrivateTexelKHRMask |
SpvImageOperandsVolatileTexelKHRMask |
SpvImageOperandsSignExtendMask |
- SpvImageOperandsZeroExtendMask);
+ SpvImageOperandsZeroExtendMask |
+ SpvImageOperandsNontemporalMask);
size_t expected_num_image_operand_words =
spvtools::utils::CountSetBits(mask_bits_having_operands);
if (mask & SpvImageOperandsGradMask) {
@@ -500,7 +503,7 @@
if (!_.IsIntVectorType(component_type) ||
_.GetDimension(component_type) != 2) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
- << "Expected Image Operand ConstOffsets array componenets to be "
+ << "Expected Image Operand ConstOffsets array components to be "
"int vectors of size 2";
}
@@ -630,6 +633,10 @@
// TODO: add validation
}
+ if (mask & SpvImageOperandsNontemporalMask) {
+ // Checked elsewhere: SPIR-V 1.6 version or later.
+ }
+
return SPV_SUCCESS;
}
@@ -915,6 +922,13 @@
"operand set to 0 or 1";
}
+ // This covers both OpTypeSampledImage and OpSampledImage.
+ if (_.version() >= SPV_SPIRV_VERSION_WORD(1, 6) && info.dim == SpvDimBuffer) {
+ return _.diag(SPV_ERROR_INVALID_ID, inst)
+ << "In SPIR-V 1.6 or later, sampled image dimension must not be "
+ "Buffer";
+ }
+
return SPV_SUCCESS;
}
@@ -1030,7 +1044,7 @@
<< "Result <id> from OpSampledImage instruction must not appear "
"as operand for Op"
<< spvOpcodeString(static_cast<SpvOp>(consumer_opcode))
- << ", since it is not specificed as taking an "
+ << ", since it is not specified as taking an "
<< "OpTypeSampledImage."
<< " Found result <id> '" << _.getIdName(inst->id())
<< "' as an operand of <id> '"
@@ -1659,7 +1673,7 @@
<< " components, but given only " << actual_coord_size;
}
- // TODO([email protected]) The spec doesn't explicitely say what the type
+ // TODO([email protected]) The spec doesn't explicitly say what the type
// of texel should be.
const uint32_t texel_type = _.GetOperandTypeId(inst, 2);
if (!_.IsIntScalarOrVectorType(texel_type) &&
diff --git a/third_party/SPIRV-Tools/source/val/validate_instruction.cpp b/third_party/SPIRV-Tools/source/val/validate_instruction.cpp
index dad9867..3edf163 100644
--- a/third_party/SPIRV-Tools/source/val/validate_instruction.cpp
+++ b/third_party/SPIRV-Tools/source/val/validate_instruction.cpp
@@ -297,7 +297,7 @@
}
// OpTerminateInvocation is special because it is enabled by Shader
- // capability, but also requries a extension and/or version check.
+ // capability, but also requires an extension and/or version check.
const bool capability_check_is_sufficient =
inst->opcode() != SpvOpTerminateInvocation;
@@ -406,7 +406,7 @@
// The instruction syntax is as follows:
// OpSwitch <selector ID> <Default ID> literal label literal label ...
// literal,label pairs come after the first 2 operands.
- // It is guaranteed at this point that num_operands is an even numner.
+ // It is guaranteed at this point that num_operands is an even number.
size_t num_pairs = (inst->operands().size() - 2) / 2;
const unsigned int num_pairs_limit =
_.options()->universal_limits_.max_switch_branches;
diff --git a/third_party/SPIRV-Tools/source/val/validate_interfaces.cpp b/third_party/SPIRV-Tools/source/val/validate_interfaces.cpp
index 7ccb637..adf2e47 100644
--- a/third_party/SPIRV-Tools/source/val/validate_interfaces.cpp
+++ b/third_party/SPIRV-Tools/source/val/validate_interfaces.cpp
@@ -154,7 +154,7 @@
// Members cannot have location decorations at this point.
if (_.HasDecoration(type->id(), SpvDecorationLocation)) {
return _.diag(SPV_ERROR_INVALID_DATA, type)
- << "Members cannot be assigned a location";
+ << _.VkErrorID(4918) << "Members cannot be assigned a location";
}
// Structs consume locations equal to the sum of the locations consumed
@@ -326,8 +326,9 @@
// Only block-decorated structs don't need a location on the variable.
const bool is_block = _.HasDecoration(type_id, SpvDecorationBlock);
if (!has_location && !is_block) {
+ const auto vuid = (type->opcode() == SpvOpTypeStruct) ? 4917 : 4916;
return _.diag(SPV_ERROR_INVALID_DATA, variable)
- << "Variable must be decorated with a location";
+ << _.VkErrorID(vuid) << "Variable must be decorated with a location";
}
const std::string storage_class = is_output ? "output" : "input";
@@ -411,7 +412,7 @@
auto where = member_locations.find(i - 1);
if (where == member_locations.end()) {
return _.diag(SPV_ERROR_INVALID_DATA, type)
- << "Member index " << i - 1
+ << _.VkErrorID(4919) << "Member index " << i - 1
<< " is missing a location assignment";
}
@@ -476,6 +477,9 @@
const Instruction* entry_point) {
// According to Vulkan 14.1 only the following execution models have
// locations assigned.
+ // TODO(dneto): SPV_NV_ray_tracing also uses locations on interface variables,
+ // in other shader stages. Similarly, the *provisional* version of
+ // SPV_KHR_ray_tracing did as well, but not the final version.
switch (entry_point->GetOperandAs<SpvExecutionModel>(0)) {
case SpvExecutionModelVertex:
case SpvExecutionModelTessellationControl:
diff --git a/third_party/SPIRV-Tools/source/val/validate_memory.cpp b/third_party/SPIRV-Tools/source/val/validate_memory.cpp
index a7b0f82..93b1800 100644
--- a/third_party/SPIRV-Tools/source/val/validate_memory.cpp
+++ b/third_party/SPIRV-Tools/source/val/validate_memory.cpp
@@ -1411,7 +1411,7 @@
<< state.getIdName(inst->id()) << "' must be an OpTypeRuntimeArray.";
}
- // The array member must the the index of the last element (the run time
+ // The array member must the index of the last element (the run time
// array).
if (inst->GetOperandAs<uint32_t>(3) != num_of_members - 1) {
return state.diag(SPV_ERROR_INVALID_ID, inst)
diff --git a/third_party/SPIRV-Tools/source/val/validate_scopes.cpp b/third_party/SPIRV-Tools/source/val/validate_scopes.cpp
index 29ba583..1c5f70a 100644
--- a/third_party/SPIRV-Tools/source/val/validate_scopes.cpp
+++ b/third_party/SPIRV-Tools/source/val/validate_scopes.cpp
@@ -225,7 +225,7 @@
<< _.VkErrorID(4638) << spvOpcodeString(opcode)
<< ": in Vulkan environment, Memory Scope cannot be CrossDevice";
}
- // Vulkan 1.0 specifc rules
+ // Vulkan 1.0 specific rules
if (_.context()->target_env == SPV_ENV_VULKAN_1_0 &&
value != SpvScopeDevice && value != SpvScopeWorkgroup &&
value != SpvScopeInvocation) {
@@ -234,7 +234,7 @@
<< ": in Vulkan 1.0 environment Memory Scope is limited to "
<< "Device, Workgroup and Invocation";
}
- // Vulkan 1.1 specifc rules
+ // Vulkan 1.1 specific rules
if ((_.context()->target_env == SPV_ENV_VULKAN_1_1 ||
_.context()->target_env == SPV_ENV_VULKAN_1_2) &&
value != SpvScopeDevice && value != SpvScopeWorkgroup &&
diff --git a/third_party/SPIRV-Tools/source/val/validation_state.cpp b/third_party/SPIRV-Tools/source/val/validation_state.cpp
index 8d1a0d3..6f97321 100644
--- a/third_party/SPIRV-Tools/source/val/validation_state.cpp
+++ b/third_party/SPIRV-Tools/source/val/validation_state.cpp
@@ -175,8 +175,18 @@
}
}
- // LocalSizeId is always allowed in non-Vulkan environments.
- features_.env_allow_localsizeid = !spvIsVulkanEnv(env);
+ // LocalSizeId is only disallowed prior to Vulkan 1.3 without maintenance4.
+ switch (env) {
+ case SPV_ENV_VULKAN_1_0:
+ case SPV_ENV_VULKAN_1_1:
+ case SPV_ENV_VULKAN_1_1_SPIRV_1_4:
+ case SPV_ENV_VULKAN_1_2:
+ features_.env_allow_localsizeid = false;
+ break;
+ default:
+ features_.env_allow_localsizeid = true;
+ break;
+ }
// Only attempt to count if we have words, otherwise let the other validation
// fail and generate an error.
@@ -389,6 +399,15 @@
features_.variable_pointers_storage_buffer = true;
break;
default:
+ // TODO(dneto): For now don't validate SPV_NV_ray_tracing, which uses
+ // capability SpvCapabilityRayTracingNV.
+ // SpvCapabilityRayTracingProvisionalKHR would need the same treatment.
+ // One of the differences going from SPV_KHR_ray_tracing from
+ // provisional to final spec was the provisional spec uses Locations
+ // for variables in certain storage classes, just like the
+ // SPV_NV_ray_tracing extension. So it mimics the NVIDIA extension.
+ // The final SPV_KHR_ray_tracing uses a different capability token
+ // number, so it doesn't fall into this case.
break;
}
}
@@ -479,7 +498,7 @@
"inside of another function");
assert(in_block() == false &&
"RegisterFunctionParameter can only be called when parsing the binary "
- "ouside of a block");
+ "outside of a block");
current_function().RegisterFunctionEnd();
in_function_ = false;
return SPV_SUCCESS;
@@ -497,15 +516,13 @@
switch (inst->opcode()) {
case SpvOpName: {
const auto target = inst->GetOperandAs<uint32_t>(0);
- const auto* str = reinterpret_cast<const char*>(inst->words().data() +
- inst->operand(1).offset);
+ const std::string str = inst->GetOperandAs<std::string>(1);
AssignNameToId(target, str);
break;
}
case SpvOpMemberName: {
const auto target = inst->GetOperandAs<uint32_t>(0);
- const auto* str = reinterpret_cast<const char*>(inst->words().data() +
- inst->operand(2).offset);
+ const std::string str = inst->GetOperandAs<std::string>(2);
AssignNameToId(target, str);
break;
}
@@ -593,7 +610,7 @@
if (message) {
*message =
errorVUID +
- "in Vulkan evironment, Output Storage Class must not be "
+ "in Vulkan environment, Output Storage Class must not be "
"used in GLCompute, RayGenerationKHR, IntersectionKHR, "
"AnyHitKHR, ClosestHitKHR, MissKHR, or CallableKHR "
"execution models";
@@ -615,7 +632,7 @@
if (message) {
*message =
errorVUID +
- "in Vulkan evironment, Workgroup Storage Class is limited "
+ "in Vulkan environment, Workgroup Storage Class is limited "
"to MeshNV, TaskNV, and GLCompute execution model";
}
return false;
@@ -1390,7 +1407,7 @@
return "";
}
- // This large switch case is only searched when an error has occured.
+ // This large switch case is only searched when an error has occurred.
// If an id is changed, the old case must be modified or removed. Each string
// here is interpreted as being "implemented"
@@ -1867,6 +1884,16 @@
return VUID_WRAP(VUID-StandaloneSpirv-OpMemoryBarrier-04733);
case 4780:
return VUID_WRAP(VUID-StandaloneSpirv-Result-04780);
+ case 4915:
+ return VUID_WRAP(VUID-StandaloneSpirv-Location-04915);
+ case 4916:
+ return VUID_WRAP(VUID-StandaloneSpirv-Location-04916);
+ case 4917:
+ return VUID_WRAP(VUID-StandaloneSpirv-Location-04917);
+ case 4918:
+ return VUID_WRAP(VUID-StandaloneSpirv-Location-04918);
+ case 4919:
+ return VUID_WRAP(VUID-StandaloneSpirv-Location-04919);
default:
return ""; // unknown id
}
diff --git a/third_party/SPIRV-Tools/source/val/validation_state.h b/third_party/SPIRV-Tools/source/val/validation_state.h
index 2ddfa4a..89834a0 100644
--- a/third_party/SPIRV-Tools/source/val/validation_state.h
+++ b/third_party/SPIRV-Tools/source/val/validation_state.h
@@ -67,7 +67,7 @@
bool declare_int16_type = false; // Allow OpTypeInt with 16 bit width?
bool declare_float16_type = false; // Allow OpTypeFloat with 16 bit width?
bool free_fp_rounding_mode = false; // Allow the FPRoundingMode decoration
- // and its vaules to be used without
+ // and its values to be used without
// requiring any capability
// Allow functionalities enabled by VariablePointers capability.
@@ -797,7 +797,7 @@
/// IDs that are entry points, ie, arguments to OpEntryPoint.
std::vector<uint32_t> entry_points_;
- /// Maps an entry point id to its desciptions.
+ /// Maps an entry point id to its descriptions.
std::unordered_map<uint32_t, std::vector<EntryPointDescription>>
entry_point_descriptions_;
@@ -844,7 +844,7 @@
// have the same pointer size (for physical pointer types).
uint32_t pointer_size_and_alignment_;
- /// NOTE: See correspoding getter functions
+ /// NOTE: See corresponding getter functions
bool in_function_;
/// The state of optional features. These are determined by capabilities
diff --git a/third_party/SPIRV-Tools/source/wasm/spirv-tools.cpp b/third_party/SPIRV-Tools/source/wasm/spirv-tools.cpp
index 90407f3..33f2f05 100644
--- a/third_party/SPIRV-Tools/source/wasm/spirv-tools.cpp
+++ b/third_party/SPIRV-Tools/source/wasm/spirv-tools.cpp
@@ -78,7 +78,8 @@
constant("SPV_ENV_VULKAN_1_1_SPIRV_1_4", static_cast<uint32_t>(SPV_ENV_VULKAN_1_1_SPIRV_1_4));
constant("SPV_ENV_UNIVERSAL_1_5", static_cast<uint32_t>(SPV_ENV_UNIVERSAL_1_5));
constant("SPV_ENV_VULKAN_1_2", static_cast<uint32_t>(SPV_ENV_VULKAN_1_2));
-
+ constant("SPV_ENV_UNIVERSAL_1_6",
+ static_cast<uint32_t>(SPV_ENV_UNIVERSAL_1_6));
constant("SPV_BINARY_TO_TEXT_OPTION_NONE", static_cast<uint32_t>(SPV_BINARY_TO_TEXT_OPTION_NONE));
constant("SPV_BINARY_TO_TEXT_OPTION_PRINT", static_cast<uint32_t>(SPV_BINARY_TO_TEXT_OPTION_PRINT));
@@ -90,4 +91,4 @@
constant("SPV_TEXT_TO_BINARY_OPTION_NONE", static_cast<uint32_t>(SPV_TEXT_TO_BINARY_OPTION_NONE));
constant("SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS", static_cast<uint32_t>(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS));
-}
\ No newline at end of file
+}
diff --git a/third_party/SPIRV-Tools/source/wasm/spirv-tools.d.ts b/third_party/SPIRV-Tools/source/wasm/spirv-tools.d.ts
index 9c19797..c06bdf1 100644
--- a/third_party/SPIRV-Tools/source/wasm/spirv-tools.d.ts
+++ b/third_party/SPIRV-Tools/source/wasm/spirv-tools.d.ts
@@ -40,6 +40,7 @@
SPV_ENV_VULKAN_1_1_SPIRV_1_4: number;
SPV_ENV_UNIVERSAL_1_5: number;
SPV_ENV_VULKAN_1_2: number;
+ SPV_ENV_UNIVERSAL_1_6: number;
SPV_TEXT_TO_BINARY_OPTION_NONE: number;
SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS: number;
diff --git a/third_party/SPIRV-Tools/test/CMakeLists.txt b/third_party/SPIRV-Tools/test/CMakeLists.txt
index e88df04..4ca8ef8 100644
--- a/third_party/SPIRV-Tools/test/CMakeLists.txt
+++ b/third_party/SPIRV-Tools/test/CMakeLists.txt
@@ -185,6 +185,7 @@
endif()
+add_subdirectory(diff)
add_subdirectory(link)
add_subdirectory(lint)
add_subdirectory(opt)
diff --git a/third_party/SPIRV-Tools/test/binary_header_get_test.cpp b/third_party/SPIRV-Tools/test/binary_header_get_test.cpp
index 3ce0b63..f94f0c1 100644
--- a/third_party/SPIRV-Tools/test/binary_header_get_test.cpp
+++ b/third_party/SPIRV-Tools/test/binary_header_get_test.cpp
@@ -51,8 +51,8 @@
ASSERT_EQ(SPV_SUCCESS, spvBinaryHeaderGet(&const_bin, endian, &header));
ASSERT_EQ(static_cast<uint32_t>(SpvMagicNumber), header.magic);
- // Expect SPIRV-Headers updated to SPIR-V 1.5.
- ASSERT_EQ(0x00010500u, header.version);
+ // Expect SPIRV-Headers updated to SPIR-V 1.6.
+ ASSERT_EQ(0x00010600u, header.version);
ASSERT_EQ(static_cast<uint32_t>(SPV_GENERATOR_CODEPLAY), header.generator);
ASSERT_EQ(1u, header.bound);
ASSERT_EQ(0u, header.schema);
diff --git a/third_party/SPIRV-Tools/test/binary_parse_test.cpp b/third_party/SPIRV-Tools/test/binary_parse_test.cpp
index 9a13f22..f0810a3 100644
--- a/third_party/SPIRV-Tools/test/binary_parse_test.cpp
+++ b/third_party/SPIRV-Tools/test/binary_parse_test.cpp
@@ -203,16 +203,7 @@
void Parse(const SpirvVector& words, spv_result_t expected_result,
bool flip_words = false) {
SpirvVector flipped_words(words);
- SCOPED_TRACE(flip_words ? "Flipped Endianness" : "Normal Endianness");
- if (flip_words) {
- std::transform(flipped_words.begin(), flipped_words.end(),
- flipped_words.begin(), [](const uint32_t raw_word) {
- return spvFixWord(raw_word,
- I32_ENDIAN_HOST == I32_ENDIAN_BIG
- ? SPV_ENDIANNESS_LITTLE
- : SPV_ENDIANNESS_BIG);
- });
- }
+ MaybeFlipWords(flip_words, flipped_words.begin(), flipped_words.end());
EXPECT_EQ(expected_result,
spvBinaryParse(ScopedContext().context, &client_,
flipped_words.data(), flipped_words.size(),
@@ -486,27 +477,27 @@
}
TEST_F(BinaryParseTest, InstructionWithStringOperand) {
- const std::string str =
- "the future is already here, it's just not evenly distributed";
- const auto str_words = MakeVector(str);
- const auto instruction = MakeInstruction(SpvOpName, {99}, str_words);
- const auto words = Concatenate({ExpectedHeaderForBound(100), instruction});
- InSequence calls_expected_in_specific_order;
- EXPECT_HEADER(100).WillOnce(Return(SPV_SUCCESS));
- const auto operands = std::vector<spv_parsed_operand_t>{
- MakeSimpleOperand(1, SPV_OPERAND_TYPE_ID),
- MakeLiteralStringOperand(2, static_cast<uint16_t>(str_words.size()))};
- EXPECT_CALL(client_,
- Instruction(ParsedInstruction(spv_parsed_instruction_t{
- instruction.data(), static_cast<uint16_t>(instruction.size()),
- SpvOpName, SPV_EXT_INST_TYPE_NONE, 0 /*type id*/,
- 0 /* No result id for OpName*/, operands.data(),
- static_cast<uint16_t>(operands.size())})))
- .WillOnce(Return(SPV_SUCCESS));
- // Since we are actually checking the output, don't test the
- // endian-swapped version.
- Parse(words, SPV_SUCCESS, false);
- EXPECT_EQ(nullptr, diagnostic_);
+ for (bool endian_swap : kSwapEndians) {
+ const std::string str =
+ "the future is already here, it's just not evenly distributed";
+ const auto str_words = MakeVector(str);
+ const auto instruction = MakeInstruction(SpvOpName, {99}, str_words);
+ const auto words = Concatenate({ExpectedHeaderForBound(100), instruction});
+ InSequence calls_expected_in_specific_order;
+ EXPECT_HEADER(100).WillOnce(Return(SPV_SUCCESS));
+ const auto operands = std::vector<spv_parsed_operand_t>{
+ MakeSimpleOperand(1, SPV_OPERAND_TYPE_ID),
+ MakeLiteralStringOperand(2, static_cast<uint16_t>(str_words.size()))};
+ EXPECT_CALL(client_, Instruction(ParsedInstruction(spv_parsed_instruction_t{
+ instruction.data(),
+ static_cast<uint16_t>(instruction.size()),
+ SpvOpName, SPV_EXT_INST_TYPE_NONE, 0 /*type id*/,
+ 0 /* No result id for OpName*/, operands.data(),
+ static_cast<uint16_t>(operands.size())})))
+ .WillOnce(Return(SPV_SUCCESS));
+ Parse(words, SPV_SUCCESS, endian_swap);
+ EXPECT_EQ(nullptr, diagnostic_);
+ }
}
// Checks for non-zero values for the result_id and ext_inst_type members
@@ -613,7 +604,7 @@
MakeInstruction(SpvOpNop, {42})}),
"Invalid instruction OpNop starting at word 5: expected "
"no more operands after 1 words, but stated word count is 2."},
- // Supply several more unexpectd words.
+ // Supply several more unexpected words.
{Concatenate({ExpectedHeaderForBound(1),
MakeInstruction(SpvOpNop, {42, 43, 44, 45, 46, 47})}),
"Invalid instruction OpNop starting at word 5: expected "
diff --git a/third_party/SPIRV-Tools/test/binary_to_text.literal_test.cpp b/third_party/SPIRV-Tools/test/binary_to_text.literal_test.cpp
index 02daac7..5956984 100644
--- a/third_party/SPIRV-Tools/test/binary_to_text.literal_test.cpp
+++ b/third_party/SPIRV-Tools/test/binary_to_text.literal_test.cpp
@@ -27,8 +27,15 @@
using RoundTripLiteralsTest =
spvtest::TextToBinaryTestBase<::testing::TestWithParam<std::string>>;
+static const bool kSwapEndians[] = {false, true};
+
TEST_P(RoundTripLiteralsTest, Sample) {
- EXPECT_THAT(EncodeAndDecodeSuccessfully(GetParam()), Eq(GetParam()));
+ for (bool endian_swap : kSwapEndians) {
+ EXPECT_THAT(
+ EncodeAndDecodeSuccessfully(GetParam(), SPV_BINARY_TO_TEXT_OPTION_NONE,
+ SPV_ENV_UNIVERSAL_1_0, endian_swap),
+ Eq(GetParam()));
+ }
}
// clang-format off
@@ -58,8 +65,12 @@
// Test case where the generated disassembly is not the same as the
// assembly passed in.
TEST_P(RoundTripSpecialCaseLiteralsTest, Sample) {
- EXPECT_THAT(EncodeAndDecodeSuccessfully(std::get<0>(GetParam())),
- Eq(std::get<1>(GetParam())));
+ for (bool endian_swap : kSwapEndians) {
+ EXPECT_THAT(EncodeAndDecodeSuccessfully(std::get<0>(GetParam()),
+ SPV_BINARY_TO_TEXT_OPTION_NONE,
+ SPV_ENV_UNIVERSAL_1_0, endian_swap),
+ Eq(std::get<1>(GetParam())));
+ }
}
// clang-format off
diff --git a/third_party/SPIRV-Tools/test/c_interface_test.cpp b/third_party/SPIRV-Tools/test/c_interface_test.cpp
index 841bb2c..1562057 100644
--- a/third_party/SPIRV-Tools/test/c_interface_test.cpp
+++ b/third_party/SPIRV-Tools/test/c_interface_test.cpp
@@ -117,7 +117,7 @@
const spv_position_t& position, const char* message) {
++invocation;
EXPECT_EQ(SPV_MSG_ERROR, level);
- // The error happens at scanning the begining of second line.
+ // The error happens at scanning the beginning of second line.
EXPECT_STREQ("input", source);
EXPECT_EQ(1u, position.line);
EXPECT_EQ(0u, position.column);
diff --git a/third_party/SPIRV-Tools/test/diff/CMakeLists.txt b/third_party/SPIRV-Tools/test/diff/CMakeLists.txt
new file mode 100644
index 0000000..811805b
--- /dev/null
+++ b/third_party/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
+)
diff --git a/third_party/SPIRV-Tools/test/diff/diff_files/.gitignore b/third_party/SPIRV-Tools/test/diff/diff_files/.gitignore
new file mode 100644
index 0000000..727526e
--- /dev/null
+++ b/third_party/SPIRV-Tools/test/diff/diff_files/.gitignore
@@ -0,0 +1,3 @@
+# To aid debugging no-dbg variants, the temporary files used to strip debug information are placed
+# in a hidden directory and aren't removed after generation.
+.no_dbg/
diff --git a/third_party/SPIRV-Tools/test/diff/diff_files/OpExtInst_in_dst_only_autogen.cpp b/third_party/SPIRV-Tools/test/diff/diff_files/OpExtInst_in_dst_only_autogen.cpp
new file mode 100644
index 0000000..ce899ed
--- /dev/null
+++ b/third_party/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
diff --git a/third_party/SPIRV-Tools/test/diff/diff_files/OpExtInst_in_dst_only_dst.spvasm b/third_party/SPIRV-Tools/test/diff/diff_files/OpExtInst_in_dst_only_dst.spvasm
new file mode 100644
index 0000000..e599d1e
--- /dev/null
+++ b/third_party/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
+
diff --git a/third_party/SPIRV-Tools/test/diff/diff_files/OpExtInst_in_dst_only_src.spvasm b/third_party/SPIRV-Tools/test/diff/diff_files/OpExtInst_in_dst_only_src.spvasm
new file mode 100644
index 0000000..9f6fc18
--- /dev/null
+++ b/third_party/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
+
diff --git a/third_party/SPIRV-Tools/test/diff/diff_files/OpExtInst_in_src_only_autogen.cpp b/third_party/SPIRV-Tools/test/diff/diff_files/OpExtInst_in_src_only_autogen.cpp
new file mode 100644
index 0000000..9944c2c
--- /dev/null
+++ b/third_party/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
diff --git a/third_party/SPIRV-Tools/test/diff/diff_files/OpExtInst_in_src_only_dst.spvasm b/third_party/SPIRV-Tools/test/diff/diff_files/OpExtInst_in_src_only_dst.spvasm
new file mode 100644
index 0000000..4723305
--- /dev/null
+++ b/third_party/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
+
diff --git a/third_party/SPIRV-Tools/test/diff/diff_files/OpExtInst_in_src_only_src.spvasm b/third_party/SPIRV-Tools/test/diff/diff_files/OpExtInst_in_src_only_src.spvasm
new file mode 100644
index 0000000..efb663a
--- /dev/null
+++ b/third_party/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
+
diff --git a/third_party/SPIRV-Tools/test/diff/diff_files/README.md b/third_party/SPIRV-Tools/test/diff/diff_files/README.md
new file mode 100644
index 0000000..5dcee25
--- /dev/null
+++ b/third_party/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.
diff --git a/third_party/SPIRV-Tools/test/diff/diff_files/basic_autogen.cpp b/third_party/SPIRV-Tools/test/diff/diff_files/basic_autogen.cpp
new file mode 100644
index 0000000..f3afc70
--- /dev/null
+++ b/third_party/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
diff --git a/third_party/SPIRV-Tools/test/diff/diff_files/basic_dst.spvasm b/third_party/SPIRV-Tools/test/diff/diff_files/basic_dst.spvasm
new file mode 100644
index 0000000..79cb888
--- /dev/null
+++ b/third_party/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
diff --git a/third_party/SPIRV-Tools/test/diff/diff_files/basic_src.spvasm b/third_party/SPIRV-Tools/test/diff/diff_files/basic_src.spvasm
new file mode 100644
index 0000000..c55ec7a
--- /dev/null
+++ b/third_party/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
diff --git a/third_party/SPIRV-Tools/test/diff/diff_files/constant_array_size_autogen.cpp b/third_party/SPIRV-Tools/test/diff/diff_files/constant_array_size_autogen.cpp
new file mode 100644
index 0000000..16975ff
--- /dev/null
+++ b/third_party/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
diff --git a/third_party/SPIRV-Tools/test/diff/diff_files/constant_array_size_dst.spvasm b/third_party/SPIRV-Tools/test/diff/diff_files/constant_array_size_dst.spvasm
new file mode 100644
index 0000000..a432b61
--- /dev/null
+++ b/third_party/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
diff --git a/third_party/SPIRV-Tools/test/diff/diff_files/constant_array_size_src.spvasm b/third_party/SPIRV-Tools/test/diff/diff_files/constant_array_size_src.spvasm
new file mode 100644
index 0000000..4e1ba64
--- /dev/null
+++ b/third_party/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
diff --git a/third_party/SPIRV-Tools/test/diff/diff_files/diff_test_files_autogen.cmake b/third_party/SPIRV-Tools/test/diff/diff_files/diff_test_files_autogen.cmake
new file mode 100644
index 0000000..f472480
--- /dev/null
+++ b/third_party/SPIRV-Tools/test/diff/diff_files/diff_test_files_autogen.cmake
@@ -0,0 +1,38 @@
+# 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/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/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"
+)
diff --git a/third_party/SPIRV-Tools/test/diff/diff_files/different_decorations_fragment_autogen.cpp b/third_party/SPIRV-Tools/test/diff/diff_files/different_decorations_fragment_autogen.cpp
new file mode 100644
index 0000000..0d34654
--- /dev/null
+++ b/third_party/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
diff --git a/third_party/SPIRV-Tools/test/diff/diff_files/different_decorations_fragment_dst.spvasm b/third_party/SPIRV-Tools/test/diff/diff_files/different_decorations_fragment_dst.spvasm
new file mode 100644
index 0000000..b5d1c9f
--- /dev/null
+++ b/third_party/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
diff --git a/third_party/SPIRV-Tools/test/diff/diff_files/different_decorations_fragment_src.spvasm b/third_party/SPIRV-Tools/test/diff/diff_files/different_decorations_fragment_src.spvasm
new file mode 100644
index 0000000..2c8cd64
--- /dev/null
+++ b/third_party/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
+
diff --git a/third_party/SPIRV-Tools/test/diff/diff_files/different_decorations_vertex_autogen.cpp b/third_party/SPIRV-Tools/test/diff/diff_files/different_decorations_vertex_autogen.cpp
new file mode 100644
index 0000000..f65ee5a
--- /dev/null
+++ b/third_party/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
diff --git a/third_party/SPIRV-Tools/test/diff/diff_files/different_decorations_vertex_dst.spvasm b/third_party/SPIRV-Tools/test/diff/diff_files/different_decorations_vertex_dst.spvasm
new file mode 100644
index 0000000..33c6a9c
--- /dev/null
+++ b/third_party/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
diff --git a/third_party/SPIRV-Tools/test/diff/diff_files/different_decorations_vertex_src.spvasm b/third_party/SPIRV-Tools/test/diff/diff_files/different_decorations_vertex_src.spvasm
new file mode 100644
index 0000000..ce1680c
--- /dev/null
+++ b/third_party/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
+
diff --git a/third_party/SPIRV-Tools/test/diff/diff_files/extra_if_block_autogen.cpp b/third_party/SPIRV-Tools/test/diff/diff_files/extra_if_block_autogen.cpp
new file mode 100644
index 0000000..4f91319
--- /dev/null
+++ b/third_party/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
diff --git a/third_party/SPIRV-Tools/test/diff/diff_files/extra_if_block_dst.spvasm b/third_party/SPIRV-Tools/test/diff/diff_files/extra_if_block_dst.spvasm
new file mode 100644
index 0000000..79bda83
--- /dev/null
+++ b/third_party/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
+
diff --git a/third_party/SPIRV-Tools/test/diff/diff_files/extra_if_block_src.spvasm b/third_party/SPIRV-Tools/test/diff/diff_files/extra_if_block_src.spvasm
new file mode 100644
index 0000000..1b43ccb
--- /dev/null
+++ b/third_party/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
+
diff --git a/third_party/SPIRV-Tools/test/diff/diff_files/generate_tests.py b/third_party/SPIRV-Tools/test/diff/diff_files/generate_tests.py
new file mode 100755
index 0000000..1c380c9
--- /dev/null
+++ b/third_party/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())
diff --git a/third_party/SPIRV-Tools/test/diff/diff_files/index_signedness_autogen.cpp b/third_party/SPIRV-Tools/test/diff/diff_files/index_signedness_autogen.cpp
new file mode 100644
index 0000000..ab650be
--- /dev/null
+++ b/third_party/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
diff --git a/third_party/SPIRV-Tools/test/diff/diff_files/index_signedness_dst.spvasm b/third_party/SPIRV-Tools/test/diff/diff_files/index_signedness_dst.spvasm
new file mode 100644
index 0000000..08c1939
--- /dev/null
+++ b/third_party/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
+
diff --git a/third_party/SPIRV-Tools/test/diff/diff_files/index_signedness_src.spvasm b/third_party/SPIRV-Tools/test/diff/diff_files/index_signedness_src.spvasm
new file mode 100644
index 0000000..06dfd18
--- /dev/null
+++ b/third_party/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
+
diff --git a/third_party/SPIRV-Tools/test/diff/diff_files/int_vs_uint_constants_autogen.cpp b/third_party/SPIRV-Tools/test/diff/diff_files/int_vs_uint_constants_autogen.cpp
new file mode 100644
index 0000000..187722e
--- /dev/null
+++ b/third_party/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
diff --git a/third_party/SPIRV-Tools/test/diff/diff_files/int_vs_uint_constants_dst.spvasm b/third_party/SPIRV-Tools/test/diff/diff_files/int_vs_uint_constants_dst.spvasm
new file mode 100644
index 0000000..da2618b
--- /dev/null
+++ b/third_party/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
diff --git a/third_party/SPIRV-Tools/test/diff/diff_files/int_vs_uint_constants_src.spvasm b/third_party/SPIRV-Tools/test/diff/diff_files/int_vs_uint_constants_src.spvasm
new file mode 100644
index 0000000..214b49b
--- /dev/null
+++ b/third_party/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
diff --git a/third_party/SPIRV-Tools/test/diff/diff_files/large_functions_large_diffs_autogen.cpp b/third_party/SPIRV-Tools/test/diff/diff_files/large_functions_large_diffs_autogen.cpp
new file mode 100644
index 0000000..12cb621
--- /dev/null
+++ b/third_party/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
diff --git a/third_party/SPIRV-Tools/test/diff/diff_files/large_functions_large_diffs_dst.spvasm b/third_party/SPIRV-Tools/test/diff/diff_files/large_functions_large_diffs_dst.spvasm
new file mode 100644
index 0000000..be7c1d5
--- /dev/null
+++ b/third_party/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
+
diff --git a/third_party/SPIRV-Tools/test/diff/diff_files/large_functions_large_diffs_src.spvasm b/third_party/SPIRV-Tools/test/diff/diff_files/large_functions_large_diffs_src.spvasm
new file mode 100644
index 0000000..8f0aa61
--- /dev/null
+++ b/third_party/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
+
diff --git a/third_party/SPIRV-Tools/test/diff/diff_files/large_functions_small_diffs_autogen.cpp b/third_party/SPIRV-Tools/test/diff/diff_files/large_functions_small_diffs_autogen.cpp
new file mode 100644
index 0000000..02838d9
--- /dev/null
+++ b/third_party/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
diff --git a/third_party/SPIRV-Tools/test/diff/diff_files/large_functions_small_diffs_dst.spvasm b/third_party/SPIRV-Tools/test/diff/diff_files/large_functions_small_diffs_dst.spvasm
new file mode 100644
index 0000000..f788e0b
--- /dev/null
+++ b/third_party/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
+
diff --git a/third_party/SPIRV-Tools/test/diff/diff_files/large_functions_small_diffs_src.spvasm b/third_party/SPIRV-Tools/test/diff/diff_files/large_functions_small_diffs_src.spvasm
new file mode 100644
index 0000000..78a9278
--- /dev/null
+++ b/third_party/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
+
diff --git a/third_party/SPIRV-Tools/test/diff/diff_files/multiple_different_entry_points_autogen.cpp b/third_party/SPIRV-Tools/test/diff/diff_files/multiple_different_entry_points_autogen.cpp
new file mode 100644
index 0000000..29d4b1d
--- /dev/null
+++ b/third_party/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
diff --git a/third_party/SPIRV-Tools/test/diff/diff_files/multiple_different_entry_points_dst.spvasm b/third_party/SPIRV-Tools/test/diff/diff_files/multiple_different_entry_points_dst.spvasm
new file mode 100644
index 0000000..72cfe28
--- /dev/null
+++ b/third_party/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
diff --git a/third_party/SPIRV-Tools/test/diff/diff_files/multiple_different_entry_points_src.spvasm b/third_party/SPIRV-Tools/test/diff/diff_files/multiple_different_entry_points_src.spvasm
new file mode 100644
index 0000000..2119aa7
--- /dev/null
+++ b/third_party/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
diff --git a/third_party/SPIRV-Tools/test/diff/diff_files/multiple_same_entry_points_autogen.cpp b/third_party/SPIRV-Tools/test/diff/diff_files/multiple_same_entry_points_autogen.cpp
new file mode 100644
index 0000000..9d01166
--- /dev/null
+++ b/third_party/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
diff --git a/third_party/SPIRV-Tools/test/diff/diff_files/multiple_same_entry_points_dst.spvasm b/third_party/SPIRV-Tools/test/diff/diff_files/multiple_same_entry_points_dst.spvasm
new file mode 100644
index 0000000..e200722
--- /dev/null
+++ b/third_party/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
diff --git a/third_party/SPIRV-Tools/test/diff/diff_files/multiple_same_entry_points_src.spvasm b/third_party/SPIRV-Tools/test/diff/diff_files/multiple_same_entry_points_src.spvasm
new file mode 100644
index 0000000..17001b5
--- /dev/null
+++ b/third_party/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
diff --git a/third_party/SPIRV-Tools/test/diff/diff_files/reordered_if_blocks_autogen.cpp b/third_party/SPIRV-Tools/test/diff/diff_files/reordered_if_blocks_autogen.cpp
new file mode 100644
index 0000000..0788199
--- /dev/null
+++ b/third_party/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
diff --git a/third_party/SPIRV-Tools/test/diff/diff_files/reordered_if_blocks_dst.spvasm b/third_party/SPIRV-Tools/test/diff/diff_files/reordered_if_blocks_dst.spvasm
new file mode 100644
index 0000000..cd1d6d5
--- /dev/null
+++ b/third_party/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
+
diff --git a/third_party/SPIRV-Tools/test/diff/diff_files/reordered_if_blocks_src.spvasm b/third_party/SPIRV-Tools/test/diff/diff_files/reordered_if_blocks_src.spvasm
new file mode 100644
index 0000000..209cb45
--- /dev/null
+++ b/third_party/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
diff --git a/third_party/SPIRV-Tools/test/diff/diff_files/reordered_switch_blocks_autogen.cpp b/third_party/SPIRV-Tools/test/diff/diff_files/reordered_switch_blocks_autogen.cpp
new file mode 100644
index 0000000..c0ba48d
--- /dev/null
+++ b/third_party/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
diff --git a/third_party/SPIRV-Tools/test/diff/diff_files/reordered_switch_blocks_dst.spvasm b/third_party/SPIRV-Tools/test/diff/diff_files/reordered_switch_blocks_dst.spvasm
new file mode 100644
index 0000000..8eabb4e
--- /dev/null
+++ b/third_party/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
diff --git a/third_party/SPIRV-Tools/test/diff/diff_files/reordered_switch_blocks_src.spvasm b/third_party/SPIRV-Tools/test/diff/diff_files/reordered_switch_blocks_src.spvasm
new file mode 100644
index 0000000..e377228
--- /dev/null
+++ b/third_party/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
diff --git a/third_party/SPIRV-Tools/test/diff/diff_files/small_functions_small_diffs_autogen.cpp b/third_party/SPIRV-Tools/test/diff/diff_files/small_functions_small_diffs_autogen.cpp
new file mode 100644
index 0000000..c1a9100
--- /dev/null
+++ b/third_party/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
diff --git a/third_party/SPIRV-Tools/test/diff/diff_files/small_functions_small_diffs_dst.spvasm b/third_party/SPIRV-Tools/test/diff/diff_files/small_functions_small_diffs_dst.spvasm
new file mode 100644
index 0000000..fabf569
--- /dev/null
+++ b/third_party/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
+
diff --git a/third_party/SPIRV-Tools/test/diff/diff_files/small_functions_small_diffs_src.spvasm b/third_party/SPIRV-Tools/test/diff/diff_files/small_functions_small_diffs_src.spvasm
new file mode 100644
index 0000000..895285b
--- /dev/null
+++ b/third_party/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
+
diff --git a/third_party/SPIRV-Tools/test/diff/diff_files/spec_constant_array_size_autogen.cpp b/third_party/SPIRV-Tools/test/diff/diff_files/spec_constant_array_size_autogen.cpp
new file mode 100644
index 0000000..1962d27
--- /dev/null
+++ b/third_party/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
diff --git a/third_party/SPIRV-Tools/test/diff/diff_files/spec_constant_array_size_dst.spvasm b/third_party/SPIRV-Tools/test/diff/diff_files/spec_constant_array_size_dst.spvasm
new file mode 100644
index 0000000..7cedf08
--- /dev/null
+++ b/third_party/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
diff --git a/third_party/SPIRV-Tools/test/diff/diff_files/spec_constant_array_size_src.spvasm b/third_party/SPIRV-Tools/test/diff/diff_files/spec_constant_array_size_src.spvasm
new file mode 100644
index 0000000..e17e04a
--- /dev/null
+++ b/third_party/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
diff --git a/third_party/SPIRV-Tools/test/diff/diff_files/spec_constant_composite_autogen.cpp b/third_party/SPIRV-Tools/test/diff/diff_files/spec_constant_composite_autogen.cpp
new file mode 100644
index 0000000..e4b52cb
--- /dev/null
+++ b/third_party/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
diff --git a/third_party/SPIRV-Tools/test/diff/diff_files/spec_constant_composite_dst.spvasm b/third_party/SPIRV-Tools/test/diff/diff_files/spec_constant_composite_dst.spvasm
new file mode 100644
index 0000000..3ab8d4d
--- /dev/null
+++ b/third_party/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
diff --git a/third_party/SPIRV-Tools/test/diff/diff_files/spec_constant_composite_src.spvasm b/third_party/SPIRV-Tools/test/diff/diff_files/spec_constant_composite_src.spvasm
new file mode 100644
index 0000000..ee48ef9
--- /dev/null
+++ b/third_party/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
diff --git a/third_party/SPIRV-Tools/test/diff/diff_files/unrelated_shaders_autogen.cpp b/third_party/SPIRV-Tools/test/diff/diff_files/unrelated_shaders_autogen.cpp
new file mode 100644
index 0000000..e1a58cc
--- /dev/null
+++ b/third_party/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
diff --git a/third_party/SPIRV-Tools/test/diff/diff_files/unrelated_shaders_dst.spvasm b/third_party/SPIRV-Tools/test/diff/diff_files/unrelated_shaders_dst.spvasm
new file mode 100644
index 0000000..719715b
--- /dev/null
+++ b/third_party/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
+
diff --git a/third_party/SPIRV-Tools/test/diff/diff_files/unrelated_shaders_src.spvasm b/third_party/SPIRV-Tools/test/diff/diff_files/unrelated_shaders_src.spvasm
new file mode 100644
index 0000000..e77b2d2
--- /dev/null
+++ b/third_party/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
+
diff --git a/third_party/SPIRV-Tools/test/diff/diff_test.cpp b/third_party/SPIRV-Tools/test/diff/diff_test.cpp
new file mode 100644
index 0000000..5b11d0e
--- /dev/null
+++ b/third_party/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
diff --git a/third_party/SPIRV-Tools/test/diff/diff_test_utils.cpp b/third_party/SPIRV-Tools/test/diff/diff_test_utils.cpp
new file mode 100644
index 0000000..14bb821
--- /dev/null
+++ b/third_party/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
diff --git a/third_party/SPIRV-Tools/test/diff/diff_test_utils.h b/third_party/SPIRV-Tools/test/diff/diff_test_utils.h
new file mode 100644
index 0000000..938236e
--- /dev/null
+++ b/third_party/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_
diff --git a/third_party/SPIRV-Tools/test/diff/lcs_test.cpp b/third_party/SPIRV-Tools/test/diff/lcs_test.cpp
new file mode 100644
index 0000000..3e097b3
--- /dev/null
+++ b/third_party/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
diff --git a/third_party/SPIRV-Tools/test/ext_inst.cldebug100_test.cpp b/third_party/SPIRV-Tools/test/ext_inst.cldebug100_test.cpp
index 4f1e106..0bbdd3a 100644
--- a/third_party/SPIRV-Tools/test/ext_inst.cldebug100_test.cpp
+++ b/third_party/SPIRV-Tools/test/ext_inst.cldebug100_test.cpp
@@ -581,7 +581,7 @@
OpenCLDebugInfo100DebugSource, ExtInstCLDebugInfo100RoundTripTest,
::testing::ValuesIn(std::vector<InstructionCase>({
// TODO(dneto): Should this be a list of sourc texts,
- // to accomodate length limits?
+ // to accommodate length limits?
CASE_I(Source),
CASE_II(Source),
})));
diff --git a/third_party/SPIRV-Tools/test/ext_inst.opencl_test.cpp b/third_party/SPIRV-Tools/test/ext_inst.opencl_test.cpp
index 7547d92..d80a9bd 100644
--- a/third_party/SPIRV-Tools/test/ext_inst.opencl_test.cpp
+++ b/third_party/SPIRV-Tools/test/ext_inst.opencl_test.cpp
@@ -233,7 +233,7 @@
CASE3(UMad_hi, u_mad_hi), // enum value 204
})));
-// OpenCL.std: 2.3 Common instrucitons
+// OpenCL.std: 2.3 Common instructions
INSTANTIATE_TEST_SUITE_P(
OpenCLCommon, ExtInstOpenCLStdRoundTripTest,
::testing::ValuesIn(std::vector<InstructionCase>({
diff --git a/third_party/SPIRV-Tools/test/fuzz/fuzz_test_util.cpp b/third_party/SPIRV-Tools/test/fuzz/fuzz_test_util.cpp
index bf0a4ff..93c9c58 100644
--- a/third_party/SPIRV-Tools/test/fuzz/fuzz_test_util.cpp
+++ b/third_party/SPIRV-Tools/test/fuzz/fuzz_test_util.cpp
@@ -149,7 +149,7 @@
json_options.add_whitespace = true;
auto json_generation_status = google::protobuf::util::MessageToJsonString(
transformations, &json_string, json_options);
- if (json_generation_status == google::protobuf::util::Status::OK) {
+ if (json_generation_status.ok()) {
std::ofstream transformations_json_file(filename);
transformations_json_file << json_string;
transformations_json_file.close();
diff --git a/third_party/SPIRV-Tools/test/fuzz/fuzzerutil_test.cpp b/third_party/SPIRV-Tools/test/fuzz/fuzzerutil_test.cpp
index 0ad3e74..1286d38 100644
--- a/third_party/SPIRV-Tools/test/fuzz/fuzzerutil_test.cpp
+++ b/third_party/SPIRV-Tools/test/fuzz/fuzzerutil_test.cpp
@@ -70,7 +70,7 @@
ASSERT_TRUE(fuzzerutil::MaybeFindBlock(ir_context, block_id2) != nullptr);
// Block with id 13 cannot be found.
ASSERT_FALSE(fuzzerutil::MaybeFindBlock(ir_context, block_id3) != nullptr);
- // Block with id 8 exisits but don't not of type OpLabel.
+ // Block with id 8 exists but don't not of type OpLabel.
ASSERT_FALSE(fuzzerutil::MaybeFindBlock(ir_context, block_id4) != nullptr);
}
@@ -965,7 +965,7 @@
ASSERT_EQ(
91, fuzzerutil::MaybeGetPointerType(ir_context, 90, input_storage_class));
- // A pointer with id=91 and pointee type 90 exisits, but the type should be
+ // A pointer with id=91 and pointee type 90 exists, but the type should be
// input.
ASSERT_EQ(0, fuzzerutil::MaybeGetPointerType(ir_context, 90,
function_storage_class));
diff --git a/third_party/SPIRV-Tools/test/fuzz/transformation_add_parameter_test.cpp b/third_party/SPIRV-Tools/test/fuzz/transformation_add_parameter_test.cpp
index 2ae60c9..7f069b5 100644
--- a/third_party/SPIRV-Tools/test/fuzz/transformation_add_parameter_test.cpp
+++ b/third_party/SPIRV-Tools/test/fuzz/transformation_add_parameter_test.cpp
@@ -367,7 +367,7 @@
transformation_bad_3.IsApplicable(context.get(), transformation_context));
// Function with id 14 does not have any callers.
- // Bad: Id 18 is not a vaild type.
+ // Bad: Id 18 is not a valid type.
TransformationAddParameter transformation_bad_4(14, 50, 18, {{}}, 51);
ASSERT_FALSE(
transformation_bad_4.IsApplicable(context.get(), transformation_context));
diff --git a/third_party/SPIRV-Tools/test/fuzz/transformation_add_type_int_test.cpp b/third_party/SPIRV-Tools/test/fuzz/transformation_add_type_int_test.cpp
index ed8e00a..4cbfed0 100644
--- a/third_party/SPIRV-Tools/test/fuzz/transformation_add_type_int_test.cpp
+++ b/third_party/SPIRV-Tools/test/fuzz/transformation_add_type_int_test.cpp
@@ -87,7 +87,7 @@
transformation.IsApplicable(context.get(), transformation_context));
// By default SPIR-V does not support 16-bit integers.
- // Below we add such capability, so the test should now be succesful.
+ // Below we add such capability, so the test should now be successful.
context.get()->get_feature_mgr()->AddCapability(SpvCapabilityInt16);
ASSERT_TRUE(TransformationAddTypeInt(7, 16, true)
.IsApplicable(context.get(), transformation_context));
diff --git a/third_party/SPIRV-Tools/test/fuzz/transformation_adjust_branch_weights_test.cpp b/third_party/SPIRV-Tools/test/fuzz/transformation_adjust_branch_weights_test.cpp
index 1bf2c59..5984a3e 100644
--- a/third_party/SPIRV-Tools/test/fuzz/transformation_adjust_branch_weights_test.cpp
+++ b/third_party/SPIRV-Tools/test/fuzz/transformation_adjust_branch_weights_test.cpp
@@ -106,7 +106,7 @@
kConsoleMessageConsumer));
TransformationContext transformation_context(
MakeUnique<FactManager>(context.get()), validator_options);
- // Tests OpBranchConditional instruction with weigths.
+ // Tests OpBranchConditional instruction with weights.
auto instruction_descriptor =
MakeInstructionDescriptor(33, SpvOpBranchConditional, 0);
auto transformation =
diff --git a/third_party/SPIRV-Tools/test/fuzzers/BUILD.gn b/third_party/SPIRV-Tools/test/fuzzers/BUILD.gn
index 2aef4e8..fc458a4 100644
--- a/third_party/SPIRV-Tools/test/fuzzers/BUILD.gn
+++ b/third_party/SPIRV-Tools/test/fuzzers/BUILD.gn
@@ -87,18 +87,21 @@
spvtools_fuzzer("spvtools_opt_performance_fuzzer_src") {
sources = [
"spvtools_opt_performance_fuzzer.cpp",
+ "spvtools_opt_fuzzer_common.cpp",
]
}
spvtools_fuzzer("spvtools_opt_legalization_fuzzer_src") {
sources = [
"spvtools_opt_legalization_fuzzer.cpp",
+ "spvtools_opt_fuzzer_common.cpp",
]
}
spvtools_fuzzer("spvtools_opt_size_fuzzer_src") {
sources = [
"spvtools_opt_size_fuzzer.cpp",
+ "spvtools_opt_fuzzer_common.cpp",
]
}
diff --git a/third_party/SPIRV-Tools/test/fuzzers/CMakeLists.txt b/third_party/SPIRV-Tools/test/fuzzers/CMakeLists.txt
index 50c4589..e1fe516 100644
--- a/third_party/SPIRV-Tools/test/fuzzers/CMakeLists.txt
+++ b/third_party/SPIRV-Tools/test/fuzzers/CMakeLists.txt
@@ -46,9 +46,9 @@
add_spvtools_libfuzzer_target(TARGET spvtools_as_fuzzer SRCS spvtools_as_fuzzer.cpp random_generator.cpp LIBS ${SPIRV_TOOLS_FULL_VISIBILITY})
add_spvtools_libfuzzer_target(TARGET spvtools_binary_parser_fuzzer SRCS spvtools_binary_parser_fuzzer.cpp random_generator.cpp LIBS ${SPIRV_TOOLS_FULL_VISIBILITY})
add_spvtools_libfuzzer_target(TARGET spvtools_dis_fuzzer SRCS spvtools_dis_fuzzer.cpp random_generator.cpp LIBS ${SPIRV_TOOLS_FULL_VISIBILITY})
- add_spvtools_libfuzzer_target(TARGET spvtools_opt_legalization_fuzzer SRCS spvtools_opt_legalization_fuzzer.cpp random_generator.cpp LIBS SPIRV-Tools-opt ${SPIRV_TOOLS_FULL_VISIBILITY})
- add_spvtools_libfuzzer_target(TARGET spvtools_opt_performance_fuzzer SRCS spvtools_opt_performance_fuzzer.cpp random_generator.cpp LIBS SPIRV-Tools-opt ${SPIRV_TOOLS_FULL_VISIBILITY})
- add_spvtools_libfuzzer_target(TARGET spvtools_opt_size_fuzzer SRCS spvtools_opt_size_fuzzer.cpp random_generator.cpp LIBS SPIRV-Tools-opt ${SPIRV_TOOLS_FULL_VISIBILITY})
+ add_spvtools_libfuzzer_target(TARGET spvtools_opt_legalization_fuzzer SRCS spvtools_opt_legalization_fuzzer.cpp spvtools_opt_fuzzer_common.cpp random_generator.cpp LIBS SPIRV-Tools-opt ${SPIRV_TOOLS_FULL_VISIBILITY})
+ add_spvtools_libfuzzer_target(TARGET spvtools_opt_performance_fuzzer SRCS spvtools_opt_performance_fuzzer.cpp spvtools_opt_fuzzer_common.cpp random_generator.cpp LIBS SPIRV-Tools-opt ${SPIRV_TOOLS_FULL_VISIBILITY})
+ add_spvtools_libfuzzer_target(TARGET spvtools_opt_size_fuzzer SRCS spvtools_opt_size_fuzzer.cpp spvtools_opt_fuzzer_common.cpp random_generator.cpp LIBS SPIRV-Tools-opt ${SPIRV_TOOLS_FULL_VISIBILITY})
add_spvtools_libfuzzer_target(TARGET spvtools_val_fuzzer SRCS spvtools_val_fuzzer.cpp random_generator.cpp LIBS ${SPIRV_TOOLS_FULL_VISIBILITY})
if (${SPIRV_BUILD_FUZZER})
add_spvtools_libfuzzer_target(TARGET spvtools_fuzz_fuzzer SRCS spvtools_fuzz_fuzzer.cpp random_generator.cpp LIBS SPIRV-Tools-fuzz ${SPIRV_TOOLS_FULL_VISIBILITY})
diff --git a/third_party/SPIRV-Tools/test/fuzzers/spvtools_as_fuzzer.cpp b/third_party/SPIRV-Tools/test/fuzzers/spvtools_as_fuzzer.cpp
index ba3f5b9..8ead1cf 100644
--- a/third_party/SPIRV-Tools/test/fuzzers/spvtools_as_fuzzer.cpp
+++ b/third_party/SPIRV-Tools/test/fuzzers/spvtools_as_fuzzer.cpp
@@ -32,22 +32,13 @@
return 0;
}
- std::vector<uint32_t> input;
- input.resize(size >> 2);
- size_t count = 0;
- for (size_t i = 0; (i + 3) < size; i += 4) {
- input[count++] = data[i] | (data[i + 1] << 8) | (data[i + 2] << 16) |
- (data[i + 3]) << 24;
- }
-
- std::vector<char> input_str;
- size_t char_count = input.size() * sizeof(uint32_t) / sizeof(char);
- input_str.resize(char_count);
- memcpy(input_str.data(), input.data(), input.size() * sizeof(uint32_t));
+ std::vector<char> contents;
+ contents.resize(size);
+ memcpy(contents.data(), data, size);
spv_binary binary = nullptr;
spv_diagnostic diagnostic = nullptr;
- spvTextToBinaryWithOptions(context, input_str.data(), input_str.size(),
+ spvTextToBinaryWithOptions(context, contents.data(), contents.size(),
SPV_TEXT_TO_BINARY_OPTION_NONE, &binary,
&diagnostic);
if (diagnostic) {
@@ -61,7 +52,7 @@
binary = nullptr;
}
- spvTextToBinaryWithOptions(context, input_str.data(), input_str.size(),
+ spvTextToBinaryWithOptions(context, contents.data(), contents.size(),
SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS,
&binary, &diagnostic);
if (diagnostic) {
diff --git a/third_party/SPIRV-Tools/test/fuzzers/spvtools_opt_fuzzer_common.cpp b/third_party/SPIRV-Tools/test/fuzzers/spvtools_opt_fuzzer_common.cpp
new file mode 100644
index 0000000..4978509
--- /dev/null
+++ b/third_party/SPIRV-Tools/test/fuzzers/spvtools_opt_fuzzer_common.cpp
@@ -0,0 +1,84 @@
+// Copyright (c) 2021 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "test/fuzzers/spvtools_opt_fuzzer_common.h"
+
+#include "source/opt/build_module.h"
+#include "test/fuzzers/random_generator.h"
+
+namespace spvtools {
+namespace fuzzers {
+
+int OptFuzzerTestOneInput(
+ const uint8_t* data, size_t size,
+ const std::function<void(spvtools::Optimizer&)>& register_passes) {
+ if (size < 1) {
+ return 0;
+ }
+
+ spvtools::fuzzers::RandomGenerator random_gen(data, size);
+ auto target_env = random_gen.GetTargetEnv();
+ spvtools::Optimizer optimizer(target_env);
+ optimizer.SetMessageConsumer([](spv_message_level_t, const char*,
+ const spv_position_t&, const char*) {});
+
+ std::vector<uint32_t> input;
+ input.resize(size >> 2);
+
+ size_t count = 0;
+ for (size_t i = 0; (i + 3) < size; i += 4) {
+ input[count++] = data[i] | (data[i + 1] << 8) | (data[i + 2] << 16) |
+ (data[i + 3]) << 24;
+ }
+
+ // The largest possible id bound is used when running the optimizer, to avoid
+ // the problem of id overflows.
+ const size_t kFinalIdLimit = UINT32_MAX;
+
+ // The input is scanned to check that it does not already use an id too close
+ // to this limit. This still gives the optimizer a large set of ids to
+ // consume. It is thus very unlikely that id overflow will occur during
+ // fuzzing. If it does, then the initial id limit should be decreased.
+ const size_t kInitialIdLimit = kFinalIdLimit - 1000000U;
+
+ // Build the module and scan it to check that all used ids are below the
+ // initial limit.
+ auto ir_context =
+ spvtools::BuildModule(target_env, nullptr, input.data(), input.size());
+ if (ir_context == nullptr) {
+ // It was not possible to build a valid module; that's OK - skip this input.
+ return 0;
+ }
+ if (ir_context->module()->id_bound() >= kInitialIdLimit) {
+ // The input already has a very large id bound. The input is thus abandoned,
+ // to avoid the possibility of ending up hitting the id bound limit.
+ return 0;
+ }
+
+ // Set the optimizer and its validator up with the largest possible id bound
+ // limit.
+ spvtools::ValidatorOptions validator_options;
+ spvtools::OptimizerOptions optimizer_options;
+ optimizer_options.set_max_id_bound(kFinalIdLimit);
+ validator_options.SetUniversalLimit(spv_validator_limit_max_id_bound,
+ kFinalIdLimit);
+ optimizer_options.set_validator_options(validator_options);
+ register_passes(optimizer);
+ optimizer.Run(input.data(), input.size(), &input, optimizer_options);
+
+ return 0;
+}
+
+} // namespace fuzzers
+} // namespace spvtools
diff --git a/third_party/SPIRV-Tools/test/fuzzers/spvtools_opt_fuzzer_common.h b/third_party/SPIRV-Tools/test/fuzzers/spvtools_opt_fuzzer_common.h
new file mode 100644
index 0000000..b8d4281
--- /dev/null
+++ b/third_party/SPIRV-Tools/test/fuzzers/spvtools_opt_fuzzer_common.h
@@ -0,0 +1,35 @@
+// Copyright (c) 2021 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef TEST_FUZZERS_SPVTOOLS_OPT_FUZZER_COMMON_H_
+#define TEST_FUZZERS_SPVTOOLS_OPT_FUZZER_COMMON_H_
+
+#include <cinttypes>
+#include <cstddef>
+#include <functional>
+
+#include "spirv-tools/optimizer.hpp"
+
+namespace spvtools {
+namespace fuzzers {
+
+// Helper function capturing the common logic for the various optimizer fuzzers.
+int OptFuzzerTestOneInput(
+ const uint8_t* data, size_t size,
+ const std::function<void(spvtools::Optimizer&)>& register_passes);
+
+} // namespace fuzzers
+} // namespace spvtools
+
+#endif // TEST_FUZZERS_SPVTOOLS_OPT_FUZZER_COMMON_H_
diff --git a/third_party/SPIRV-Tools/test/fuzzers/spvtools_opt_legalization_fuzzer.cpp b/third_party/SPIRV-Tools/test/fuzzers/spvtools_opt_legalization_fuzzer.cpp
index 6f4d7e8..fac4d23 100644
--- a/third_party/SPIRV-Tools/test/fuzzers/spvtools_opt_legalization_fuzzer.cpp
+++ b/third_party/SPIRV-Tools/test/fuzzers/spvtools_opt_legalization_fuzzer.cpp
@@ -12,33 +12,16 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include <cstdint>
-#include <vector>
+#include <cinttypes>
+#include <cstddef>
+#include <functional>
#include "spirv-tools/optimizer.hpp"
-#include "test/fuzzers/random_generator.h"
+#include "test/fuzzers/spvtools_opt_fuzzer_common.h"
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
- if (size < 1) {
- return 0;
- }
-
- spvtools::fuzzers::RandomGenerator random_gen(data, size);
- spvtools::Optimizer optimizer(random_gen.GetTargetEnv());
- optimizer.SetMessageConsumer([](spv_message_level_t, const char*,
- const spv_position_t&, const char*) {});
-
- std::vector<uint32_t> input;
- input.resize(size >> 2);
-
- size_t count = 0;
- for (size_t i = 0; (i + 3) < size; i += 4) {
- input[count++] = data[i] | (data[i + 1] << 8) | (data[i + 2] << 16) |
- (data[i + 3]) << 24;
- }
-
- optimizer.RegisterLegalizationPasses();
- optimizer.Run(input.data(), input.size(), &input);
-
- return 0;
+ return spvtools::fuzzers::OptFuzzerTestOneInput(
+ data, size, [](spvtools::Optimizer& optimizer) -> void {
+ optimizer.RegisterLegalizationPasses();
+ });
}
diff --git a/third_party/SPIRV-Tools/test/fuzzers/spvtools_opt_performance_fuzzer.cpp b/third_party/SPIRV-Tools/test/fuzzers/spvtools_opt_performance_fuzzer.cpp
index 9c47d7d..e6038b9 100644
--- a/third_party/SPIRV-Tools/test/fuzzers/spvtools_opt_performance_fuzzer.cpp
+++ b/third_party/SPIRV-Tools/test/fuzzers/spvtools_opt_performance_fuzzer.cpp
@@ -12,33 +12,16 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include <cstdint>
-#include <vector>
+#include <cinttypes>
+#include <cstddef>
+#include <functional>
#include "spirv-tools/optimizer.hpp"
-#include "test/fuzzers/random_generator.h"
+#include "test/fuzzers/spvtools_opt_fuzzer_common.h"
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
- if (size < 1) {
- return 0;
- }
-
- spvtools::fuzzers::RandomGenerator random_gen(data, size);
- spvtools::Optimizer optimizer(random_gen.GetTargetEnv());
- optimizer.SetMessageConsumer([](spv_message_level_t, const char*,
- const spv_position_t&, const char*) {});
-
- std::vector<uint32_t> input;
- input.resize(size >> 2);
-
- size_t count = 0;
- for (size_t i = 0; (i + 3) < size; i += 4) {
- input[count++] = data[i] | (data[i + 1] << 8) | (data[i + 2] << 16) |
- (data[i + 3]) << 24;
- }
-
- optimizer.RegisterPerformancePasses();
- optimizer.Run(input.data(), input.size(), &input);
-
- return 0;
+ return spvtools::fuzzers::OptFuzzerTestOneInput(
+ data, size, [](spvtools::Optimizer& optimizer) -> void {
+ optimizer.RegisterPerformancePasses();
+ });
}
diff --git a/third_party/SPIRV-Tools/test/fuzzers/spvtools_opt_size_fuzzer.cpp b/third_party/SPIRV-Tools/test/fuzzers/spvtools_opt_size_fuzzer.cpp
index 10fac42..65492b1 100644
--- a/third_party/SPIRV-Tools/test/fuzzers/spvtools_opt_size_fuzzer.cpp
+++ b/third_party/SPIRV-Tools/test/fuzzers/spvtools_opt_size_fuzzer.cpp
@@ -12,33 +12,16 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include <cstdint>
-#include <vector>
+#include <cinttypes>
+#include <cstddef>
+#include <functional>
#include "spirv-tools/optimizer.hpp"
-#include "test/fuzzers/random_generator.h"
+#include "test/fuzzers/spvtools_opt_fuzzer_common.h"
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
- if (size < 1) {
- return 0;
- }
-
- spvtools::fuzzers::RandomGenerator random_gen(data, size);
- spvtools::Optimizer optimizer(random_gen.GetTargetEnv());
- optimizer.SetMessageConsumer([](spv_message_level_t, const char*,
- const spv_position_t&, const char*) {});
-
- std::vector<uint32_t> input;
- input.resize(size >> 2);
-
- size_t count = 0;
- for (size_t i = 0; (i + 3) < size; i += 4) {
- input[count++] = data[i] | (data[i + 1] << 8) | (data[i + 2] << 16) |
- (data[i + 3]) << 24;
- }
-
- optimizer.RegisterSizePasses();
- optimizer.Run(input.data(), input.size(), &input);
-
- return 0;
+ return spvtools::fuzzers::OptFuzzerTestOneInput(
+ data, size, [](spvtools::Optimizer& optimizer) -> void {
+ optimizer.RegisterSizePasses();
+ });
}
diff --git a/third_party/SPIRV-Tools/test/hex_float_test.cpp b/third_party/SPIRV-Tools/test/hex_float_test.cpp
index ffdb8bd..7edfd43 100644
--- a/third_party/SPIRV-Tools/test/hex_float_test.cpp
+++ b/third_party/SPIRV-Tools/test/hex_float_test.cpp
@@ -1343,7 +1343,7 @@
template <typename T>
std::ostream& operator<<(std::ostream& os, const StreamParseCase<T>& fspc) {
os << "StreamParseCase(" << fspc.literal
- << ", expect_succes:" << int(fspc.expect_success) << ","
+ << ", expect_success:" << int(fspc.expect_success) << ","
<< fspc.expected_suffix << "," << fspc.expected_value << ")";
return os;
}
diff --git a/third_party/SPIRV-Tools/test/link/binary_version_test.cpp b/third_party/SPIRV-Tools/test/link/binary_version_test.cpp
index 80aab0f..a56030f 100644
--- a/third_party/SPIRV-Tools/test/link/binary_version_test.cpp
+++ b/third_party/SPIRV-Tools/test/link/binary_version_test.cpp
@@ -20,40 +20,57 @@
namespace spvtools {
namespace {
+using ::testing::HasSubstr;
using BinaryVersion = spvtest::LinkerTest;
-TEST_F(BinaryVersion, LinkerChoosesMaxSpirvVersion) {
+spvtest::Binary CreateBinary(uint32_t version) {
+ return {
+ // clang-format off
+ // Header
+ SpvMagicNumber,
+ version,
+ SPV_GENERATOR_WORD(SPV_GENERATOR_KHRONOS, 0),
+ 1u, // NOTE: Bound
+ 0u, // NOTE: Schema; reserved
+
+ // OpCapability Shader
+ SpvOpCapability | 2u << SpvWordCountShift,
+ SpvCapabilityShader,
+
+ // OpMemoryModel Logical Simple
+ SpvOpMemoryModel | 3u << SpvWordCountShift,
+ SpvAddressingModelLogical,
+ SpvMemoryModelSimple
+ // clang-format on
+ };
+}
+
+TEST_F(BinaryVersion, Match) {
// clang-format off
spvtest::Binaries binaries = {
- {
- SpvMagicNumber,
- 0x00010300u,
- SPV_GENERATOR_CODEPLAY,
- 1u, // NOTE: Bound
- 0u // NOTE: Schema; reserved
- },
- {
- SpvMagicNumber,
- 0x00010500u,
- SPV_GENERATOR_CODEPLAY,
- 1u, // NOTE: Bound
- 0u // NOTE: Schema; reserved
- },
- {
- SpvMagicNumber,
- 0x00010100u,
- SPV_GENERATOR_CODEPLAY,
- 1u, // NOTE: Bound
- 0u // NOTE: Schema; reserved
- }
+ CreateBinary(SPV_SPIRV_VERSION_WORD(1, 3)),
+ CreateBinary(SPV_SPIRV_VERSION_WORD(1, 3)),
};
// clang-format on
spvtest::Binary linked_binary;
-
- ASSERT_EQ(SPV_SUCCESS, Link(binaries, &linked_binary));
+ ASSERT_EQ(SPV_SUCCESS, Link(binaries, &linked_binary)) << GetErrorMessage();
EXPECT_THAT(GetErrorMessage(), std::string());
+ EXPECT_EQ(SPV_SPIRV_VERSION_WORD(1, 3), linked_binary[1]);
+}
- EXPECT_EQ(0x00010500u, linked_binary[1]);
+TEST_F(BinaryVersion, Mismatch) {
+ // clang-format off
+ spvtest::Binaries binaries = {
+ CreateBinary(SPV_SPIRV_VERSION_WORD(1, 3)),
+ CreateBinary(SPV_SPIRV_VERSION_WORD(1, 5)),
+ };
+ // clang-format on
+ spvtest::Binary linked_binary;
+ ASSERT_EQ(SPV_ERROR_INTERNAL, Link(binaries, &linked_binary))
+ << GetErrorMessage();
+ EXPECT_THAT(GetErrorMessage(),
+ HasSubstr("Conflicting SPIR-V versions: 1.3 (input modules 1 "
+ "through 1) vs 1.5 (input module 2)."));
}
} // namespace
diff --git a/third_party/SPIRV-Tools/test/link/entry_points_test.cpp b/third_party/SPIRV-Tools/test/link/entry_points_test.cpp
index bac8e02..df7ea20 100644
--- a/third_party/SPIRV-Tools/test/link/entry_points_test.cpp
+++ b/third_party/SPIRV-Tools/test/link/entry_points_test.cpp
@@ -26,6 +26,8 @@
TEST_F(EntryPoints, SameModelDifferentName) {
const std::string body1 = R"(
+OpCapability Shader
+OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %3 "foo"
%1 = OpTypeVoid
%2 = OpTypeFunction %1
@@ -33,6 +35,8 @@
OpFunctionEnd
)";
const std::string body2 = R"(
+OpCapability Shader
+OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %3 "bar"
%1 = OpTypeVoid
%2 = OpTypeFunction %1
@@ -41,12 +45,15 @@
)";
spvtest::Binary linked_binary;
- EXPECT_EQ(SPV_SUCCESS, AssembleAndLink({body1, body2}, &linked_binary));
+ ASSERT_EQ(SPV_SUCCESS, AssembleAndLink({body1, body2}, &linked_binary))
+ << GetErrorMessage();
EXPECT_THAT(GetErrorMessage(), std::string());
}
TEST_F(EntryPoints, DifferentModelSameName) {
const std::string body1 = R"(
+OpCapability Shader
+OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %3 "foo"
%1 = OpTypeVoid
%2 = OpTypeFunction %1
@@ -54,6 +61,8 @@
OpFunctionEnd
)";
const std::string body2 = R"(
+OpCapability Shader
+OpMemoryModel Logical GLSL450
OpEntryPoint Vertex %3 "foo"
%1 = OpTypeVoid
%2 = OpTypeFunction %1
@@ -62,12 +71,15 @@
)";
spvtest::Binary linked_binary;
- EXPECT_EQ(SPV_SUCCESS, AssembleAndLink({body1, body2}, &linked_binary));
+ ASSERT_EQ(SPV_SUCCESS, AssembleAndLink({body1, body2}, &linked_binary))
+ << GetErrorMessage();
EXPECT_THAT(GetErrorMessage(), std::string());
}
TEST_F(EntryPoints, SameModelAndName) {
const std::string body1 = R"(
+OpCapability Shader
+OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %3 "foo"
%1 = OpTypeVoid
%2 = OpTypeFunction %1
@@ -75,6 +87,8 @@
OpFunctionEnd
)";
const std::string body2 = R"(
+OpCapability Shader
+OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %3 "foo"
%1 = OpTypeVoid
%2 = OpTypeFunction %1
diff --git a/third_party/SPIRV-Tools/test/link/global_values_amount_test.cpp b/third_party/SPIRV-Tools/test/link/global_values_amount_test.cpp
index 2c4ee1f..3158b7e 100644
--- a/third_party/SPIRV-Tools/test/link/global_values_amount_test.cpp
+++ b/third_party/SPIRV-Tools/test/link/global_values_amount_test.cpp
@@ -22,85 +22,56 @@
using ::testing::HasSubstr;
+const uint32_t binary_count = 2u;
+
class EntryPointsAmountTest : public spvtest::LinkerTest {
public:
- EntryPointsAmountTest() { binaries.reserve(0xFFFF); }
+ EntryPointsAmountTest() { binaries.reserve(binary_count + 1u); }
void SetUp() override {
- binaries.push_back({SpvMagicNumber,
- SpvVersion,
- SPV_GENERATOR_CODEPLAY,
- 10u, // NOTE: Bound
- 0u, // NOTE: Schema; reserved
+ const uint32_t global_variable_count_per_binary =
+ (SPV_LIMIT_GLOBAL_VARIABLES_MAX - 1u) / binary_count;
- 3u << SpvWordCountShift | SpvOpTypeFloat,
- 1u, // NOTE: Result ID
- 32u, // NOTE: Width
+ spvtest::Binary common_binary = {
+ // clang-format off
+ SpvMagicNumber,
+ SpvVersion,
+ SPV_GENERATOR_WORD(SPV_GENERATOR_KHRONOS, 0),
+ 3u + global_variable_count_per_binary, // NOTE: Bound
+ 0u, // NOTE: Schema; reserved
- 4u << SpvWordCountShift | SpvOpTypePointer,
- 2u, // NOTE: Result ID
- SpvStorageClassInput,
- 1u, // NOTE: Type ID
+ SpvOpCapability | 2u << SpvWordCountShift,
+ SpvCapabilityShader,
- 2u << SpvWordCountShift | SpvOpTypeVoid,
- 3u, // NOTE: Result ID
+ SpvOpMemoryModel | 3u << SpvWordCountShift,
+ SpvAddressingModelLogical,
+ SpvMemoryModelSimple,
- 3u << SpvWordCountShift | SpvOpTypeFunction,
- 4u, // NOTE: Result ID
- 3u, // NOTE: Return type
+ SpvOpTypeFloat | 3u << SpvWordCountShift,
+ 1u, // NOTE: Result ID
+ 32u, // NOTE: Width
- 5u << SpvWordCountShift | SpvOpFunction,
- 3u, // NOTE: Result type
- 5u, // NOTE: Result ID
- SpvFunctionControlMaskNone,
- 4u, // NOTE: Function type
+ SpvOpTypePointer | 4u << SpvWordCountShift,
+ 2u, // NOTE: Result ID
+ SpvStorageClassInput,
+ 1u // NOTE: Type ID
+ // clang-format on
+ };
- 2u << SpvWordCountShift | SpvOpLabel,
- 6u, // NOTE: Result ID
+ binaries.push_back({});
+ spvtest::Binary& binary = binaries.back();
+ binary.reserve(common_binary.size() + global_variable_count_per_binary * 4);
+ binary.insert(binary.end(), common_binary.cbegin(), common_binary.cend());
- 4u << SpvWordCountShift | SpvOpVariable,
- 2u, // NOTE: Type ID
- 7u, // NOTE: Result ID
- SpvStorageClassFunction,
+ for (uint32_t i = 0u; i < global_variable_count_per_binary; ++i) {
+ binary.push_back(SpvOpVariable | 4u << SpvWordCountShift);
+ binary.push_back(2u); // NOTE: Type ID
+ binary.push_back(3u + i); // NOTE: Result ID
+ binary.push_back(SpvStorageClassInput);
+ }
- 4u << SpvWordCountShift | SpvOpVariable,
- 2u, // NOTE: Type ID
- 8u, // NOTE: Result ID
- SpvStorageClassFunction,
-
- 4u << SpvWordCountShift | SpvOpVariable,
- 2u, // NOTE: Type ID
- 9u, // NOTE: Result ID
- SpvStorageClassFunction,
-
- 1u << SpvWordCountShift | SpvOpReturn,
-
- 1u << SpvWordCountShift | SpvOpFunctionEnd});
- for (size_t i = 0u; i < 2u; ++i) {
- spvtest::Binary binary = {
- SpvMagicNumber,
- SpvVersion,
- SPV_GENERATOR_CODEPLAY,
- 103u, // NOTE: Bound
- 0u, // NOTE: Schema; reserved
-
- 3u << SpvWordCountShift | SpvOpTypeFloat,
- 1u, // NOTE: Result ID
- 32u, // NOTE: Width
-
- 4u << SpvWordCountShift | SpvOpTypePointer,
- 2u, // NOTE: Result ID
- SpvStorageClassInput,
- 1u // NOTE: Type ID
- };
-
- for (uint32_t j = 0u; j < 0xFFFFu / 2u; ++j) {
- binary.push_back(4u << SpvWordCountShift | SpvOpVariable);
- binary.push_back(2u); // NOTE: Type ID
- binary.push_back(j + 3u); // NOTE: Result ID
- binary.push_back(SpvStorageClassInput);
- }
- binaries.push_back(binary);
+ for (uint32_t i = 0u; i < binary_count - 1u; ++i) {
+ binaries.push_back(binaries.back());
}
}
void TearDown() override { binaries.clear(); }
@@ -111,42 +82,53 @@
TEST_F(EntryPointsAmountTest, UnderLimit) {
spvtest::Binary linked_binary;
- EXPECT_EQ(SPV_SUCCESS, Link(binaries, &linked_binary));
+ ASSERT_EQ(SPV_SUCCESS, Link(binaries, &linked_binary)) << GetErrorMessage();
EXPECT_THAT(GetErrorMessage(), std::string());
}
TEST_F(EntryPointsAmountTest, OverLimit) {
- binaries.push_back({SpvMagicNumber,
- SpvVersion,
- SPV_GENERATOR_CODEPLAY,
- 5u, // NOTE: Bound
- 0u, // NOTE: Schema; reserved
+ binaries.push_back({
+ // clang-format off
+ SpvMagicNumber,
+ SpvVersion,
+ SPV_GENERATOR_WORD(SPV_GENERATOR_KHRONOS, 0),
+ 5u, // NOTE: Bound
+ 0u, // NOTE: Schema; reserved
- 3u << SpvWordCountShift | SpvOpTypeFloat,
- 1u, // NOTE: Result ID
- 32u, // NOTE: Width
+ SpvOpCapability | 2u << SpvWordCountShift,
+ SpvCapabilityShader,
- 4u << SpvWordCountShift | SpvOpTypePointer,
- 2u, // NOTE: Result ID
- SpvStorageClassInput,
- 1u, // NOTE: Type ID
+ SpvOpMemoryModel | 3u << SpvWordCountShift,
+ SpvAddressingModelLogical,
+ SpvMemoryModelSimple,
- 4u << SpvWordCountShift | SpvOpVariable,
- 2u, // NOTE: Type ID
- 3u, // NOTE: Result ID
- SpvStorageClassInput,
+ SpvOpTypeFloat | 3u << SpvWordCountShift,
+ 1u, // NOTE: Result ID
+ 32u, // NOTE: Width
- 4u << SpvWordCountShift | SpvOpVariable,
- 2u, // NOTE: Type ID
- 4u, // NOTE: Result ID
- SpvStorageClassInput});
+ SpvOpTypePointer | 4u << SpvWordCountShift,
+ 2u, // NOTE: Result ID
+ SpvStorageClassInput,
+ 1u, // NOTE: Type ID
+
+ SpvOpVariable | 4u << SpvWordCountShift,
+ 2u, // NOTE: Type ID
+ 3u, // NOTE: Result ID
+ SpvStorageClassInput,
+
+ SpvOpVariable | 4u << SpvWordCountShift,
+ 2u, // NOTE: Type ID
+ 4u, // NOTE: Result ID
+ SpvStorageClassInput
+ // clang-format on
+ });
spvtest::Binary linked_binary;
-
- EXPECT_EQ(SPV_ERROR_INTERNAL, Link(binaries, &linked_binary));
- EXPECT_THAT(GetErrorMessage(),
- HasSubstr("The limit of global values, 65535, was exceeded; "
- "65536 global values were found."));
+ ASSERT_EQ(SPV_SUCCESS, Link(binaries, &linked_binary)) << GetErrorMessage();
+ EXPECT_THAT(
+ GetErrorMessage(),
+ HasSubstr("The minimum limit of global values, 65535, was exceeded; "
+ "65536 global values were found."));
}
} // namespace
diff --git a/third_party/SPIRV-Tools/test/link/ids_limit_test.cpp b/third_party/SPIRV-Tools/test/link/ids_limit_test.cpp
index 6d7815a..846fbef 100644
--- a/third_party/SPIRV-Tools/test/link/ids_limit_test.cpp
+++ b/third_party/SPIRV-Tools/test/link/ids_limit_test.cpp
@@ -21,51 +21,114 @@
namespace {
using ::testing::HasSubstr;
-using IdsLimit = spvtest::LinkerTest;
-TEST_F(IdsLimit, UnderLimit) {
- spvtest::Binaries binaries = {
- {
- SpvMagicNumber, SpvVersion, SPV_GENERATOR_CODEPLAY,
- 0x2FFFFFu, // NOTE: Bound
- 0u, // NOTE: Schema; reserved
- },
- {
- SpvMagicNumber, SpvVersion, SPV_GENERATOR_CODEPLAY,
- 0x100000u, // NOTE: Bound
- 0u, // NOTE: Schema; reserved
- }};
- spvtest::Binary linked_binary;
+class IdsLimit : public spvtest::LinkerTest {
+ public:
+ IdsLimit() { binaries.reserve(2u); }
- ASSERT_EQ(SPV_SUCCESS, Link(binaries, &linked_binary));
- EXPECT_THAT(GetErrorMessage(), std::string());
- EXPECT_EQ(0x3FFFFEu, linked_binary[3]);
+ void SetUp() override {
+ const uint32_t id_bound = SPV_LIMIT_RESULT_ID_BOUND - 1u;
+ const uint32_t constant_count =
+ id_bound -
+ 2u; // One ID is used for TypeBool, and (constant_count + 1) < id_bound
+
+ // This is needed, as otherwise the ID bound will get reset to 1 while
+ // running the RemoveDuplicates pass.
+ spvtest::Binary common_binary = {
+ // clang-format off
+ SpvMagicNumber,
+ SpvVersion,
+ SPV_GENERATOR_WORD(SPV_GENERATOR_KHRONOS, 0),
+ id_bound, // NOTE: Bound
+ 0u, // NOTE: Schema; reserved
+
+ SpvOpCapability | 2u << SpvWordCountShift,
+ SpvCapabilityShader,
+
+ SpvOpMemoryModel | 3u << SpvWordCountShift,
+ SpvAddressingModelLogical,
+ SpvMemoryModelSimple,
+
+ SpvOpTypeBool | 2u << SpvWordCountShift,
+ 1u // NOTE: Result ID
+ // clang-format on
+ };
+
+ binaries.push_back({});
+ spvtest::Binary& binary = binaries.back();
+ binary.reserve(common_binary.size() + constant_count * 3u);
+ binary.insert(binary.end(), common_binary.cbegin(), common_binary.cend());
+
+ for (uint32_t i = 0u; i < constant_count; ++i) {
+ binary.push_back(SpvOpConstantTrue | 3u << SpvWordCountShift);
+ binary.push_back(1u); // NOTE: Type ID
+ binary.push_back(2u + i); // NOTE: Result ID
+ }
+ }
+ void TearDown() override { binaries.clear(); }
+
+ spvtest::Binaries binaries;
+};
+
+spvtest::Binary CreateBinary(uint32_t id_bound) {
+ return {
+ // clang-format off
+ // Header
+ SpvMagicNumber,
+ SpvVersion,
+ SPV_GENERATOR_WORD(SPV_GENERATOR_KHRONOS, 0),
+ id_bound, // NOTE: Bound
+ 0u, // NOTE: Schema; reserved
+
+ // OpCapability Shader
+ SpvOpCapability | 2u << SpvWordCountShift,
+ SpvCapabilityShader,
+
+ // OpMemoryModel Logical Simple
+ SpvOpMemoryModel | 3u << SpvWordCountShift,
+ SpvAddressingModelLogical,
+ SpvMemoryModelSimple
+ // clang-format on
+ };
}
-TEST_F(IdsLimit, OverLimit) {
- spvtest::Binaries binaries = {
- {
- SpvMagicNumber, SpvVersion, SPV_GENERATOR_CODEPLAY,
- 0x2FFFFFu, // NOTE: Bound
- 0u, // NOTE: Schema; reserved
- },
- {
- SpvMagicNumber, SpvVersion, SPV_GENERATOR_CODEPLAY,
- 0x100000u, // NOTE: Bound
- 0u, // NOTE: Schema; reserved
- },
- {
- SpvMagicNumber, SpvVersion, SPV_GENERATOR_CODEPLAY,
- 3u, // NOTE: Bound
- 0u, // NOTE: Schema; reserved
- }};
+TEST_F(IdsLimit, DISABLED_UnderLimit) {
+ spvtest::Binary linked_binary;
+ ASSERT_EQ(SPV_SUCCESS, Link(binaries, &linked_binary)) << GetErrorMessage();
+ EXPECT_THAT(GetErrorMessage(), std::string());
+ EXPECT_EQ(0x3FFFFFu, linked_binary[3]);
+}
+
+TEST_F(IdsLimit, DISABLED_OverLimit) {
+ spvtest::Binary& binary = binaries.back();
+
+ const uint32_t id_bound = binary[3];
+ binary[3] = id_bound + 1u;
+
+ binary.push_back(SpvOpConstantFalse | 3u << SpvWordCountShift);
+ binary.push_back(1u); // NOTE: Type ID
+ binary.push_back(id_bound); // NOTE: Result ID
+
+ spvtest::Binary linked_binary;
+ ASSERT_EQ(SPV_SUCCESS, Link(binaries, &linked_binary)) << GetErrorMessage();
+ EXPECT_THAT(
+ GetErrorMessage(),
+ HasSubstr("The minimum limit of IDs, 4194303, was exceeded: 4194304 is "
+ "the current ID bound."));
+ EXPECT_EQ(0x400000u, linked_binary[3]);
+}
+
+TEST_F(IdsLimit, DISABLED_Overflow) {
+ spvtest::Binaries binaries = {CreateBinary(0xFFFFFFFFu),
+ CreateBinary(0x00000002u)};
spvtest::Binary linked_binary;
- EXPECT_EQ(SPV_ERROR_INVALID_ID, Link(binaries, &linked_binary));
- EXPECT_THAT(GetErrorMessage(),
- HasSubstr("The limit of IDs, 4194303, was exceeded: 4194304 is "
- "the current ID bound."));
+ EXPECT_EQ(SPV_ERROR_INVALID_DATA, Link(binaries, &linked_binary));
+ EXPECT_THAT(
+ GetErrorMessage(),
+ HasSubstr("Too many IDs (4294967296): combining all modules would "
+ "overflow the 32-bit word of the SPIR-V header."));
}
} // namespace
diff --git a/third_party/SPIRV-Tools/test/link/matching_imports_to_exports_test.cpp b/third_party/SPIRV-Tools/test/link/matching_imports_to_exports_test.cpp
index e76c69f..6b02fc4 100644
--- a/third_party/SPIRV-Tools/test/link/matching_imports_to_exports_test.cpp
+++ b/third_party/SPIRV-Tools/test/link/matching_imports_to_exports_test.cpp
@@ -26,6 +26,9 @@
TEST_F(MatchingImportsToExports, Default) {
const std::string body1 = R"(
OpCapability Linkage
+OpCapability Addresses
+OpCapability Kernel
+OpMemoryModel Physical64 OpenCL
OpDecorate %1 LinkageAttributes "foo" Import
%2 = OpTypeFloat 32
%1 = OpVariable %2 Uniform
@@ -33,6 +36,9 @@
)";
const std::string body2 = R"(
OpCapability Linkage
+OpCapability Addresses
+OpCapability Kernel
+OpMemoryModel Physical64 OpenCL
OpDecorate %1 LinkageAttributes "foo" Export
%2 = OpTypeFloat 32
%3 = OpConstant %2 42
@@ -40,11 +46,14 @@
)";
spvtest::Binary linked_binary;
- EXPECT_EQ(SPV_SUCCESS, AssembleAndLink({body1, body2}, &linked_binary))
+ ASSERT_EQ(SPV_SUCCESS, AssembleAndLink({body1, body2}, &linked_binary))
<< GetErrorMessage();
const std::string expected_res =
- R"(OpModuleProcessed "Linked by SPIR-V Tools Linker"
+ R"(OpCapability Addresses
+OpCapability Kernel
+OpMemoryModel Physical64 OpenCL
+OpModuleProcessed "Linked by SPIR-V Tools Linker"
%1 = OpTypeFloat 32
%2 = OpVariable %1 Input
%3 = OpConstant %1 42
@@ -52,7 +61,7 @@
)";
std::string res_body;
SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
- EXPECT_EQ(SPV_SUCCESS, Disassemble(linked_binary, &res_body))
+ ASSERT_EQ(SPV_SUCCESS, Disassemble(linked_binary, &res_body))
<< GetErrorMessage();
EXPECT_EQ(expected_res, res_body);
}
@@ -60,23 +69,29 @@
TEST_F(MatchingImportsToExports, NotALibraryExtraExports) {
const std::string body = R"(
OpCapability Linkage
+OpCapability Addresses
+OpCapability Kernel
+OpMemoryModel Physical64 OpenCL
OpDecorate %1 LinkageAttributes "foo" Export
%2 = OpTypeFloat 32
%1 = OpVariable %2 Uniform
)";
spvtest::Binary linked_binary;
- EXPECT_EQ(SPV_SUCCESS, AssembleAndLink({body}, &linked_binary))
+ ASSERT_EQ(SPV_SUCCESS, AssembleAndLink({body}, &linked_binary))
<< GetErrorMessage();
const std::string expected_res =
- R"(OpModuleProcessed "Linked by SPIR-V Tools Linker"
+ R"(OpCapability Addresses
+OpCapability Kernel
+OpMemoryModel Physical64 OpenCL
+OpModuleProcessed "Linked by SPIR-V Tools Linker"
%1 = OpTypeFloat 32
%2 = OpVariable %1 Uniform
)";
std::string res_body;
SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
- EXPECT_EQ(SPV_SUCCESS, Disassemble(linked_binary, &res_body))
+ ASSERT_EQ(SPV_SUCCESS, Disassemble(linked_binary, &res_body))
<< GetErrorMessage();
EXPECT_EQ(expected_res, res_body);
}
@@ -84,6 +99,9 @@
TEST_F(MatchingImportsToExports, LibraryExtraExports) {
const std::string body = R"(
OpCapability Linkage
+OpCapability Addresses
+OpCapability Kernel
+OpMemoryModel Physical64 OpenCL
OpDecorate %1 LinkageAttributes "foo" Export
%2 = OpTypeFloat 32
%1 = OpVariable %2 Uniform
@@ -92,10 +110,13 @@
spvtest::Binary linked_binary;
LinkerOptions options;
options.SetCreateLibrary(true);
- EXPECT_EQ(SPV_SUCCESS, AssembleAndLink({body}, &linked_binary, options))
+ ASSERT_EQ(SPV_SUCCESS, AssembleAndLink({body}, &linked_binary, options))
<< GetErrorMessage();
const std::string expected_res = R"(OpCapability Linkage
+OpCapability Addresses
+OpCapability Kernel
+OpMemoryModel Physical64 OpenCL
OpModuleProcessed "Linked by SPIR-V Tools Linker"
OpDecorate %1 LinkageAttributes "foo" Export
%2 = OpTypeFloat 32
@@ -103,7 +124,7 @@
)";
std::string res_body;
SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
- EXPECT_EQ(SPV_SUCCESS, Disassemble(linked_binary, &res_body))
+ ASSERT_EQ(SPV_SUCCESS, Disassemble(linked_binary, &res_body))
<< GetErrorMessage();
EXPECT_EQ(expected_res, res_body);
}
@@ -111,11 +132,18 @@
TEST_F(MatchingImportsToExports, UnresolvedImports) {
const std::string body1 = R"(
OpCapability Linkage
+OpCapability Addresses
+OpCapability Kernel
+OpMemoryModel Physical64 OpenCL
OpDecorate %1 LinkageAttributes "foo" Import
%2 = OpTypeFloat 32
%1 = OpVariable %2 Uniform
)";
- const std::string body2 = R"()";
+ const std::string body2 = R"(
+OpCapability Addresses
+OpCapability Kernel
+OpMemoryModel Physical64 OpenCL
+)";
spvtest::Binary linked_binary;
EXPECT_EQ(SPV_ERROR_INVALID_BINARY,
@@ -127,6 +155,9 @@
TEST_F(MatchingImportsToExports, TypeMismatch) {
const std::string body1 = R"(
OpCapability Linkage
+OpCapability Addresses
+OpCapability Kernel
+OpMemoryModel Physical64 OpenCL
OpDecorate %1 LinkageAttributes "foo" Import
%2 = OpTypeFloat 32
%1 = OpVariable %2 Uniform
@@ -134,6 +165,9 @@
)";
const std::string body2 = R"(
OpCapability Linkage
+OpCapability Addresses
+OpCapability Kernel
+OpMemoryModel Physical64 OpenCL
OpDecorate %1 LinkageAttributes "foo" Export
%2 = OpTypeInt 32 0
%3 = OpConstant %2 42
@@ -153,6 +187,9 @@
TEST_F(MatchingImportsToExports, MultipleDefinitions) {
const std::string body1 = R"(
OpCapability Linkage
+OpCapability Addresses
+OpCapability Kernel
+OpMemoryModel Physical64 OpenCL
OpDecorate %1 LinkageAttributes "foo" Import
%2 = OpTypeFloat 32
%1 = OpVariable %2 Uniform
@@ -160,6 +197,9 @@
)";
const std::string body2 = R"(
OpCapability Linkage
+OpCapability Addresses
+OpCapability Kernel
+OpMemoryModel Physical64 OpenCL
OpDecorate %1 LinkageAttributes "foo" Export
%2 = OpTypeFloat 32
%3 = OpConstant %2 42
@@ -167,6 +207,9 @@
)";
const std::string body3 = R"(
OpCapability Linkage
+OpCapability Addresses
+OpCapability Kernel
+OpMemoryModel Physical64 OpenCL
OpDecorate %1 LinkageAttributes "foo" Export
%2 = OpTypeFloat 32
%3 = OpConstant %2 -1
@@ -185,6 +228,9 @@
TEST_F(MatchingImportsToExports, SameNameDifferentTypes) {
const std::string body1 = R"(
OpCapability Linkage
+OpCapability Addresses
+OpCapability Kernel
+OpMemoryModel Physical64 OpenCL
OpDecorate %1 LinkageAttributes "foo" Import
%2 = OpTypeFloat 32
%1 = OpVariable %2 Uniform
@@ -192,6 +238,9 @@
)";
const std::string body2 = R"(
OpCapability Linkage
+OpCapability Addresses
+OpCapability Kernel
+OpMemoryModel Physical64 OpenCL
OpDecorate %1 LinkageAttributes "foo" Export
%2 = OpTypeInt 32 0
%3 = OpConstant %2 42
@@ -199,6 +248,9 @@
)";
const std::string body3 = R"(
OpCapability Linkage
+OpCapability Addresses
+OpCapability Kernel
+OpMemoryModel Physical64 OpenCL
OpDecorate %1 LinkageAttributes "foo" Export
%2 = OpTypeFloat 32
%3 = OpConstant %2 12
@@ -217,6 +269,9 @@
TEST_F(MatchingImportsToExports, DecorationMismatch) {
const std::string body1 = R"(
OpCapability Linkage
+OpCapability Addresses
+OpCapability Kernel
+OpMemoryModel Physical64 OpenCL
OpDecorate %1 LinkageAttributes "foo" Import
OpDecorate %2 Constant
%2 = OpTypeFloat 32
@@ -225,6 +280,9 @@
)";
const std::string body2 = R"(
OpCapability Linkage
+OpCapability Addresses
+OpCapability Kernel
+OpMemoryModel Physical64 OpenCL
OpDecorate %1 LinkageAttributes "foo" Export
%2 = OpTypeFloat 32
%3 = OpConstant %2 42
@@ -244,8 +302,10 @@
TEST_F(MatchingImportsToExports,
FuncParamAttrDifferButStillMatchExportToImport) {
const std::string body1 = R"(
-OpCapability Kernel
OpCapability Linkage
+OpCapability Addresses
+OpCapability Kernel
+OpMemoryModel Physical64 OpenCL
OpDecorate %1 LinkageAttributes "foo" Import
OpDecorate %2 FuncParamAttr Zext
%3 = OpTypeVoid
@@ -256,8 +316,10 @@
OpFunctionEnd
)";
const std::string body2 = R"(
-OpCapability Kernel
OpCapability Linkage
+OpCapability Addresses
+OpCapability Kernel
+OpMemoryModel Physical64 OpenCL
OpDecorate %1 LinkageAttributes "foo" Export
OpDecorate %2 FuncParamAttr Sext
%3 = OpTypeVoid
@@ -271,10 +333,12 @@
)";
spvtest::Binary linked_binary;
- EXPECT_EQ(SPV_SUCCESS, AssembleAndLink({body1, body2}, &linked_binary))
+ ASSERT_EQ(SPV_SUCCESS, AssembleAndLink({body1, body2}, &linked_binary))
<< GetErrorMessage();
- const std::string expected_res = R"(OpCapability Kernel
+ const std::string expected_res = R"(OpCapability Addresses
+OpCapability Kernel
+OpMemoryModel Physical64 OpenCL
OpModuleProcessed "Linked by SPIR-V Tools Linker"
OpDecorate %1 FuncParamAttr Sext
%2 = OpTypeVoid
@@ -288,7 +352,7 @@
)";
std::string res_body;
SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
- EXPECT_EQ(SPV_SUCCESS, Disassemble(linked_binary, &res_body))
+ ASSERT_EQ(SPV_SUCCESS, Disassemble(linked_binary, &res_body))
<< GetErrorMessage();
EXPECT_EQ(expected_res, res_body);
}
@@ -296,6 +360,9 @@
TEST_F(MatchingImportsToExports, FunctionCtrl) {
const std::string body1 = R"(
OpCapability Linkage
+OpCapability Addresses
+OpCapability Kernel
+OpMemoryModel Physical64 OpenCL
OpDecorate %1 LinkageAttributes "foo" Import
%2 = OpTypeVoid
%3 = OpTypeFunction %2
@@ -306,6 +373,9 @@
)";
const std::string body2 = R"(
OpCapability Linkage
+OpCapability Addresses
+OpCapability Kernel
+OpMemoryModel Physical64 OpenCL
OpDecorate %1 LinkageAttributes "foo" Export
%2 = OpTypeVoid
%3 = OpTypeFunction %2
@@ -316,11 +386,14 @@
)";
spvtest::Binary linked_binary;
- EXPECT_EQ(SPV_SUCCESS, AssembleAndLink({body1, body2}, &linked_binary))
+ ASSERT_EQ(SPV_SUCCESS, AssembleAndLink({body1, body2}, &linked_binary))
<< GetErrorMessage();
const std::string expected_res =
- R"(OpModuleProcessed "Linked by SPIR-V Tools Linker"
+ R"(OpCapability Addresses
+OpCapability Kernel
+OpMemoryModel Physical64 OpenCL
+OpModuleProcessed "Linked by SPIR-V Tools Linker"
%1 = OpTypeVoid
%2 = OpTypeFunction %1
%3 = OpTypeFloat 32
@@ -332,15 +405,17 @@
)";
std::string res_body;
SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
- EXPECT_EQ(SPV_SUCCESS, Disassemble(linked_binary, &res_body))
+ ASSERT_EQ(SPV_SUCCESS, Disassemble(linked_binary, &res_body))
<< GetErrorMessage();
EXPECT_EQ(expected_res, res_body);
}
TEST_F(MatchingImportsToExports, UseExportedFuncParamAttr) {
const std::string body1 = R"(
-OpCapability Kernel
OpCapability Linkage
+OpCapability Addresses
+OpCapability Kernel
+OpMemoryModel Physical64 OpenCL
OpDecorate %1 LinkageAttributes "foo" Import
OpDecorate %2 FuncParamAttr Zext
%2 = OpDecorationGroup
@@ -356,8 +431,10 @@
OpFunctionEnd
)";
const std::string body2 = R"(
-OpCapability Kernel
OpCapability Linkage
+OpCapability Addresses
+OpCapability Kernel
+OpMemoryModel Physical64 OpenCL
OpDecorate %1 LinkageAttributes "foo" Export
OpDecorate %2 FuncParamAttr Sext
%3 = OpTypeVoid
@@ -371,10 +448,12 @@
)";
spvtest::Binary linked_binary;
- EXPECT_EQ(SPV_SUCCESS, AssembleAndLink({body1, body2}, &linked_binary))
+ ASSERT_EQ(SPV_SUCCESS, AssembleAndLink({body1, body2}, &linked_binary))
<< GetErrorMessage();
- const std::string expected_res = R"(OpCapability Kernel
+ const std::string expected_res = R"(OpCapability Addresses
+OpCapability Kernel
+OpMemoryModel Physical64 OpenCL
OpModuleProcessed "Linked by SPIR-V Tools Linker"
OpDecorate %1 FuncParamAttr Zext
%1 = OpDecorationGroup
@@ -394,15 +473,17 @@
)";
std::string res_body;
SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
- EXPECT_EQ(SPV_SUCCESS, Disassemble(linked_binary, &res_body))
+ ASSERT_EQ(SPV_SUCCESS, Disassemble(linked_binary, &res_body))
<< GetErrorMessage();
EXPECT_EQ(expected_res, res_body);
}
TEST_F(MatchingImportsToExports, NamesAndDecorations) {
const std::string body1 = R"(
-OpCapability Kernel
OpCapability Linkage
+OpCapability Addresses
+OpCapability Kernel
+OpMemoryModel Physical64 OpenCL
OpName %1 "foo"
OpName %3 "param"
OpDecorate %1 LinkageAttributes "foo" Import
@@ -422,8 +503,10 @@
OpFunctionEnd
)";
const std::string body2 = R"(
-OpCapability Kernel
OpCapability Linkage
+OpCapability Addresses
+OpCapability Kernel
+OpMemoryModel Physical64 OpenCL
OpName %1 "foo"
OpName %2 "param"
OpDecorate %1 LinkageAttributes "foo" Export
@@ -440,10 +523,12 @@
)";
spvtest::Binary linked_binary;
- EXPECT_EQ(SPV_SUCCESS, AssembleAndLink({body1, body2}, &linked_binary))
+ ASSERT_EQ(SPV_SUCCESS, AssembleAndLink({body1, body2}, &linked_binary))
<< GetErrorMessage();
- const std::string expected_res = R"(OpCapability Kernel
+ const std::string expected_res = R"(OpCapability Addresses
+OpCapability Kernel
+OpMemoryModel Physical64 OpenCL
OpName %1 "foo"
OpName %2 "param"
OpModuleProcessed "Linked by SPIR-V Tools Linker"
@@ -467,7 +552,7 @@
)";
std::string res_body;
SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
- EXPECT_EQ(SPV_SUCCESS, Disassemble(linked_binary, &res_body))
+ ASSERT_EQ(SPV_SUCCESS, Disassemble(linked_binary, &res_body))
<< GetErrorMessage();
EXPECT_EQ(expected_res, res_body);
}
diff --git a/third_party/SPIRV-Tools/test/link/memory_model_test.cpp b/third_party/SPIRV-Tools/test/link/memory_model_test.cpp
index 2add504..280a776 100644
--- a/third_party/SPIRV-Tools/test/link/memory_model_test.cpp
+++ b/third_party/SPIRV-Tools/test/link/memory_model_test.cpp
@@ -50,9 +50,9 @@
spvtest::Binary linked_binary;
EXPECT_EQ(SPV_ERROR_INTERNAL,
AssembleAndLink({body1, body2}, &linked_binary));
- EXPECT_THAT(
- GetErrorMessage(),
- HasSubstr("Conflicting addressing models: Logical vs Physical32."));
+ EXPECT_THAT(GetErrorMessage(),
+ HasSubstr("Conflicting addressing models: Logical (input modules "
+ "1 through 1) vs Physical32 (input module 2)."));
}
TEST_F(MemoryModel, MemoryMismatch) {
@@ -67,7 +67,38 @@
EXPECT_EQ(SPV_ERROR_INTERNAL,
AssembleAndLink({body1, body2}, &linked_binary));
EXPECT_THAT(GetErrorMessage(),
- HasSubstr("Conflicting memory models: Simple vs GLSL450."));
+ HasSubstr("Conflicting memory models: Simple (input modules 1 "
+ "through 1) vs GLSL450 (input module 2)."));
+}
+
+TEST_F(MemoryModel, FirstLackMemoryModel) {
+ const std::string body1 = R"(
+)";
+ const std::string body2 = R"(
+OpMemoryModel Logical GLSL450
+)";
+
+ spvtest::Binary linked_binary;
+ EXPECT_EQ(SPV_ERROR_INVALID_BINARY,
+ AssembleAndLink({body1, body2}, &linked_binary));
+ EXPECT_THAT(
+ GetErrorMessage(),
+ HasSubstr("Input module 1 is lacking an OpMemoryModel instruction."));
+}
+
+TEST_F(MemoryModel, SecondLackMemoryModel) {
+ const std::string body1 = R"(
+OpMemoryModel Logical GLSL450
+)";
+ const std::string body2 = R"(
+)";
+
+ spvtest::Binary linked_binary;
+ EXPECT_EQ(SPV_ERROR_INVALID_BINARY,
+ AssembleAndLink({body1, body2}, &linked_binary));
+ EXPECT_THAT(
+ GetErrorMessage(),
+ HasSubstr("Input module 2 is lacking an OpMemoryModel instruction."));
}
} // namespace
diff --git a/third_party/SPIRV-Tools/test/link/partial_linkage_test.cpp b/third_party/SPIRV-Tools/test/link/partial_linkage_test.cpp
index c43b06e..bf4b508 100644
--- a/third_party/SPIRV-Tools/test/link/partial_linkage_test.cpp
+++ b/third_party/SPIRV-Tools/test/link/partial_linkage_test.cpp
@@ -26,6 +26,9 @@
TEST_F(PartialLinkage, Allowed) {
const std::string body1 = R"(
OpCapability Linkage
+OpCapability Addresses
+OpCapability Kernel
+OpMemoryModel Physical64 OpenCL
OpDecorate %1 LinkageAttributes "foo" Import
OpDecorate %2 LinkageAttributes "bar" Import
%3 = OpTypeFloat 32
@@ -34,6 +37,9 @@
)";
const std::string body2 = R"(
OpCapability Linkage
+OpCapability Addresses
+OpCapability Kernel
+OpMemoryModel Physical64 OpenCL
OpDecorate %1 LinkageAttributes "bar" Export
%2 = OpTypeFloat 32
%3 = OpConstant %2 3.1415
@@ -44,9 +50,13 @@
LinkerOptions linker_options;
linker_options.SetAllowPartialLinkage(true);
ASSERT_EQ(SPV_SUCCESS,
- AssembleAndLink({body1, body2}, &linked_binary, linker_options));
+ AssembleAndLink({body1, body2}, &linked_binary, linker_options))
+ << GetErrorMessage();
const std::string expected_res = R"(OpCapability Linkage
+OpCapability Addresses
+OpCapability Kernel
+OpMemoryModel Physical64 OpenCL
OpModuleProcessed "Linked by SPIR-V Tools Linker"
OpDecorate %1 LinkageAttributes "foo" Import
%2 = OpTypeFloat 32
@@ -64,6 +74,9 @@
TEST_F(PartialLinkage, Disallowed) {
const std::string body1 = R"(
OpCapability Linkage
+OpCapability Addresses
+OpCapability Kernel
+OpMemoryModel Physical64 OpenCL
OpDecorate %1 LinkageAttributes "foo" Import
OpDecorate %2 LinkageAttributes "bar" Import
%3 = OpTypeFloat 32
@@ -72,6 +85,9 @@
)";
const std::string body2 = R"(
OpCapability Linkage
+OpCapability Addresses
+OpCapability Kernel
+OpMemoryModel Physical64 OpenCL
OpDecorate %1 LinkageAttributes "bar" Export
%2 = OpTypeFloat 32
%3 = OpConstant %2 3.1415
diff --git a/third_party/SPIRV-Tools/test/link/type_match_test.cpp b/third_party/SPIRV-Tools/test/link/type_match_test.cpp
index dae70c1..efc5cf7 100644
--- a/third_party/SPIRV-Tools/test/link/type_match_test.cpp
+++ b/third_party/SPIRV-Tools/test/link/type_match_test.cpp
@@ -66,6 +66,7 @@
"OpCapability Kernel\n" \
"OpCapability Shader\n" \
"OpCapability Addresses\n" \
+ "OpMemoryModel Physical64 OpenCL\n" \
"OpDecorate %var LinkageAttributes \"foo\" " \
"{Import,Export}\n" \
"; CHECK: [[baseint:%\\w+]] = OpTypeInt 32 1\n" \
diff --git a/third_party/SPIRV-Tools/test/link/unique_ids_test.cpp b/third_party/SPIRV-Tools/test/link/unique_ids_test.cpp
index 55c70ea..16a9b52 100644
--- a/third_party/SPIRV-Tools/test/link/unique_ids_test.cpp
+++ b/third_party/SPIRV-Tools/test/link/unique_ids_test.cpp
@@ -135,7 +135,8 @@
LinkerOptions options;
options.SetVerifyIds(true);
spv_result_t res = AssembleAndLink(bodies, &linked_binary, options);
- EXPECT_EQ(SPV_SUCCESS, res);
+ ASSERT_EQ(SPV_SUCCESS, res) << GetErrorMessage();
+ EXPECT_THAT(GetErrorMessage(), std::string());
}
} // namespace
diff --git a/third_party/SPIRV-Tools/test/operand_pattern_test.cpp b/third_party/SPIRV-Tools/test/operand_pattern_test.cpp
index 1caf008..a98a9d7 100644
--- a/third_party/SPIRV-Tools/test/operand_pattern_test.cpp
+++ b/third_party/SPIRV-Tools/test/operand_pattern_test.cpp
@@ -91,9 +91,14 @@
{SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS, 0, {PREFIX0}, {PREFIX0}},
// Unknown bits means no change. Use all bits that aren't in the
// grammar.
- // The last mask enum is 0x20
+ // The used mask bits are:
+ // 1 through...
+ // 0x20 SpvMemoryAccessNonPrivatePointerMask
+ // also
+ // 0x10000 SpvMemoryAccessAliasScopeINTELMaskShift
+ // 0x20000 SpvMemoryAccessNoAliasINTELMaskMask
{SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS,
- 0xffffffc0,
+ 0xffffffc0 ^ (0x10000) ^ (0x20000),
{PREFIX1},
{PREFIX1}},
// Volatile has no operands.
@@ -111,6 +116,7 @@
SpvMemoryAccessVolatileMask | SpvMemoryAccessAlignedMask,
{PREFIX1},
{PREFIX1, SPV_OPERAND_TYPE_LITERAL_INTEGER}},
+ // Newer masks are not tested
}));
#undef PREFIX0
#undef PREFIX1
diff --git a/third_party/SPIRV-Tools/test/opt/CMakeLists.txt b/third_party/SPIRV-Tools/test/opt/CMakeLists.txt
index bc44e8d..759d423 100644
--- a/third_party/SPIRV-Tools/test/opt/CMakeLists.txt
+++ b/third_party/SPIRV-Tools/test/opt/CMakeLists.txt
@@ -91,9 +91,10 @@
scalar_replacement_test.cpp
set_spec_const_default_value_test.cpp
simplification_test.cpp
+ spread_volatile_semantics_test.cpp
strength_reduction_test.cpp
strip_debug_info_test.cpp
- strip_reflect_info_test.cpp
+ strip_nonsemantic_info_test.cpp
struct_cfg_analysis_test.cpp
type_manager_test.cpp
types_test.cpp
diff --git a/third_party/SPIRV-Tools/test/opt/aggressive_dead_code_elim_test.cpp b/third_party/SPIRV-Tools/test/opt/aggressive_dead_code_elim_test.cpp
index bc7dd71..25f8541 100644
--- a/third_party/SPIRV-Tools/test/opt/aggressive_dead_code_elim_test.cpp
+++ b/third_party/SPIRV-Tools/test/opt/aggressive_dead_code_elim_test.cpp
@@ -4323,7 +4323,7 @@
},
// Uint vector type spec constants. One vector has all component dead,
- // another vector has one dead unsigend integer and one used unsigned
+ // another vector has one dead unsigned integer and one used unsigned
// integer.
{
/* .used_consts = */
diff --git a/third_party/SPIRV-Tools/test/opt/assembly_builder.h b/third_party/SPIRV-Tools/test/opt/assembly_builder.h
index 1673c09..b94e90f 100644
--- a/third_party/SPIRV-Tools/test/opt/assembly_builder.h
+++ b/third_party/SPIRV-Tools/test/opt/assembly_builder.h
@@ -70,7 +70,7 @@
static const uint32_t SPEC_ID_BASE = 200;
public:
- // Initalize a minimal SPIR-V assembly code as the template. The minimal
+ // Initialize a minimal SPIR-V assembly code as the template. The minimal
// module contains an empty main function and some predefined names for the
// main function.
AssemblyBuilder()
@@ -102,7 +102,7 @@
});
}
- // Appends OpName instructions to this builder. Instrcution strings that do
+ // Appends OpName instructions to this builder. Instruction strings that do
// not start with 'OpName ' will be skipped. Returns the references of this
// assembly builder.
AssemblyBuilder& AppendNames(const std::vector<std::string>& vec_asm_code) {
diff --git a/third_party/SPIRV-Tools/test/opt/block_merge_test.cpp b/third_party/SPIRV-Tools/test/opt/block_merge_test.cpp
index 6903c4e..9698fed 100644
--- a/third_party/SPIRV-Tools/test/opt/block_merge_test.cpp
+++ b/third_party/SPIRV-Tools/test/opt/block_merge_test.cpp
@@ -884,7 +884,7 @@
; CHECK-NEXT: [[header]] = OpLabel
; CHECK-NEXT: OpSelectionMerge [[merge:%\w+]]
; CHECK: [[merge]] = OpLabel
-; CHEKC: OpReturn
+; CHECK: OpReturn
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %func "func"
diff --git a/third_party/SPIRV-Tools/test/opt/code_sink_test.cpp b/third_party/SPIRV-Tools/test/opt/code_sink_test.cpp
index f1bd127..bf5029b 100644
--- a/third_party/SPIRV-Tools/test/opt/code_sink_test.cpp
+++ b/third_party/SPIRV-Tools/test/opt/code_sink_test.cpp
@@ -378,7 +378,7 @@
%uint = OpTypeInt 32 0
%uint_0 = OpConstant %uint 0
%uint_4 = OpConstant %uint 4
-%mem_semantics = OpConstant %uint 0x42 ; Uniform memeory arquire
+%mem_semantics = OpConstant %uint 0x42 ; Uniform memory arquire
%_arr_uint_uint_4 = OpTypeArray %uint %uint_4
%_ptr_Uniform_uint = OpTypePointer Uniform %uint
%_ptr_Uniform__arr_uint_uint_4 = OpTypePointer Uniform %_arr_uint_uint_4
@@ -419,7 +419,7 @@
%uint = OpTypeInt 32 0
%uint_0 = OpConstant %uint 0
%uint_4 = OpConstant %uint 4
-%mem_semantics = OpConstant %uint 0x42 ; Uniform memeory arquire
+%mem_semantics = OpConstant %uint 0x42 ; Uniform memory arquire
%_arr_uint_uint_4 = OpTypeStruct %uint
%_ptr_Uniform_uint = OpTypePointer Uniform %uint
%_ptr_Uniform__arr_uint_uint_4 = OpTypePointer Uniform %_arr_uint_uint_4
@@ -460,7 +460,7 @@
%uint = OpTypeInt 32 0
%uint_0 = OpConstant %uint 0
%uint_4 = OpConstant %uint 4
-%mem_semantics = OpConstant %uint 0x42 ; Uniform memeory arquire
+%mem_semantics = OpConstant %uint 0x42 ; Uniform memory arquire
%_arr_uint_uint_4 = OpTypeStruct %uint
%_ptr_Uniform_uint = OpTypePointer Uniform %uint
%_ptr_Uniform__arr_uint_uint_4 = OpTypePointer Uniform %_arr_uint_uint_4
diff --git a/third_party/SPIRV-Tools/test/opt/dead_branch_elim_test.cpp b/third_party/SPIRV-Tools/test/opt/dead_branch_elim_test.cpp
index 9c1ef2a..b04c8f5 100644
--- a/third_party/SPIRV-Tools/test/opt/dead_branch_elim_test.cpp
+++ b/third_party/SPIRV-Tools/test/opt/dead_branch_elim_test.cpp
@@ -1613,7 +1613,7 @@
%11 = OpLogicalOr %bool %true %false
OpBranch %7
%7 = OpLabel
-; This phi is in a block preceeding the merge %14!
+; This phi is in a block preceding the merge %14!
%8 = OpPhi %bool %10 %5 %11 %6
OpBranch %14
%14 = OpLabel
diff --git a/third_party/SPIRV-Tools/test/opt/decoration_manager_test.cpp b/third_party/SPIRV-Tools/test/opt/decoration_manager_test.cpp
index fcfbff0..c9fabe7 100644
--- a/third_party/SPIRV-Tools/test/opt/decoration_manager_test.cpp
+++ b/third_party/SPIRV-Tools/test/opt/decoration_manager_test.cpp
@@ -118,7 +118,7 @@
TEST_F(DecorationManagerTest,
ComparingDecorationsWithDiffOpcodesDecorateDecorateId) {
IRContext ir_context(SPV_ENV_UNIVERSAL_1_2, GetConsumer());
- // This parameter can be interprated both as { SpvDecorationConstant }
+ // This parameter can be interpreted both as { SpvDecorationConstant }
// and also as a list of IDs: { 22 }
const std::vector<uint32_t> param{SpvDecorationConstant};
// OpDecorate %1 Constant
@@ -137,7 +137,7 @@
TEST_F(DecorationManagerTest,
ComparingDecorationsWithDiffOpcodesDecorateDecorateString) {
IRContext ir_context(SPV_ENV_UNIVERSAL_1_2, GetConsumer());
- // This parameter can be interprated both as { SpvDecorationConstant }
+ // This parameter can be interpreted both as { SpvDecorationConstant }
// and also as a null-terminated string with a single character with value 22.
const std::vector<uint32_t> param{SpvDecorationConstant};
// OpDecorate %1 Constant
diff --git a/third_party/SPIRV-Tools/test/opt/def_use_test.cpp b/third_party/SPIRV-Tools/test/opt/def_use_test.cpp
index cfdad74..48a485e 100644
--- a/third_party/SPIRV-Tools/test/opt/def_use_test.cpp
+++ b/third_party/SPIRV-Tools/test/opt/def_use_test.cpp
@@ -950,6 +950,369 @@
);
// clang-format on
+// We re-use the same replace usecases, we need to similarly exercise the
+// DefUseManager by replacing instructions and uses.
+using CompactIdempotence = ::testing::TestWithParam<ReplaceUseCase>;
+
+TEST_P(CompactIdempotence, Case) {
+ const auto& tc = GetParam();
+
+ // Build module.
+ const std::vector<const char*> text = {tc.before};
+ std::unique_ptr<IRContext> context =
+ BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, JoinAllInsts(text),
+ SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
+ ASSERT_NE(nullptr, context);
+
+ // Force a re-build of def-use manager.
+ context->InvalidateAnalyses(IRContext::Analysis::kAnalysisDefUse);
+ (void)context->get_def_use_mgr();
+
+ // Do the substitution.
+ for (const auto& candidate : tc.candidates) {
+ context->ReplaceAllUsesWith(candidate.first, candidate.second);
+ }
+
+ // Ensure new/uncompacted managers produce the same result
+ EXPECT_TRUE(CompareAndPrintDifferences(*context->get_def_use_mgr(),
+ DefUseManager(context->module())));
+
+ EXPECT_EQ(tc.after, DisassembleModule(context->module()));
+ CheckDef(tc.du, context->get_def_use_mgr()->id_to_defs());
+ CheckUse(tc.du, context->get_def_use_mgr(), context->module()->IdBound());
+
+ // Compare again after compacting the defuse manager's storage
+ context->get_def_use_mgr()->CompactStorage();
+
+ CheckDef(tc.du, context->get_def_use_mgr()->id_to_defs());
+ CheckUse(tc.du, context->get_def_use_mgr(), context->module()->IdBound());
+
+ EXPECT_TRUE(CompareAndPrintDifferences(*context->get_def_use_mgr(),
+ DefUseManager(context->module())));
+}
+
+// clang-format off
+INSTANTIATE_TEST_SUITE_P(
+ TestCase, CompactIdempotence,
+ ::testing::ValuesIn(std::vector<ReplaceUseCase>{
+ { // no use, no replace request
+ "", {}, "", {},
+ },
+ { // replace one use
+ "%1 = OpTypeBool "
+ "%2 = OpTypeVector %1 3 "
+ "%3 = OpTypeInt 32 0 ",
+ {{1, 3}},
+ "%1 = OpTypeBool\n"
+ "%2 = OpTypeVector %3 3\n"
+ "%3 = OpTypeInt 32 0",
+ {
+ { // defs
+ {1, "%1 = OpTypeBool"},
+ {2, "%2 = OpTypeVector %3 3"},
+ {3, "%3 = OpTypeInt 32 0"},
+ },
+ { // uses
+ {3, {"%2 = OpTypeVector %3 3"}},
+ },
+ },
+ },
+ { // replace and then replace back
+ "%1 = OpTypeBool "
+ "%2 = OpTypeVector %1 3 "
+ "%3 = OpTypeInt 32 0",
+ {{1, 3}, {3, 1}},
+ "%1 = OpTypeBool\n"
+ "%2 = OpTypeVector %1 3\n"
+ "%3 = OpTypeInt 32 0",
+ {
+ { // defs
+ {1, "%1 = OpTypeBool"},
+ {2, "%2 = OpTypeVector %1 3"},
+ {3, "%3 = OpTypeInt 32 0"},
+ },
+ { // uses
+ {1, {"%2 = OpTypeVector %1 3"}},
+ },
+ },
+ },
+ { // replace with the same id
+ "%1 = OpTypeBool "
+ "%2 = OpTypeVector %1 3",
+ {{1, 1}, {2, 2}, {3, 3}},
+ "%1 = OpTypeBool\n"
+ "%2 = OpTypeVector %1 3",
+ {
+ { // defs
+ {1, "%1 = OpTypeBool"},
+ {2, "%2 = OpTypeVector %1 3"},
+ },
+ { // uses
+ {1, {"%2 = OpTypeVector %1 3"}},
+ },
+ },
+ },
+ { // replace in sequence
+ "%1 = OpTypeBool "
+ "%2 = OpTypeVector %1 3 "
+ "%3 = OpTypeInt 32 0 "
+ "%4 = OpTypeInt 32 1 ",
+ {{1, 3}, {3, 4}},
+ "%1 = OpTypeBool\n"
+ "%2 = OpTypeVector %4 3\n"
+ "%3 = OpTypeInt 32 0\n"
+ "%4 = OpTypeInt 32 1",
+ {
+ { // defs
+ {1, "%1 = OpTypeBool"},
+ {2, "%2 = OpTypeVector %4 3"},
+ {3, "%3 = OpTypeInt 32 0"},
+ {4, "%4 = OpTypeInt 32 1"},
+ },
+ { // uses
+ {4, {"%2 = OpTypeVector %4 3"}},
+ },
+ },
+ },
+ { // replace multiple uses
+ "%1 = OpTypeBool "
+ "%2 = OpTypeVector %1 2 "
+ "%3 = OpTypeVector %1 3 "
+ "%4 = OpTypeVector %1 4 "
+ "%5 = OpTypeMatrix %2 2 "
+ "%6 = OpTypeMatrix %3 3 "
+ "%7 = OpTypeMatrix %4 4 "
+ "%8 = OpTypeInt 32 0 "
+ "%9 = OpTypeInt 32 1 "
+ "%10 = OpTypeInt 64 0",
+ {{1, 8}, {2, 9}, {4, 10}},
+ "%1 = OpTypeBool\n"
+ "%2 = OpTypeVector %8 2\n"
+ "%3 = OpTypeVector %8 3\n"
+ "%4 = OpTypeVector %8 4\n"
+ "%5 = OpTypeMatrix %9 2\n"
+ "%6 = OpTypeMatrix %3 3\n"
+ "%7 = OpTypeMatrix %10 4\n"
+ "%8 = OpTypeInt 32 0\n"
+ "%9 = OpTypeInt 32 1\n"
+ "%10 = OpTypeInt 64 0",
+ {
+ { // defs
+ {1, "%1 = OpTypeBool"},
+ {2, "%2 = OpTypeVector %8 2"},
+ {3, "%3 = OpTypeVector %8 3"},
+ {4, "%4 = OpTypeVector %8 4"},
+ {5, "%5 = OpTypeMatrix %9 2"},
+ {6, "%6 = OpTypeMatrix %3 3"},
+ {7, "%7 = OpTypeMatrix %10 4"},
+ {8, "%8 = OpTypeInt 32 0"},
+ {9, "%9 = OpTypeInt 32 1"},
+ {10, "%10 = OpTypeInt 64 0"},
+ },
+ { // uses
+ {8,
+ {
+ "%2 = OpTypeVector %8 2",
+ "%3 = OpTypeVector %8 3",
+ "%4 = OpTypeVector %8 4",
+ }
+ },
+ {9, {"%5 = OpTypeMatrix %9 2"}},
+ {3, {"%6 = OpTypeMatrix %3 3"}},
+ {10, {"%7 = OpTypeMatrix %10 4"}},
+ },
+ },
+ },
+ { // OpPhi.
+ kOpPhiTestFunction,
+ // replace one id used by OpPhi, replace one id generated by OpPhi
+ {{9, 13}, {11, 9}},
+ "%1 = OpTypeVoid\n"
+ "%6 = OpTypeInt 32 0\n"
+ "%10 = OpTypeFloat 32\n"
+ "%16 = OpTypeBool\n"
+ "%3 = OpTypeFunction %1\n"
+ "%8 = OpConstant %6 0\n"
+ "%18 = OpConstant %6 1\n"
+ "%12 = OpConstant %10 1\n"
+ "%2 = OpFunction %1 None %3\n"
+ "%4 = OpLabel\n"
+ "OpBranch %5\n"
+
+ "%5 = OpLabel\n"
+ "%7 = OpPhi %6 %8 %4 %13 %5\n" // %9 -> %13
+ "%11 = OpPhi %10 %12 %4 %13 %5\n"
+ "%9 = OpIAdd %6 %7 %8\n"
+ "%13 = OpFAdd %10 %9 %12\n" // %11 -> %9
+ "%17 = OpSLessThan %16 %7 %18\n"
+ "OpLoopMerge %19 %5 None\n"
+ "OpBranchConditional %17 %5 %19\n"
+
+ "%19 = OpLabel\n"
+ "OpReturn\n"
+ "OpFunctionEnd",
+ {
+ { // defs.
+ {1, "%1 = OpTypeVoid"},
+ {2, "%2 = OpFunction %1 None %3"},
+ {3, "%3 = OpTypeFunction %1"},
+ {4, "%4 = OpLabel"},
+ {5, "%5 = OpLabel"},
+ {6, "%6 = OpTypeInt 32 0"},
+ {7, "%7 = OpPhi %6 %8 %4 %13 %5"},
+ {8, "%8 = OpConstant %6 0"},
+ {9, "%9 = OpIAdd %6 %7 %8"},
+ {10, "%10 = OpTypeFloat 32"},
+ {11, "%11 = OpPhi %10 %12 %4 %13 %5"},
+ {12, "%12 = OpConstant %10 1.0"},
+ {13, "%13 = OpFAdd %10 %9 %12"},
+ {16, "%16 = OpTypeBool"},
+ {17, "%17 = OpSLessThan %16 %7 %18"},
+ {18, "%18 = OpConstant %6 1"},
+ {19, "%19 = OpLabel"},
+ },
+ { // uses
+ {1,
+ {
+ "%2 = OpFunction %1 None %3",
+ "%3 = OpTypeFunction %1",
+ }
+ },
+ {3, {"%2 = OpFunction %1 None %3"}},
+ {4,
+ {
+ "%7 = OpPhi %6 %8 %4 %13 %5",
+ "%11 = OpPhi %10 %12 %4 %13 %5",
+ }
+ },
+ {5,
+ {
+ "OpBranch %5",
+ "%7 = OpPhi %6 %8 %4 %13 %5",
+ "%11 = OpPhi %10 %12 %4 %13 %5",
+ "OpLoopMerge %19 %5 None",
+ "OpBranchConditional %17 %5 %19",
+ }
+ },
+ {6,
+ {
+ // Can't properly check constants
+ // "%8 = OpConstant %6 0",
+ // "%18 = OpConstant %6 1",
+ "%7 = OpPhi %6 %8 %4 %13 %5",
+ "%9 = OpIAdd %6 %7 %8"
+ }
+ },
+ {7,
+ {
+ "%9 = OpIAdd %6 %7 %8",
+ "%17 = OpSLessThan %16 %7 %18",
+ }
+ },
+ {8,
+ {
+ "%7 = OpPhi %6 %8 %4 %13 %5",
+ "%9 = OpIAdd %6 %7 %8",
+ }
+ },
+ {9, {"%13 = OpFAdd %10 %9 %12"}}, // uses of %9 changed from %7 to %13
+ {10,
+ {
+ "%11 = OpPhi %10 %12 %4 %13 %5",
+ // "%12 = OpConstant %10 1",
+ "%13 = OpFAdd %10 %9 %12"
+ }
+ },
+ // no more uses of %11
+ {12,
+ {
+ "%11 = OpPhi %10 %12 %4 %13 %5",
+ "%13 = OpFAdd %10 %9 %12"
+ }
+ },
+ {13, {
+ "%7 = OpPhi %6 %8 %4 %13 %5",
+ "%11 = OpPhi %10 %12 %4 %13 %5",
+ }
+ },
+ {16, {"%17 = OpSLessThan %16 %7 %18"}},
+ {17, {"OpBranchConditional %17 %5 %19"}},
+ {18, {"%17 = OpSLessThan %16 %7 %18"}},
+ {19,
+ {
+ "OpLoopMerge %19 %5 None",
+ "OpBranchConditional %17 %5 %19",
+ }
+ },
+ },
+ },
+ },
+ { // OpPhi defining and referencing the same id.
+ "%1 = OpTypeBool "
+ "%3 = OpTypeFunction %1 "
+ "%2 = OpConstantTrue %1 "
+
+ "%4 = OpFunction %3 None %1 "
+ "%6 = OpLabel "
+ " OpBranch %7 "
+ "%7 = OpLabel "
+ "%8 = OpPhi %1 %8 %7 %2 %6 " // both defines and uses %8
+ " OpBranch %7 "
+ " OpFunctionEnd",
+ {{8, 2}},
+ "%1 = OpTypeBool\n"
+ "%3 = OpTypeFunction %1\n"
+ "%2 = OpConstantTrue %1\n"
+
+ "%4 = OpFunction %3 None %1\n"
+ "%6 = OpLabel\n"
+ "OpBranch %7\n"
+ "%7 = OpLabel\n"
+ "%8 = OpPhi %1 %2 %7 %2 %6\n" // use of %8 changed to %2
+ "OpBranch %7\n"
+ "OpFunctionEnd",
+ {
+ { // defs
+ {1, "%1 = OpTypeBool"},
+ {2, "%2 = OpConstantTrue %1"},
+ {3, "%3 = OpTypeFunction %1"},
+ {4, "%4 = OpFunction %3 None %1"},
+ {6, "%6 = OpLabel"},
+ {7, "%7 = OpLabel"},
+ {8, "%8 = OpPhi %1 %2 %7 %2 %6"},
+ },
+ { // uses
+ {1,
+ {
+ "%2 = OpConstantTrue %1",
+ "%3 = OpTypeFunction %1",
+ "%4 = OpFunction %3 None %1",
+ "%8 = OpPhi %1 %2 %7 %2 %6",
+ }
+ },
+ {2,
+ {
+ // Only checking users
+ "%8 = OpPhi %1 %2 %7 %2 %6",
+ }
+ },
+ {3, {"%4 = OpFunction %3 None %1"}},
+ {6, {"%8 = OpPhi %1 %2 %7 %2 %6"}},
+ {7,
+ {
+ "OpBranch %7",
+ "%8 = OpPhi %1 %2 %7 %2 %6",
+ "OpBranch %7",
+ }
+ },
+ // {8, {"%8 = OpPhi %1 %8 %7 %2 %6"}},
+ },
+ },
+ },
+ })
+);
+// clang-format on
+
struct KillDefCase {
const char* before;
std::vector<uint32_t> ids_to_kill;
@@ -1656,7 +2019,7 @@
"OpGroupDecorate %1 %2 %3",
},
},
- // memeber decorate
+ // member decorate
{
// code
"OpMemberDecorate %1 0 RelaxedPrecision "
@@ -1707,9 +2070,10 @@
def->SetInOperands({{SPV_OPERAND_TYPE_ID, {25}}});
context->UpdateDefUse(def);
- auto users = def_use_mgr->id_to_users();
- UserEntry entry = {def, use};
- EXPECT_THAT(users, Contains(entry));
+ auto scanUser = [&](Instruction* user) { return user != use; };
+ bool userFound = !def_use_mgr->WhileEachUser(def, scanUser);
+
+ EXPECT_TRUE(userFound);
}
// clang-format on
diff --git a/third_party/SPIRV-Tools/test/opt/dominator_tree/generated.cpp b/third_party/SPIRV-Tools/test/opt/dominator_tree/generated.cpp
index 534f770..4fccef0 100644
--- a/third_party/SPIRV-Tools/test/opt/dominator_tree/generated.cpp
+++ b/third_party/SPIRV-Tools/test/opt/dominator_tree/generated.cpp
@@ -57,7 +57,7 @@
}
}
-// Check that x does not dominates y and vise versa
+// Check that x does not dominates y and vice versa
void check_no_dominance(const DominatorAnalysisBase& dom_tree,
const Function* fn, uint32_t x, uint32_t y) {
SCOPED_TRACE("Check no domination for Basic Block " + std::to_string(x) +
diff --git a/third_party/SPIRV-Tools/test/opt/eliminate_dead_const_test.cpp b/third_party/SPIRV-Tools/test/opt/eliminate_dead_const_test.cpp
index 59f06f9..87aab54 100644
--- a/third_party/SPIRV-Tools/test/opt/eliminate_dead_const_test.cpp
+++ b/third_party/SPIRV-Tools/test/opt/eliminate_dead_const_test.cpp
@@ -547,7 +547,7 @@
},
// Uint vector type spec constants. One vector has all component dead,
- // another vector has one dead unsigend integer and one used unsigned
+ // another vector has one dead unsigned integer and one used unsigned
// integer.
{
/* .used_consts = */
diff --git a/third_party/SPIRV-Tools/test/opt/flatten_decoration_test.cpp b/third_party/SPIRV-Tools/test/opt/flatten_decoration_test.cpp
index d8d8867..63207fd 100644
--- a/third_party/SPIRV-Tools/test/opt/flatten_decoration_test.cpp
+++ b/third_party/SPIRV-Tools/test/opt/flatten_decoration_test.cpp
@@ -43,7 +43,7 @@
)";
}
-// Retuns types
+// Returns types
std::string TypesAndFunctionsAssembly() {
return
R"(%void = OpTypeVoid
diff --git a/third_party/SPIRV-Tools/test/opt/fold_test.cpp b/third_party/SPIRV-Tools/test/opt/fold_test.cpp
index 009631c..df8f3b1 100644
--- a/third_party/SPIRV-Tools/test/opt/fold_test.cpp
+++ b/third_party/SPIRV-Tools/test/opt/fold_test.cpp
@@ -7092,7 +7092,7 @@
// Test folding instructions that do not have a result. The instruction
// that will be folded is the last instruction before the return. If there
-// are multiple returns, there is not guarentee which one is used.
+// are multiple returns, there is not guarantee which one is used.
TEST_P(MatchingInstructionWithNoResultFoldingTest, Case) {
const auto& tc = GetParam();
diff --git a/third_party/SPIRV-Tools/test/opt/freeze_spec_const_test.cpp b/third_party/SPIRV-Tools/test/opt/freeze_spec_const_test.cpp
index e5999ce..ad0fc32 100644
--- a/third_party/SPIRV-Tools/test/opt/freeze_spec_const_test.cpp
+++ b/third_party/SPIRV-Tools/test/opt/freeze_spec_const_test.cpp
@@ -128,6 +128,51 @@
/* skip_nop = */ true);
}
+TEST_F(FreezeSpecConstantValueRemoveDecorationTest,
+ RemoveDecorationForLocalSizeIdWithSpecId) {
+ std::vector<const char*> text = {
+ // clang-format off
+ "OpCapability Shader",
+ "%1 = OpExtInstImport \"GLSL.std.450\"",
+ "OpMemoryModel Logical GLSL450",
+ "OpEntryPoint GLCompute %2 \"main\"",
+ "OpExecutionModeId %2 LocalSizeId %uint_32 %uint_1 %uint_1_0",
+ "OpSource GLSL 450",
+ "OpDecorate %3 SpecId 18",
+ "OpDecorate %5 SpecId 19",
+ "%void = OpTypeVoid",
+ "%9 = OpTypeFunction %void",
+ "%uint = OpTypeInt 32 0",
+ "%uint_32 = OpSpecConstant %uint 32",
+ "%uint_1 = OpConstant %uint 1",
+ "%uint_1_0 = OpSpecConstant %uint 1",
+ "%2 = OpFunction %void None %9",
+ "%11 = OpLabel",
+ "OpReturn",
+ "OpFunctionEnd",
+ // clang-format on
+ };
+ std::string expected_disassembly = SelectiveJoin(text, [](const char* line) {
+ return std::string(line).find("SpecId") != std::string::npos;
+ });
+ std::vector<std::pair<const char*, const char*>> replacement_pairs = {
+ {"%uint_32 = OpSpecConstant %uint 32", "%uint_32 = OpConstant %uint 32"},
+ {"%uint_1_0 = OpSpecConstant %uint 1", "%uint_1_0 = OpConstant %uint 1"},
+ };
+ for (auto& p : replacement_pairs) {
+ EXPECT_TRUE(FindAndReplace(&expected_disassembly, p.first, p.second))
+ << "text:\n"
+ << expected_disassembly << "\n"
+ << "find_str:\n"
+ << p.first << "\n"
+ << "replace_str:\n"
+ << p.second << "\n";
+ }
+ SinglePassRunAndCheck<FreezeSpecConstantValuePass>(JoinAllInsts(text),
+ expected_disassembly,
+ /* skip_nop = */ true);
+}
+
} // namespace
} // namespace opt
} // namespace spvtools
diff --git a/third_party/SPIRV-Tools/test/opt/graphics_robust_access_test.cpp b/third_party/SPIRV-Tools/test/opt/graphics_robust_access_test.cpp
index 3c23347..057b909 100644
--- a/third_party/SPIRV-Tools/test/opt/graphics_robust_access_test.cpp
+++ b/third_party/SPIRV-Tools/test/opt/graphics_robust_access_test.cpp
@@ -1242,7 +1242,7 @@
; CHECK-DAG: %int_9 = OpConstant %int 9
; CHECK-DAG: %[[intmax:\w+]] = OpConstant %int 2147483647
; CHECK: OpLabel
- ; This access chain is manufatured only so we can compute the array length.
+ ; This access chain is manufactured only so we can compute the array length.
; Note that the %int_9 is already clamped
; CHECK: %[[ssbo_base:\w+]] = )" << ac
<< R"( %[[ssbo_p]] %var %int_9
diff --git a/third_party/SPIRV-Tools/test/opt/inline_test.cpp b/third_party/SPIRV-Tools/test/opt/inline_test.cpp
index d22f027..cefd8e5 100644
--- a/third_party/SPIRV-Tools/test/opt/inline_test.cpp
+++ b/third_party/SPIRV-Tools/test/opt/inline_test.cpp
@@ -4238,7 +4238,7 @@
// This shader causes CreateDebugInlinedAt to generate a constant.
// Using the Constant manager would attempt to build the invalidated
// DefUse manager during inlining which could cause an assert because
- // the function is in an inconsistant state. This test verifies that
+ // the function is in an inconsistent state. This test verifies that
// CreateDebugInlinedAt detects that the DefUse manager is disabled
// and creates a duplicate constant safely without the Constant manager.
//
diff --git a/third_party/SPIRV-Tools/test/opt/inst_bindless_check_test.cpp b/third_party/SPIRV-Tools/test/opt/inst_bindless_check_test.cpp
index 1a42329..4c271de 100644
--- a/third_party/SPIRV-Tools/test/opt/inst_bindless_check_test.cpp
+++ b/third_party/SPIRV-Tools/test/opt/inst_bindless_check_test.cpp
@@ -9984,8 +9984,8 @@
//
// Compute shader
// Geometry shader
-// Tesselation control shader
-// Tesselation eval shader
+// Tessellation control shader
+// Tessellation eval shader
// OpImage
// SampledImage variable
diff --git a/third_party/SPIRV-Tools/test/opt/inst_debug_printf_test.cpp b/third_party/SPIRV-Tools/test/opt/inst_debug_printf_test.cpp
index 8123ffb..c5fd679 100644
--- a/third_party/SPIRV-Tools/test/opt/inst_debug_printf_test.cpp
+++ b/third_party/SPIRV-Tools/test/opt/inst_debug_printf_test.cpp
@@ -206,8 +206,8 @@
//
// Compute shader
// Geometry shader
-// Tesselation control shader
-// Tesselation eval shader
+// Tessellation control shader
+// Tessellation eval shader
// Vertex shader
} // namespace
diff --git a/third_party/SPIRV-Tools/test/opt/instruction_test.cpp b/third_party/SPIRV-Tools/test/opt/instruction_test.cpp
index c5b92ef..2a48134 100644
--- a/third_party/SPIRV-Tools/test/opt/instruction_test.cpp
+++ b/third_party/SPIRV-Tools/test/opt/instruction_test.cpp
@@ -62,12 +62,6 @@
EXPECT_EQ(inst.end(), inst.begin());
}
-TEST(InstructionTest, OperandAsCString) {
- Operand::OperandData abcde{0x64636261, 0x65};
- Operand operand(SPV_OPERAND_TYPE_LITERAL_STRING, std::move(abcde));
- EXPECT_STREQ("abcde", operand.AsCString());
-}
-
TEST(InstructionTest, OperandAsString) {
Operand::OperandData abcde{0x64636261, 0x65};
Operand operand(SPV_OPERAND_TYPE_LITERAL_STRING, std::move(abcde));
diff --git a/third_party/SPIRV-Tools/test/opt/loop_optimizations/loop_descriptions.cpp b/third_party/SPIRV-Tools/test/opt/loop_optimizations/loop_descriptions.cpp
index 4d2f989..b3f4f44 100644
--- a/third_party/SPIRV-Tools/test/opt/loop_optimizations/loop_descriptions.cpp
+++ b/third_party/SPIRV-Tools/test/opt/loop_optimizations/loop_descriptions.cpp
@@ -298,7 +298,7 @@
/*
Generated from following GLSL with latch block artificially inserted to be
-seperate from continue.
+separate from continue.
#version 430
void main(void) {
float x[10];
diff --git a/third_party/SPIRV-Tools/test/opt/loop_optimizations/loop_fission.cpp b/third_party/SPIRV-Tools/test/opt/loop_optimizations/loop_fission.cpp
index 55b9c26..bc3ec39 100644
--- a/third_party/SPIRV-Tools/test/opt/loop_optimizations/loop_fission.cpp
+++ b/third_party/SPIRV-Tools/test/opt/loop_optimizations/loop_fission.cpp
@@ -692,7 +692,7 @@
SinglePassRunAndCheck<LoopFissionPass>(source, expected, true);
// By passing 1 as argument we are using the constructor which makes the
-// critera to split the loop be if the registers in the loop exceede 1. By
+// criteria to split the loop be if the registers in the loop exceede 1. By
// using this constructor we are also enabling multiple passes (disabled by
// default).
SinglePassRunAndCheck<LoopFissionPass>(source, expected_multiple_passes, true,
diff --git a/third_party/SPIRV-Tools/test/opt/loop_optimizations/unroll_simple.cpp b/third_party/SPIRV-Tools/test/opt/loop_optimizations/unroll_simple.cpp
index ac0dfde..b72305c 100644
--- a/third_party/SPIRV-Tools/test/opt/loop_optimizations/unroll_simple.cpp
+++ b/third_party/SPIRV-Tools/test/opt/loop_optimizations/unroll_simple.cpp
@@ -886,7 +886,7 @@
LoopUnroller loop_unroller;
SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
// By unrolling by a factor that doesn't divide evenly into the number of loop
- // iterations we perfom an additional transform when partially unrolling to
+ // iterations we perform an additional transform when partially unrolling to
// account for the remainder.
SinglePassRunAndCheck<PartialUnrollerTestPass<3>>(text, output, false);
}
@@ -3118,7 +3118,7 @@
/*
Generated from following GLSL with latch block artificially inserted to be
-seperate from continue.
+separate from continue.
#version 430
void main(void) {
float x[10];
diff --git a/third_party/SPIRV-Tools/test/opt/module_test.cpp b/third_party/SPIRV-Tools/test/opt/module_test.cpp
index a3c2eed..17a1365 100644
--- a/third_party/SPIRV-Tools/test/opt/module_test.cpp
+++ b/third_party/SPIRV-Tools/test/opt/module_test.cpp
@@ -52,7 +52,7 @@
}
TEST(ModuleTest, ComputeIdBound) {
- // Emtpy module case.
+ // Empty module case.
EXPECT_EQ(1u, BuildModule("")->module()->ComputeIdBound());
// Sensitive to result id
EXPECT_EQ(2u, BuildModule("%void = OpTypeVoid")->module()->ComputeIdBound());
diff --git a/third_party/SPIRV-Tools/test/opt/optimizer_test.cpp b/third_party/SPIRV-Tools/test/opt/optimizer_test.cpp
index a51638a..0171c09 100644
--- a/third_party/SPIRV-Tools/test/opt/optimizer_test.cpp
+++ b/third_party/SPIRV-Tools/test/opt/optimizer_test.cpp
@@ -147,7 +147,7 @@
std::vector<std::string> pass_flags = {
"--strip-debug",
- "--strip-reflect",
+ "--strip-nonsemantic",
"--set-spec-const-default-value=23:42 21:12",
"--if-conversion",
"--freeze-spec-const",
diff --git a/third_party/SPIRV-Tools/test/opt/pass_manager_test.cpp b/third_party/SPIRV-Tools/test/opt/pass_manager_test.cpp
index 22d5e22..4f36d5b 100644
--- a/third_party/SPIRV-Tools/test/opt/pass_manager_test.cpp
+++ b/third_party/SPIRV-Tools/test/opt/pass_manager_test.cpp
@@ -30,7 +30,7 @@
using spvtest::GetIdBound;
using ::testing::Eq;
-// A null pass whose construtors accept arguments
+// A null pass whose constructors accept arguments
class NullPassWithArgs : public NullPass {
public:
NullPassWithArgs(uint32_t) {}
diff --git a/third_party/SPIRV-Tools/test/opt/replace_desc_array_access_using_var_index_test.cpp b/third_party/SPIRV-Tools/test/opt/replace_desc_array_access_using_var_index_test.cpp
index ca62581..9900304 100644
--- a/third_party/SPIRV-Tools/test/opt/replace_desc_array_access_using_var_index_test.cpp
+++ b/third_party/SPIRV-Tools/test/opt/replace_desc_array_access_using_var_index_test.cpp
@@ -406,6 +406,94 @@
SinglePassRunAndMatch<ReplaceDescArrayAccessUsingVarIndex>(text, true);
}
+TEST_F(ReplaceDescArrayAccessUsingVarIndexTest,
+ ReplaceAccessChainToTextureArrayWithNonUniformIndex) {
+ const std::string text = R"(
+ OpCapability Shader
+ OpCapability ShaderNonUniform
+ OpCapability SampledImageArrayNonUniformIndexing
+ OpExtension "SPV_EXT_descriptor_indexing"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %PSMain "PSMain" %in_var_TEXCOORD0 %in_var_MATERIAL_ID %out_var_SV_TARGET
+ OpExecutionMode %PSMain OriginUpperLeft
+ OpSource HLSL 610
+ OpName %type_sampler "type.sampler"
+ OpName %sampler_ "sampler_"
+ OpName %type_2d_image "type.2d.image"
+ OpName %texture_2d "texture_2d"
+ OpName %in_var_TEXCOORD0 "in.var.TEXCOORD0"
+ OpName %in_var_MATERIAL_ID "in.var.MATERIAL_ID"
+ OpName %out_var_SV_TARGET "out.var.SV_TARGET"
+ OpName %PSMain "PSMain"
+ OpName %type_sampled_image "type.sampled.image"
+ OpDecorate %in_var_MATERIAL_ID Flat
+ OpDecorate %in_var_TEXCOORD0 Location 0
+ OpDecorate %in_var_MATERIAL_ID Location 1
+ OpDecorate %out_var_SV_TARGET Location 0
+ OpDecorate %sampler_ DescriptorSet 1
+ OpDecorate %sampler_ Binding 1
+ OpDecorate %texture_2d DescriptorSet 0
+ OpDecorate %texture_2d Binding 0
+
+; CHECK: OpDecorate [[v0:%\w+]] NonUniform
+; CHECK: OpDecorate [[v1:%\w+]] NonUniform
+; CHECK: OpDecorate [[v2:%\w+]] NonUniform
+; CHECK: OpDecorate [[v3:%\w+]] NonUniform
+
+ OpDecorate %10 NonUniform
+ OpDecorate %11 NonUniform
+ OpDecorate %12 NonUniform
+ OpDecorate %13 NonUniform
+%type_sampler = OpTypeSampler
+%_ptr_UniformConstant_type_sampler = OpTypePointer UniformConstant %type_sampler
+ %uint = OpTypeInt 32 0
+ %uint_4 = OpConstant %uint 4
+ %float = OpTypeFloat 32
+%type_2d_image = OpTypeImage %float 2D 2 0 0 1 Unknown
+%_arr_type_2d_image_uint_4 = OpTypeArray %type_2d_image %uint_4
+%_ptr_UniformConstant__arr_type_2d_image_uint_4 = OpTypePointer UniformConstant %_arr_type_2d_image_uint_4
+ %v2float = OpTypeVector %float 2
+%_ptr_Input_v2float = OpTypePointer Input %v2float
+%_ptr_Input_uint = OpTypePointer Input %uint
+ %v4float = OpTypeVector %float 4
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+ %void = OpTypeVoid
+ %26 = OpTypeFunction %void
+%_ptr_UniformConstant_type_2d_image = OpTypePointer UniformConstant %type_2d_image
+%type_sampled_image = OpTypeSampledImage %type_2d_image
+ %sampler_ = OpVariable %_ptr_UniformConstant_type_sampler UniformConstant
+ %texture_2d = OpVariable %_ptr_UniformConstant__arr_type_2d_image_uint_4 UniformConstant
+%in_var_TEXCOORD0 = OpVariable %_ptr_Input_v2float Input
+%in_var_MATERIAL_ID = OpVariable %_ptr_Input_uint Input
+%out_var_SV_TARGET = OpVariable %_ptr_Output_v4float Output
+
+; CHECK: %uint_0 = OpConstant %uint 0
+; CHECK: %uint_1 = OpConstant %uint 1
+; CHECK: %uint_2 = OpConstant %uint 2
+; CHECK: %uint_3 = OpConstant %uint 3
+
+ %PSMain = OpFunction %void None %26
+ %28 = OpLabel
+ %29 = OpLoad %v2float %in_var_TEXCOORD0
+ %30 = OpLoad %uint %in_var_MATERIAL_ID
+; CHECK: [[v0]] = OpCopyObject %uint {{%\w+}}
+ %10 = OpCopyObject %uint %30
+; CHECK: [[v1]] = OpAccessChain %_ptr_UniformConstant_type_2d_image %texture_2d [[v0]]
+ %11 = OpAccessChain %_ptr_UniformConstant_type_2d_image %texture_2d %10
+; CHECK: [[v2]] = OpLoad %type_2d_image [[v1]]
+ %12 = OpLoad %type_2d_image %11
+ %31 = OpLoad %type_sampler %sampler_
+; CHECK: [[v3]] = OpSampledImage %type_sampled_image [[v2]] {{%\w+}}
+ %13 = OpSampledImage %type_sampled_image %12 %31
+ %32 = OpImageSampleImplicitLod %v4float %13 %29 None
+ OpStore %out_var_SV_TARGET %32
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ SinglePassRunAndMatch<ReplaceDescArrayAccessUsingVarIndex>(text, true);
+}
+
} // namespace
} // namespace opt
} // namespace spvtools
diff --git a/third_party/SPIRV-Tools/test/opt/scalar_replacement_test.cpp b/third_party/SPIRV-Tools/test/opt/scalar_replacement_test.cpp
index 8cb888c..7db997d 100644
--- a/third_party/SPIRV-Tools/test/opt/scalar_replacement_test.cpp
+++ b/third_party/SPIRV-Tools/test/opt/scalar_replacement_test.cpp
@@ -470,9 +470,9 @@
; CHECK: [[const_array:%\w+]] = OpConstantComposite [[array]]
; CHECK: [[const_matrix:%\w+]] = OpConstantNull [[matrix]]
; CHECK: [[const_struct1:%\w+]] = OpConstantComposite [[struct1]]
-; CHECK: OpConstantNull [[uint]]
-; CHECK: OpConstantNull [[vector]]
-; CHECK: OpConstantNull [[long]]
+; CHECK: OpUndef [[uint]]
+; CHECK: OpUndef [[vector]]
+; CHECK: OpUndef [[long]]
; CHECK: OpFunction
; CHECK-NOT: OpVariable [[struct2_ptr]] Function
; CHECK: OpVariable [[uint_ptr]] Function
@@ -654,11 +654,10 @@
; CHECK: [[uint:%\w+]] = OpTypeInt 32 0
; CHECK: [[struct1:%\w+]] = OpTypeStruct [[uint]] [[uint]]
; CHECK: [[uint_ptr:%\w+]] = OpTypePointer Function [[uint]]
-; CHECK: [[const:%\w+]] = OpConstant [[uint]] 0
-; CHECK: [[null:%\w+]] = OpConstantNull [[uint]]
+; CHECK: [[undef:%\w+]] = OpUndef [[uint]]
; CHECK: [[var0:%\w+]] = OpVariable [[uint_ptr]] Function
; CHECK: [[l0:%\w+]] = OpLoad [[uint]] [[var0]] Nontemporal
-; CHECK: OpCompositeConstruct [[struct1]] [[l0]] [[null]]
+; CHECK: OpCompositeConstruct [[struct1]] [[l0]] [[undef]]
;
OpCapability Shader
OpCapability Linkage
@@ -1267,16 +1266,16 @@
; CHECK: [[struct1:%\w+]] = OpTypeStruct [[uint]] [[uint]]
; CHECK: [[uint_ptr:%\w+]] = OpTypePointer Function [[uint]]
; CHECK: [[const:%\w+]] = OpConstant [[uint]] 0
-; CHECK: [[null:%\w+]] = OpConstantNull [[uint]]
+; CHECK: [[undef:%\w+]] = OpUndef [[uint]]
; CHECK: [[var0:%\w+]] = OpVariable [[uint_ptr]] Function
; CHECK: [[var1:%\w+]] = OpVariable [[uint_ptr]] Function
; CHECK-NOT: OpVariable
; CHECK: [[l0:%\w+]] = OpLoad [[uint]] [[var0]]
-; CHECK: [[c0:%\w+]] = OpCompositeConstruct [[struct1]] [[l0]] [[null]]
+; CHECK: [[c0:%\w+]] = OpCompositeConstruct [[struct1]] [[l0]] [[undef]]
; CHECK: [[e0:%\w+]] = OpCompositeExtract [[uint]] [[c0]] 0
; CHECK: OpStore [[var1]] [[e0]]
; CHECK: [[l1:%\w+]] = OpLoad [[uint]] [[var1]]
-; CHECK: [[c1:%\w+]] = OpCompositeConstruct [[struct1]] [[l1]] [[null]]
+; CHECK: [[c1:%\w+]] = OpCompositeConstruct [[struct1]] [[l1]] [[undef]]
; CHECK: [[e1:%\w+]] = OpCompositeExtract [[uint]] [[c1]] 0
;
OpCapability Shader
@@ -1314,7 +1313,7 @@
; CHECK: [[struct1:%\w+]] = OpTypeStruct [[uint]] [[uint]]
; CHECK: [[uint_ptr:%\w+]] = OpTypePointer Function [[uint]]
; CHECK: [[const:%\w+]] = OpConstant [[uint]] 0
-; CHECK: [[null:%\w+]] = OpConstantNull [[uint]]
+; CHECK: [[undef:%\w+]] = OpUndef [[uint]]
; CHECK: [[var1:%\w+]] = OpVariable [[uint_ptr]] Function
; CHECK: [[var0a:%\w+]] = OpVariable [[uint_ptr]] Function
; CHECK: [[var0b:%\w+]] = OpVariable [[uint_ptr]] Function
@@ -1325,7 +1324,7 @@
; CHECK: [[e0:%\w+]] = OpCompositeExtract [[uint]] [[c0]] 0
; CHECK: OpStore [[var1]] [[e0]]
; CHECK: [[l1:%\w+]] = OpLoad [[uint]] [[var1]]
-; CHECK: [[c1:%\w+]] = OpCompositeConstruct [[struct1]] [[l1]] [[null]]
+; CHECK: [[c1:%\w+]] = OpCompositeConstruct [[struct1]] [[l1]] [[undef]]
; CHECK: [[e1:%\w+]] = OpCompositeExtract [[uint]] [[c1]] 0
;
OpCapability Shader
@@ -1362,14 +1361,14 @@
; CHECK: [[struct1:%\w+]] = OpTypeStruct [[uint]] [[struct_member:%\w+]]
; CHECK: [[uint_ptr:%\w+]] = OpTypePointer Function [[uint]]
; CHECK: [[const:%\w+]] = OpConstant [[uint]] 0
-; CHECK: [[null:%\w+]] = OpConstantNull [[struct_member]]
+; CHECK: [[undef:%\w+]] = OpUndef [[struct_member]]
; CHECK: [[var0a:%\w+]] = OpVariable [[uint_ptr]] Function
; CHECK: [[var1:%\w+]] = OpVariable [[uint_ptr]] Function
; CHECK: [[var0b:%\w+]] = OpVariable [[uint_ptr]] Function
; CHECK-NOT: OpVariable
; CHECK: OpStore [[var1]]
; CHECK: [[l1:%\w+]] = OpLoad [[uint]] [[var1]]
-; CHECK: [[c1:%\w+]] = OpCompositeConstruct [[struct1]] [[l1]] [[null]]
+; CHECK: [[c1:%\w+]] = OpCompositeConstruct [[struct1]] [[l1]] [[undef]]
; CHECK: [[e1:%\w+]] = OpCompositeExtract [[uint]] [[c1]] 0
;
OpCapability Shader
@@ -1444,13 +1443,13 @@
; CHECK: [[struct1:%\w+]] = OpTypeStruct [[uint]] [[struct_member:%\w+]]
; CHECK: [[uint_ptr:%\w+]] = OpTypePointer Function [[uint]]
; CHECK: [[const:%\w+]] = OpConstant [[uint]] 0
-; CHECK: [[null:%\w+]] = OpConstantNull [[struct_member]]
+; CHECK: [[undef:%\w+]] = OpUndef [[struct_member]]
; CHECK: [[var0a:%\w+]] = OpVariable [[uint_ptr]] Function
; CHECK: [[var1:%\w+]] = OpVariable [[uint_ptr]] Function
; CHECK: [[var0b:%\w+]] = OpVariable [[uint_ptr]] Function
; CHECK: OpStore [[var1]]
; CHECK: [[l1:%\w+]] = OpLoad [[uint]] [[var1]]
-; CHECK: [[c1:%\w+]] = OpCompositeConstruct [[struct1]] [[l1]] [[null]]
+; CHECK: [[c1:%\w+]] = OpCompositeConstruct [[struct1]] [[l1]] [[undef]]
; CHECK: [[e1:%\w+]] = OpCompositeExtract [[uint]] [[c1]] 0
;
OpCapability Shader
@@ -2263,6 +2262,40 @@
SinglePassRunAndCheck<ScalarReplacementPass>(text, text, false);
}
+TEST_F(ScalarReplacementTest, UndefImageMember) {
+ // Test that scalar replacement creates an undef for a type that cannot have
+ // and OpConstantNull.
+ const std::string text = R"(
+; CHECK: [[image_type:%\w+]] = OpTypeSampledImage {{%\w+}}
+; CHECK: [[struct_type:%\w+]] = OpTypeStruct [[image_type]]
+; CHECK: [[undef:%\w+]] = OpUndef [[image_type]]
+; CHECK: {{%\w+}} = OpCompositeConstruct [[struct_type]] [[undef]]
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %2 "main"
+ OpExecutionMode %2 OriginUpperLeft
+ %void = OpTypeVoid
+ %4 = OpTypeFunction %void
+ %float = OpTypeFloat 32
+ %6 = OpTypeImage %float 2D 0 0 0 1 Unknown
+ %7 = OpTypeSampledImage %6
+ %_struct_8 = OpTypeStruct %7
+ %9 = OpTypeFunction %_struct_8
+ %10 = OpUndef %_struct_8
+%_ptr_Function__struct_8 = OpTypePointer Function %_struct_8
+ %2 = OpFunction %void None %4
+ %11 = OpLabel
+ %16 = OpVariable %_ptr_Function__struct_8 Function
+ OpStore %16 %10
+ %12 = OpLoad %_struct_8 %16
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ SinglePassRunAndMatch<ScalarReplacementPass>(text, true);
+}
+
} // namespace
} // namespace opt
} // namespace spvtools
diff --git a/third_party/SPIRV-Tools/test/opt/set_spec_const_default_value_test.cpp b/third_party/SPIRV-Tools/test/opt/set_spec_const_default_value_test.cpp
index f1dd50e..10f805b 100644
--- a/third_party/SPIRV-Tools/test/opt/set_spec_const_default_value_test.cpp
+++ b/third_party/SPIRV-Tools/test/opt/set_spec_const_default_value_test.cpp
@@ -618,7 +618,7 @@
{"", SpecIdToValueBitPatternMap{}, ""},
// 1. Empty with non-empty values to set.
{"", SpecIdToValueBitPatternMap{{1, {100}}, {2, {200}}}, ""},
- // 2. Baisc bool type.
+ // 2. Basic bool type.
{
// code
"OpDecorate %1 SpecId 100\n"
diff --git a/third_party/SPIRV-Tools/test/opt/spread_volatile_semantics_test.cpp b/third_party/SPIRV-Tools/test/opt/spread_volatile_semantics_test.cpp
new file mode 100644
index 0000000..83b2dcf
--- /dev/null
+++ b/third_party/SPIRV-Tools/test/opt/spread_volatile_semantics_test.cpp
@@ -0,0 +1,1118 @@
+// 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 <string>
+
+#include "gmock/gmock.h"
+#include "test/opt/pass_fixture.h"
+#include "test/opt/pass_utils.h"
+
+namespace spvtools {
+namespace opt {
+namespace {
+
+struct ExecutionModelAndBuiltIn {
+ const char* execution_model;
+ const char* built_in;
+ const bool use_v4uint;
+};
+
+using AddVolatileDecorationTest =
+ PassTest<::testing::TestWithParam<ExecutionModelAndBuiltIn>>;
+
+TEST_P(AddVolatileDecorationTest, InMain) {
+ const auto& tc = GetParam();
+ const std::string execution_model(tc.execution_model);
+ const std::string built_in(tc.built_in);
+ const std::string var_type =
+ tc.use_v4uint ? "%_ptr_Input_v4uint" : "%_ptr_Input_uint";
+ const std::string var_load_type = tc.use_v4uint ? "%v4uint" : "%uint";
+
+ const std::string text =
+ std::string(R"(OpCapability RuntimeDescriptorArray
+OpCapability RayTracingKHR
+OpCapability SubgroupBallotKHR
+OpExtension "SPV_EXT_descriptor_indexing"
+OpExtension "SPV_KHR_ray_tracing"
+OpExtension "SPV_KHR_shader_ballot"
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint )") +
+ execution_model + std::string(R"( %main "main" %var
+OpSource GLSL 460
+OpSourceExtension "GL_EXT_nonuniform_qualifier"
+OpSourceExtension "GL_KHR_ray_tracing"
+OpName %main "main"
+OpName %StorageBuffer "StorageBuffer"
+OpMemberName %StorageBuffer 0 "index"
+OpMemberName %StorageBuffer 1 "red"
+OpName %sbo "sbo"
+OpName %images "images"
+OpMemberDecorate %StorageBuffer 0 Offset 0
+OpMemberDecorate %StorageBuffer 1 Offset 4
+OpDecorate %StorageBuffer BufferBlock
+OpDecorate %sbo DescriptorSet 0
+OpDecorate %sbo Binding 0
+OpDecorate %images DescriptorSet 0
+OpDecorate %images Binding 1
+OpDecorate %images NonWritable
+)") + std::string(R"(
+; CHECK: OpDecorate [[var:%\w+]] BuiltIn )") +
+ built_in + std::string(R"(
+; CHECK: OpDecorate [[var]] Volatile
+OpDecorate %var BuiltIn )") + built_in + std::string(R"(
+%void = OpTypeVoid
+%3 = OpTypeFunction %void
+%uint = OpTypeInt 32 0
+%float = OpTypeFloat 32
+%StorageBuffer = OpTypeStruct %uint %float
+%_ptr_Uniform_StorageBuffer = OpTypePointer Uniform %StorageBuffer
+%sbo = OpVariable %_ptr_Uniform_StorageBuffer Uniform
+%int = OpTypeInt 32 1
+%int_1 = OpConstant %int 1
+%13 = OpTypeImage %float 2D 0 0 0 2 Rgba32f
+%_runtimearr_13 = OpTypeRuntimeArray %13
+%_ptr_UniformConstant__runtimearr_13 = OpTypePointer UniformConstant %_runtimearr_13
+%images = OpVariable %_ptr_UniformConstant__runtimearr_13 UniformConstant
+%_ptr_Input_uint = OpTypePointer Input %uint
+%v4uint = OpTypeVector %uint 4
+%_ptr_Input_v4uint = OpTypePointer Input %v4uint
+%var = OpVariable )") +
+ var_type + std::string(R"( Input
+%int_0 = OpConstant %int 0
+%_ptr_Uniform_uint = OpTypePointer Uniform %uint
+%_ptr_UniformConstant_13 = OpTypePointer UniformConstant %13
+%v2int = OpTypeVector %int 2
+%25 = OpConstantComposite %v2int %int_0 %int_0
+%v4float = OpTypeVector %float 4
+%uint_0 = OpConstant %uint 0
+%_ptr_Uniform_float = OpTypePointer Uniform %float
+%main = OpFunction %void None %3
+%5 = OpLabel
+%19 = OpAccessChain %_ptr_Uniform_uint %sbo %int_0
+%20 = OpLoad %uint %19
+%load = OpLoad )") + var_load_type + std::string(R"( %var
+%22 = OpAccessChain %_ptr_UniformConstant_13 %images %20
+%23 = OpLoad %13 %22
+%27 = OpImageRead %v4float %23 %25
+%29 = OpCompositeExtract %float %27 0
+%31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1
+OpStore %31 %29
+OpReturn
+OpFunctionEnd
+)");
+
+ SinglePassRunAndMatch<SpreadVolatileSemantics>(text, true);
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ AddVolatileDecoration, AddVolatileDecorationTest,
+ ::testing::ValuesIn(std::vector<ExecutionModelAndBuiltIn>{
+ {"RayGenerationKHR", "SubgroupSize", false},
+ {"RayGenerationKHR", "SubgroupLocalInvocationId", false},
+ {"RayGenerationKHR", "SubgroupEqMask", true},
+ {"ClosestHitKHR", "SubgroupLocalInvocationId", true},
+ {"IntersectionKHR", "SubgroupEqMask", true},
+ {"MissKHR", "SubgroupGeMask", true},
+ {"CallableKHR", "SubgroupGtMask", true},
+ {"RayGenerationKHR", "SubgroupLeMask", true},
+ }));
+
+using SetLoadVolatileTest =
+ PassTest<::testing::TestWithParam<ExecutionModelAndBuiltIn>>;
+
+TEST_P(SetLoadVolatileTest, InMain) {
+ const auto& tc = GetParam();
+ const std::string execution_model(tc.execution_model);
+ const std::string built_in(tc.built_in);
+
+ const std::string var_type =
+ tc.use_v4uint ? "%_ptr_Input_v4uint" : "%_ptr_Input_uint";
+ const std::string var_value = tc.use_v4uint ? std::string(R"(
+; CHECK: [[ptr:%\w+]] = OpAccessChain %_ptr_Input_uint [[var]] %int_0
+; CHECK: OpLoad {{%\w+}} [[ptr]] Volatile
+%ptr = OpAccessChain %_ptr_Input_uint %var %int_0
+%var_value = OpLoad %uint %ptr)")
+ : std::string(R"(
+; CHECK: OpLoad {{%\w+}} [[var]] Volatile
+%var_value = OpLoad %uint %var)");
+
+ const std::string text = std::string(R"(OpCapability RuntimeDescriptorArray
+OpCapability RayTracingKHR
+OpCapability SubgroupBallotKHR
+OpCapability VulkanMemoryModel
+OpExtension "SPV_KHR_vulkan_memory_model"
+OpExtension "SPV_EXT_descriptor_indexing"
+OpExtension "SPV_KHR_ray_tracing"
+OpExtension "SPV_KHR_shader_ballot"
+OpMemoryModel Logical Vulkan
+OpEntryPoint )") + execution_model +
+ std::string(R"( %main "main" %var
+OpName %main "main"
+OpName %StorageBuffer "StorageBuffer"
+OpMemberName %StorageBuffer 0 "index"
+OpMemberName %StorageBuffer 1 "red"
+OpName %sbo "sbo"
+OpName %images "images"
+OpMemberDecorate %StorageBuffer 0 Offset 0
+OpMemberDecorate %StorageBuffer 1 Offset 4
+OpDecorate %StorageBuffer BufferBlock
+OpDecorate %sbo DescriptorSet 0
+OpDecorate %sbo Binding 0
+OpDecorate %images DescriptorSet 0
+OpDecorate %images Binding 1
+OpDecorate %images NonWritable
+)") + std::string(R"(
+; CHECK: OpDecorate [[var:%\w+]] BuiltIn )") +
+ built_in + std::string(R"(
+OpDecorate %var BuiltIn )") + built_in +
+ std::string(R"(
+%void = OpTypeVoid
+%3 = OpTypeFunction %void
+%uint = OpTypeInt 32 0
+%float = OpTypeFloat 32
+%StorageBuffer = OpTypeStruct %uint %float
+%_ptr_Uniform_StorageBuffer = OpTypePointer Uniform %StorageBuffer
+%sbo = OpVariable %_ptr_Uniform_StorageBuffer Uniform
+%int = OpTypeInt 32 1
+%int_1 = OpConstant %int 1
+%13 = OpTypeImage %float 2D 0 0 0 2 Rgba32f
+%_runtimearr_13 = OpTypeRuntimeArray %13
+%_ptr_UniformConstant__runtimearr_13 = OpTypePointer UniformConstant %_runtimearr_13
+%images = OpVariable %_ptr_UniformConstant__runtimearr_13 UniformConstant
+%_ptr_Input_uint = OpTypePointer Input %uint
+%v4uint = OpTypeVector %uint 4
+%_ptr_Input_v4uint = OpTypePointer Input %v4uint
+%var = OpVariable )") + var_type +
+ std::string(R"( Input
+%int_0 = OpConstant %int 0
+%_ptr_Uniform_uint = OpTypePointer Uniform %uint
+%_ptr_UniformConstant_13 = OpTypePointer UniformConstant %13
+%v2int = OpTypeVector %int 2
+%25 = OpConstantComposite %v2int %int_0 %int_0
+%v4float = OpTypeVector %float 4
+%uint_0 = OpConstant %uint 0
+%_ptr_Uniform_float = OpTypePointer Uniform %float
+%main = OpFunction %void None %3
+%5 = OpLabel
+%19 = OpAccessChain %_ptr_Uniform_uint %sbo %int_0
+%20 = OpLoad %uint %19
+)") + var_value + std::string(R"(
+%test = OpIAdd %uint %var_value %20
+%22 = OpAccessChain %_ptr_UniformConstant_13 %images %test
+%23 = OpLoad %13 %22
+%27 = OpImageRead %v4float %23 %25
+%29 = OpCompositeExtract %float %27 0
+%31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1
+OpStore %31 %29
+OpReturn
+OpFunctionEnd
+)");
+
+ SinglePassRunAndMatch<SpreadVolatileSemantics>(text, true);
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ SetLoadVolatile, SetLoadVolatileTest,
+ ::testing::ValuesIn(std::vector<ExecutionModelAndBuiltIn>{
+ {"RayGenerationKHR", "SubgroupSize", false},
+ {"RayGenerationKHR", "SubgroupLocalInvocationId", false},
+ {"RayGenerationKHR", "SubgroupEqMask", true},
+ {"ClosestHitKHR", "SubgroupLocalInvocationId", true},
+ {"IntersectionKHR", "SubgroupEqMask", true},
+ {"MissKHR", "SubgroupGeMask", true},
+ {"CallableKHR", "SubgroupGtMask", true},
+ {"RayGenerationKHR", "SubgroupLeMask", true},
+ }));
+
+using VolatileSpreadTest = PassTest<::testing::Test>;
+
+TEST_F(VolatileSpreadTest, SpreadVolatileForHelperInvocation) {
+ const std::string text =
+ R"(
+OpCapability Shader
+OpCapability DemoteToHelperInvocation
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %main "main" %var
+OpExecutionMode %main OriginUpperLeft
+
+; CHECK: OpDecorate [[var:%\w+]] BuiltIn HelperInvocation
+; CHECK: OpDecorate [[var]] Volatile
+OpDecorate %var BuiltIn HelperInvocation
+
+%bool = OpTypeBool
+%void = OpTypeVoid
+%void_fn = OpTypeFunction %void
+%_ptr_Input_bool = OpTypePointer Input %bool
+%var = OpVariable %_ptr_Input_bool Input
+%main = OpFunction %void None %void_fn
+%entry = OpLabel
+%load = OpLoad %bool %var
+OpDemoteToHelperInvocation
+OpReturn
+OpFunctionEnd
+)";
+
+ SetTargetEnv(SPV_ENV_UNIVERSAL_1_6);
+ SinglePassRunAndMatch<SpreadVolatileSemantics>(text, true);
+}
+
+TEST_F(VolatileSpreadTest, MultipleExecutionModel) {
+ const std::string text =
+ R"(
+OpCapability RuntimeDescriptorArray
+OpCapability RayTracingKHR
+OpCapability SubgroupBallotKHR
+OpExtension "SPV_EXT_descriptor_indexing"
+OpExtension "SPV_KHR_ray_tracing"
+OpExtension "SPV_KHR_shader_ballot"
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint RayGenerationKHR %RayGeneration "RayGeneration" %var
+OpEntryPoint GLCompute %compute "Compute" %gl_LocalInvocationIndex
+OpExecutionMode %compute LocalSize 16 16 1
+OpSource GLSL 460
+OpSourceExtension "GL_EXT_nonuniform_qualifier"
+OpSourceExtension "GL_KHR_ray_tracing"
+OpName %RayGeneration "RayGeneration"
+OpName %StorageBuffer "StorageBuffer"
+OpMemberName %StorageBuffer 0 "index"
+OpMemberName %StorageBuffer 1 "red"
+OpName %sbo "sbo"
+OpName %images "images"
+OpMemberDecorate %StorageBuffer 0 Offset 0
+OpMemberDecorate %StorageBuffer 1 Offset 4
+OpDecorate %gl_LocalInvocationIndex BuiltIn LocalInvocationIndex
+OpDecorate %StorageBuffer BufferBlock
+OpDecorate %sbo DescriptorSet 0
+OpDecorate %sbo Binding 0
+OpDecorate %images DescriptorSet 0
+OpDecorate %images Binding 1
+OpDecorate %images NonWritable
+
+; CHECK: OpEntryPoint RayGenerationNV {{%\w+}} "RayGeneration" [[var:%\w+]]
+; CHECK: OpDecorate [[var]] BuiltIn SubgroupSize
+; CHECK: OpDecorate [[var]] Volatile
+; CHECK-NOT: OpDecorate {{%\w+}} Volatile
+OpDecorate %var BuiltIn SubgroupSize
+
+%void = OpTypeVoid
+%3 = OpTypeFunction %void
+%uint = OpTypeInt 32 0
+%float = OpTypeFloat 32
+%StorageBuffer = OpTypeStruct %uint %float
+%_ptr_Uniform_StorageBuffer = OpTypePointer Uniform %StorageBuffer
+%sbo = OpVariable %_ptr_Uniform_StorageBuffer Uniform
+%int = OpTypeInt 32 1
+%int_1 = OpConstant %int 1
+%13 = OpTypeImage %float 2D 0 0 0 2 Rgba32f
+%_runtimearr_13 = OpTypeRuntimeArray %13
+%_ptr_UniformConstant__runtimearr_13 = OpTypePointer UniformConstant %_runtimearr_13
+%images = OpVariable %_ptr_UniformConstant__runtimearr_13 UniformConstant
+%_ptr_Input_uint = OpTypePointer Input %uint
+%var = OpVariable %_ptr_Input_uint Input
+%int_0 = OpConstant %int 0
+%_ptr_Uniform_uint = OpTypePointer Uniform %uint
+%_ptr_UniformConstant_13 = OpTypePointer UniformConstant %13
+%v2int = OpTypeVector %int 2
+%25 = OpConstantComposite %v2int %int_0 %int_0
+%v4float = OpTypeVector %float 4
+%uint_0 = OpConstant %uint 0
+%uint_1 = OpConstant %uint 1
+%_ptr_Uniform_float = OpTypePointer Uniform %float
+%gl_LocalInvocationIndex = OpVariable %_ptr_Input_uint Input
+%_ptr_Workgroup_uint = OpTypePointer Workgroup %uint
+%shared = OpVariable %_ptr_Workgroup_uint Workgroup
+
+%RayGeneration = OpFunction %void None %3
+%5 = OpLabel
+%19 = OpAccessChain %_ptr_Uniform_uint %sbo %int_0
+%20 = OpLoad %uint %var
+%22 = OpAccessChain %_ptr_UniformConstant_13 %images %20
+%23 = OpLoad %13 %22
+%27 = OpImageRead %v4float %23 %25
+%29 = OpCompositeExtract %float %27 0
+%31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1
+OpStore %31 %29
+OpReturn
+OpFunctionEnd
+
+%compute = OpFunction %void None %3
+%66 = OpLabel
+%62 = OpLoad %uint %gl_LocalInvocationIndex
+%61 = OpAtomicIAdd %uint %shared %uint_1 %uint_0 %62
+OpReturn
+OpFunctionEnd
+)";
+
+ SinglePassRunAndMatch<SpreadVolatileSemantics>(text, true);
+}
+
+TEST_F(VolatileSpreadTest, VarUsedInMultipleEntryPoints) {
+ const std::string text =
+ R"(
+OpCapability RuntimeDescriptorArray
+OpCapability RayTracingKHR
+OpCapability SubgroupBallotKHR
+OpExtension "SPV_EXT_descriptor_indexing"
+OpExtension "SPV_KHR_ray_tracing"
+OpExtension "SPV_KHR_shader_ballot"
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint RayGenerationKHR %RayGeneration "RayGeneration" %var
+OpEntryPoint ClosestHitKHR %ClosestHit "ClosestHit" %var
+OpSource GLSL 460
+OpSourceExtension "GL_EXT_nonuniform_qualifier"
+OpSourceExtension "GL_KHR_ray_tracing"
+OpName %RayGeneration "RayGeneration"
+OpName %ClosestHit "ClosestHit"
+OpName %StorageBuffer "StorageBuffer"
+OpMemberName %StorageBuffer 0 "index"
+OpMemberName %StorageBuffer 1 "red"
+OpName %sbo "sbo"
+OpName %images "images"
+OpMemberDecorate %StorageBuffer 0 Offset 0
+OpMemberDecorate %StorageBuffer 1 Offset 4
+OpDecorate %gl_LocalInvocationIndex BuiltIn LocalInvocationIndex
+OpDecorate %StorageBuffer BufferBlock
+OpDecorate %sbo DescriptorSet 0
+OpDecorate %sbo Binding 0
+OpDecorate %images DescriptorSet 0
+OpDecorate %images Binding 1
+OpDecorate %images NonWritable
+
+; CHECK: OpEntryPoint RayGenerationNV {{%\w+}} "RayGeneration" [[var:%\w+]]
+; CHECK: OpEntryPoint ClosestHitNV {{%\w+}} "ClosestHit" [[var]]
+; CHECK: OpDecorate [[var]] BuiltIn SubgroupSize
+; CHECK: OpDecorate [[var]] Volatile
+; CHECK-NOT: OpDecorate {{%\w+}} Volatile
+OpDecorate %var BuiltIn SubgroupSize
+
+%void = OpTypeVoid
+%3 = OpTypeFunction %void
+%uint = OpTypeInt 32 0
+%float = OpTypeFloat 32
+%StorageBuffer = OpTypeStruct %uint %float
+%_ptr_Uniform_StorageBuffer = OpTypePointer Uniform %StorageBuffer
+%sbo = OpVariable %_ptr_Uniform_StorageBuffer Uniform
+%int = OpTypeInt 32 1
+%int_1 = OpConstant %int 1
+%13 = OpTypeImage %float 2D 0 0 0 2 Rgba32f
+%_runtimearr_13 = OpTypeRuntimeArray %13
+%_ptr_UniformConstant__runtimearr_13 = OpTypePointer UniformConstant %_runtimearr_13
+%images = OpVariable %_ptr_UniformConstant__runtimearr_13 UniformConstant
+%_ptr_Input_uint = OpTypePointer Input %uint
+%var = OpVariable %_ptr_Input_uint Input
+%int_0 = OpConstant %int 0
+%_ptr_Uniform_uint = OpTypePointer Uniform %uint
+%_ptr_UniformConstant_13 = OpTypePointer UniformConstant %13
+%v2int = OpTypeVector %int 2
+%25 = OpConstantComposite %v2int %int_0 %int_0
+%v4float = OpTypeVector %float 4
+%uint_0 = OpConstant %uint 0
+%uint_1 = OpConstant %uint 1
+%_ptr_Uniform_float = OpTypePointer Uniform %float
+%gl_LocalInvocationIndex = OpVariable %_ptr_Input_uint Input
+%_ptr_Workgroup_uint = OpTypePointer Workgroup %uint
+%shared = OpVariable %_ptr_Workgroup_uint Workgroup
+
+%RayGeneration = OpFunction %void None %3
+%5 = OpLabel
+%19 = OpAccessChain %_ptr_Uniform_uint %sbo %int_0
+%20 = OpLoad %uint %var
+%22 = OpAccessChain %_ptr_UniformConstant_13 %images %20
+%23 = OpLoad %13 %22
+%27 = OpImageRead %v4float %23 %25
+%29 = OpCompositeExtract %float %27 0
+%31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1
+OpStore %31 %29
+OpReturn
+OpFunctionEnd
+
+%ClosestHit = OpFunction %void None %3
+%45 = OpLabel
+%49 = OpAccessChain %_ptr_Uniform_uint %sbo %int_0
+%40 = OpLoad %uint %var
+%42 = OpAccessChain %_ptr_UniformConstant_13 %images %40
+%43 = OpLoad %13 %42
+%47 = OpImageRead %v4float %43 %25
+%59 = OpCompositeExtract %float %47 0
+%51 = OpAccessChain %_ptr_Uniform_float %sbo %int_1
+OpStore %51 %59
+OpReturn
+OpFunctionEnd
+)";
+
+ SinglePassRunAndMatch<SpreadVolatileSemantics>(text, true);
+}
+
+class VolatileSpreadErrorTest : public PassTest<::testing::Test> {
+ public:
+ VolatileSpreadErrorTest()
+ : consumer_([this](spv_message_level_t level, const char*,
+ const spv_position_t& position, const char* message) {
+ if (!error_message_.empty()) error_message_ += "\n";
+ switch (level) {
+ case SPV_MSG_FATAL:
+ case SPV_MSG_INTERNAL_ERROR:
+ case SPV_MSG_ERROR:
+ error_message_ += "ERROR";
+ break;
+ case SPV_MSG_WARNING:
+ error_message_ += "WARNING";
+ break;
+ case SPV_MSG_INFO:
+ error_message_ += "INFO";
+ break;
+ case SPV_MSG_DEBUG:
+ error_message_ += "DEBUG";
+ break;
+ }
+ error_message_ +=
+ ": " + std::to_string(position.index) + ": " + message;
+ }) {}
+
+ Pass::Status RunPass(const std::string& text) {
+ std::unique_ptr<IRContext> context_ =
+ spvtools::BuildModule(SPV_ENV_UNIVERSAL_1_2, consumer_, text);
+ if (!context_.get()) return Pass::Status::Failure;
+
+ PassManager manager;
+ manager.SetMessageConsumer(consumer_);
+ manager.AddPass<SpreadVolatileSemantics>();
+
+ return manager.Run(context_.get());
+ }
+
+ std::string GetErrorMessage() const { return error_message_; }
+
+ void TearDown() override { error_message_.clear(); }
+
+ private:
+ spvtools::MessageConsumer consumer_;
+ std::string error_message_;
+};
+
+TEST_F(VolatileSpreadErrorTest, VarUsedInMultipleExecutionModelError) {
+ const std::string text =
+ R"(
+OpCapability RuntimeDescriptorArray
+OpCapability RayTracingKHR
+OpCapability SubgroupBallotKHR
+OpExtension "SPV_EXT_descriptor_indexing"
+OpExtension "SPV_KHR_ray_tracing"
+OpExtension "SPV_KHR_shader_ballot"
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint RayGenerationKHR %RayGeneration "RayGeneration" %var
+OpEntryPoint GLCompute %compute "Compute" %gl_LocalInvocationIndex %var
+OpExecutionMode %compute LocalSize 16 16 1
+OpSource GLSL 460
+OpSourceExtension "GL_EXT_nonuniform_qualifier"
+OpSourceExtension "GL_KHR_ray_tracing"
+OpName %RayGeneration "RayGeneration"
+OpName %StorageBuffer "StorageBuffer"
+OpMemberName %StorageBuffer 0 "index"
+OpMemberName %StorageBuffer 1 "red"
+OpName %sbo "sbo"
+OpName %images "images"
+OpMemberDecorate %StorageBuffer 0 Offset 0
+OpMemberDecorate %StorageBuffer 1 Offset 4
+OpDecorate %gl_LocalInvocationIndex BuiltIn LocalInvocationIndex
+OpDecorate %StorageBuffer BufferBlock
+OpDecorate %sbo DescriptorSet 0
+OpDecorate %sbo Binding 0
+OpDecorate %images DescriptorSet 0
+OpDecorate %images Binding 1
+OpDecorate %images NonWritable
+OpDecorate %var BuiltIn SubgroupSize
+%void = OpTypeVoid
+%3 = OpTypeFunction %void
+%uint = OpTypeInt 32 0
+%float = OpTypeFloat 32
+%StorageBuffer = OpTypeStruct %uint %float
+%_ptr_Uniform_StorageBuffer = OpTypePointer Uniform %StorageBuffer
+%sbo = OpVariable %_ptr_Uniform_StorageBuffer Uniform
+%int = OpTypeInt 32 1
+%int_1 = OpConstant %int 1
+%13 = OpTypeImage %float 2D 0 0 0 2 Rgba32f
+%_runtimearr_13 = OpTypeRuntimeArray %13
+%_ptr_UniformConstant__runtimearr_13 = OpTypePointer UniformConstant %_runtimearr_13
+%images = OpVariable %_ptr_UniformConstant__runtimearr_13 UniformConstant
+%_ptr_Input_uint = OpTypePointer Input %uint
+%var = OpVariable %_ptr_Input_uint Input
+%int_0 = OpConstant %int 0
+%_ptr_Uniform_uint = OpTypePointer Uniform %uint
+%_ptr_UniformConstant_13 = OpTypePointer UniformConstant %13
+%v2int = OpTypeVector %int 2
+%25 = OpConstantComposite %v2int %int_0 %int_0
+%v4float = OpTypeVector %float 4
+%uint_0 = OpConstant %uint 0
+%uint_1 = OpConstant %uint 1
+%_ptr_Uniform_float = OpTypePointer Uniform %float
+%gl_LocalInvocationIndex = OpVariable %_ptr_Input_uint Input
+%_ptr_Workgroup_uint = OpTypePointer Workgroup %uint
+%shared = OpVariable %_ptr_Workgroup_uint Workgroup
+
+%RayGeneration = OpFunction %void None %3
+%5 = OpLabel
+%19 = OpAccessChain %_ptr_Uniform_uint %sbo %int_0
+%20 = OpLoad %uint %var
+%22 = OpAccessChain %_ptr_UniformConstant_13 %images %20
+%23 = OpLoad %13 %22
+%27 = OpImageRead %v4float %23 %25
+%29 = OpCompositeExtract %float %27 0
+%31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1
+OpStore %31 %29
+OpReturn
+OpFunctionEnd
+
+%compute = OpFunction %void None %3
+%66 = OpLabel
+%62 = OpLoad %uint %gl_LocalInvocationIndex
+%63 = OpLoad %uint %var
+%64 = OpIAdd %uint %62 %63
+%61 = OpAtomicIAdd %uint %shared %uint_1 %uint_0 %64
+OpReturn
+OpFunctionEnd
+)";
+
+ EXPECT_EQ(RunPass(text), Pass::Status::Failure);
+ const char expected_error[] =
+ "ERROR: 0: Variable is a target for Volatile semantics for an entry "
+ "point, but it is not for another entry point";
+ EXPECT_STREQ(GetErrorMessage().substr(0, sizeof(expected_error) - 1).c_str(),
+ expected_error);
+}
+
+TEST_F(VolatileSpreadErrorTest,
+ VarUsedInMultipleReverseOrderExecutionModelError) {
+ const std::string text =
+ R"(
+OpCapability RuntimeDescriptorArray
+OpCapability RayTracingKHR
+OpCapability SubgroupBallotKHR
+OpExtension "SPV_EXT_descriptor_indexing"
+OpExtension "SPV_KHR_ray_tracing"
+OpExtension "SPV_KHR_shader_ballot"
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %compute "Compute" %gl_LocalInvocationIndex %var
+OpEntryPoint RayGenerationKHR %RayGeneration "RayGeneration" %var
+OpExecutionMode %compute LocalSize 16 16 1
+OpSource GLSL 460
+OpSourceExtension "GL_EXT_nonuniform_qualifier"
+OpSourceExtension "GL_KHR_ray_tracing"
+OpName %RayGeneration "RayGeneration"
+OpName %StorageBuffer "StorageBuffer"
+OpMemberName %StorageBuffer 0 "index"
+OpMemberName %StorageBuffer 1 "red"
+OpName %sbo "sbo"
+OpName %images "images"
+OpMemberDecorate %StorageBuffer 0 Offset 0
+OpMemberDecorate %StorageBuffer 1 Offset 4
+OpDecorate %gl_LocalInvocationIndex BuiltIn LocalInvocationIndex
+OpDecorate %StorageBuffer BufferBlock
+OpDecorate %sbo DescriptorSet 0
+OpDecorate %sbo Binding 0
+OpDecorate %images DescriptorSet 0
+OpDecorate %images Binding 1
+OpDecorate %images NonWritable
+OpDecorate %var BuiltIn SubgroupSize
+%void = OpTypeVoid
+%3 = OpTypeFunction %void
+%uint = OpTypeInt 32 0
+%float = OpTypeFloat 32
+%StorageBuffer = OpTypeStruct %uint %float
+%_ptr_Uniform_StorageBuffer = OpTypePointer Uniform %StorageBuffer
+%sbo = OpVariable %_ptr_Uniform_StorageBuffer Uniform
+%int = OpTypeInt 32 1
+%int_1 = OpConstant %int 1
+%13 = OpTypeImage %float 2D 0 0 0 2 Rgba32f
+%_runtimearr_13 = OpTypeRuntimeArray %13
+%_ptr_UniformConstant__runtimearr_13 = OpTypePointer UniformConstant %_runtimearr_13
+%images = OpVariable %_ptr_UniformConstant__runtimearr_13 UniformConstant
+%_ptr_Input_uint = OpTypePointer Input %uint
+%var = OpVariable %_ptr_Input_uint Input
+%int_0 = OpConstant %int 0
+%_ptr_Uniform_uint = OpTypePointer Uniform %uint
+%_ptr_UniformConstant_13 = OpTypePointer UniformConstant %13
+%v2int = OpTypeVector %int 2
+%25 = OpConstantComposite %v2int %int_0 %int_0
+%v4float = OpTypeVector %float 4
+%uint_0 = OpConstant %uint 0
+%uint_1 = OpConstant %uint 1
+%_ptr_Uniform_float = OpTypePointer Uniform %float
+%gl_LocalInvocationIndex = OpVariable %_ptr_Input_uint Input
+%_ptr_Workgroup_uint = OpTypePointer Workgroup %uint
+%shared = OpVariable %_ptr_Workgroup_uint Workgroup
+
+%RayGeneration = OpFunction %void None %3
+%5 = OpLabel
+%19 = OpAccessChain %_ptr_Uniform_uint %sbo %int_0
+%20 = OpLoad %uint %var
+%22 = OpAccessChain %_ptr_UniformConstant_13 %images %20
+%23 = OpLoad %13 %22
+%27 = OpImageRead %v4float %23 %25
+%29 = OpCompositeExtract %float %27 0
+%31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1
+OpStore %31 %29
+OpReturn
+OpFunctionEnd
+
+%compute = OpFunction %void None %3
+%66 = OpLabel
+%62 = OpLoad %uint %gl_LocalInvocationIndex
+%63 = OpLoad %uint %var
+%64 = OpIAdd %uint %62 %63
+%61 = OpAtomicIAdd %uint %shared %uint_1 %uint_0 %64
+OpReturn
+OpFunctionEnd
+)";
+
+ EXPECT_EQ(RunPass(text), Pass::Status::Failure);
+ const char expected_error[] =
+ "ERROR: 0: Variable is a target for Volatile semantics for an entry "
+ "point, but it is not for another entry point";
+ EXPECT_STREQ(GetErrorMessage().substr(0, sizeof(expected_error) - 1).c_str(),
+ expected_error);
+}
+
+TEST_F(VolatileSpreadErrorTest, FunctionNotInlined) {
+ const std::string text =
+ R"(
+OpCapability RuntimeDescriptorArray
+OpCapability RayTracingKHR
+OpCapability SubgroupBallotKHR
+OpExtension "SPV_EXT_descriptor_indexing"
+OpExtension "SPV_KHR_ray_tracing"
+OpExtension "SPV_KHR_shader_ballot"
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint RayGenerationKHR %RayGeneration "RayGeneration" %var
+OpEntryPoint ClosestHitKHR %ClosestHit "ClosestHit" %var
+OpSource GLSL 460
+OpSourceExtension "GL_EXT_nonuniform_qualifier"
+OpSourceExtension "GL_KHR_ray_tracing"
+OpName %RayGeneration "RayGeneration"
+OpName %ClosestHit "ClosestHit"
+OpName %StorageBuffer "StorageBuffer"
+OpMemberName %StorageBuffer 0 "index"
+OpMemberName %StorageBuffer 1 "red"
+OpName %sbo "sbo"
+OpName %images "images"
+OpMemberDecorate %StorageBuffer 0 Offset 0
+OpMemberDecorate %StorageBuffer 1 Offset 4
+OpDecorate %gl_LocalInvocationIndex BuiltIn LocalInvocationIndex
+OpDecorate %StorageBuffer BufferBlock
+OpDecorate %sbo DescriptorSet 0
+OpDecorate %sbo Binding 0
+OpDecorate %images DescriptorSet 0
+OpDecorate %images Binding 1
+OpDecorate %images NonWritable
+OpDecorate %var BuiltIn SubgroupSize
+%void = OpTypeVoid
+%3 = OpTypeFunction %void
+%uint = OpTypeInt 32 0
+%float = OpTypeFloat 32
+%StorageBuffer = OpTypeStruct %uint %float
+%_ptr_Uniform_StorageBuffer = OpTypePointer Uniform %StorageBuffer
+%sbo = OpVariable %_ptr_Uniform_StorageBuffer Uniform
+%int = OpTypeInt 32 1
+%int_1 = OpConstant %int 1
+%13 = OpTypeImage %float 2D 0 0 0 2 Rgba32f
+%_runtimearr_13 = OpTypeRuntimeArray %13
+%_ptr_UniformConstant__runtimearr_13 = OpTypePointer UniformConstant %_runtimearr_13
+%images = OpVariable %_ptr_UniformConstant__runtimearr_13 UniformConstant
+%_ptr_Input_uint = OpTypePointer Input %uint
+%var = OpVariable %_ptr_Input_uint Input
+%int_0 = OpConstant %int 0
+%_ptr_Uniform_uint = OpTypePointer Uniform %uint
+%_ptr_UniformConstant_13 = OpTypePointer UniformConstant %13
+%v2int = OpTypeVector %int 2
+%25 = OpConstantComposite %v2int %int_0 %int_0
+%v4float = OpTypeVector %float 4
+%uint_0 = OpConstant %uint 0
+%uint_1 = OpConstant %uint 1
+%_ptr_Uniform_float = OpTypePointer Uniform %float
+%gl_LocalInvocationIndex = OpVariable %_ptr_Input_uint Input
+%_ptr_Workgroup_uint = OpTypePointer Workgroup %uint
+%shared = OpVariable %_ptr_Workgroup_uint Workgroup
+
+%RayGeneration = OpFunction %void None %3
+%5 = OpLabel
+%19 = OpAccessChain %_ptr_Uniform_uint %sbo %int_0
+%20 = OpLoad %uint %19
+%22 = OpAccessChain %_ptr_UniformConstant_13 %images %20
+%23 = OpLoad %13 %22
+%27 = OpImageRead %v4float %23 %25
+%29 = OpCompositeExtract %float %27 0
+%31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1
+OpStore %31 %29
+OpReturn
+OpFunctionEnd
+
+%NotInlined = OpFunction %void None %3
+%32 = OpLabel
+OpReturn
+OpFunctionEnd
+
+%ClosestHit = OpFunction %void None %3
+%45 = OpLabel
+%49 = OpAccessChain %_ptr_Uniform_uint %sbo %int_0
+%40 = OpLoad %uint %49
+%42 = OpAccessChain %_ptr_UniformConstant_13 %images %40
+%43 = OpLoad %13 %42
+%47 = OpImageRead %v4float %43 %25
+%59 = OpCompositeExtract %float %47 0
+%51 = OpAccessChain %_ptr_Uniform_float %sbo %int_1
+OpStore %51 %59
+OpReturn
+OpFunctionEnd
+)";
+
+ EXPECT_EQ(RunPass(text), Pass::Status::Failure);
+ const char expected_error[] =
+ "ERROR: 0: Functions of SPIR-V for spread-volatile-semantics pass "
+ "input must be inlined except entry points";
+ EXPECT_STREQ(GetErrorMessage().substr(0, sizeof(expected_error) - 1).c_str(),
+ expected_error);
+}
+
+TEST_F(VolatileSpreadErrorTest, VarNotUsedInEntryPointForVolatile) {
+ const std::string text =
+ R"(
+OpCapability RuntimeDescriptorArray
+OpCapability RayTracingKHR
+OpCapability SubgroupBallotKHR
+OpExtension "SPV_EXT_descriptor_indexing"
+OpExtension "SPV_KHR_ray_tracing"
+OpExtension "SPV_KHR_shader_ballot"
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint RayGenerationKHR %RayGeneration "RayGeneration" %var
+OpEntryPoint GLCompute %compute "Compute" %gl_LocalInvocationIndex %var
+OpExecutionMode %compute LocalSize 16 16 1
+OpSource GLSL 460
+OpSourceExtension "GL_EXT_nonuniform_qualifier"
+OpSourceExtension "GL_KHR_ray_tracing"
+OpName %RayGeneration "RayGeneration"
+OpName %StorageBuffer "StorageBuffer"
+OpMemberName %StorageBuffer 0 "index"
+OpMemberName %StorageBuffer 1 "red"
+OpName %sbo "sbo"
+OpName %images "images"
+OpMemberDecorate %StorageBuffer 0 Offset 0
+OpMemberDecorate %StorageBuffer 1 Offset 4
+OpDecorate %gl_LocalInvocationIndex BuiltIn LocalInvocationIndex
+OpDecorate %StorageBuffer BufferBlock
+OpDecorate %sbo DescriptorSet 0
+OpDecorate %sbo Binding 0
+OpDecorate %images DescriptorSet 0
+OpDecorate %images Binding 1
+OpDecorate %images NonWritable
+
+; CHECK-NOT: OpDecorate {{%\w+}} Volatile
+
+OpDecorate %var BuiltIn SubgroupSize
+%void = OpTypeVoid
+%3 = OpTypeFunction %void
+%uint = OpTypeInt 32 0
+%float = OpTypeFloat 32
+%StorageBuffer = OpTypeStruct %uint %float
+%_ptr_Uniform_StorageBuffer = OpTypePointer Uniform %StorageBuffer
+%sbo = OpVariable %_ptr_Uniform_StorageBuffer Uniform
+%int = OpTypeInt 32 1
+%int_1 = OpConstant %int 1
+%13 = OpTypeImage %float 2D 0 0 0 2 Rgba32f
+%_runtimearr_13 = OpTypeRuntimeArray %13
+%_ptr_UniformConstant__runtimearr_13 = OpTypePointer UniformConstant %_runtimearr_13
+%images = OpVariable %_ptr_UniformConstant__runtimearr_13 UniformConstant
+%_ptr_Input_uint = OpTypePointer Input %uint
+%var = OpVariable %_ptr_Input_uint Input
+%int_0 = OpConstant %int 0
+%_ptr_Uniform_uint = OpTypePointer Uniform %uint
+%_ptr_UniformConstant_13 = OpTypePointer UniformConstant %13
+%v2int = OpTypeVector %int 2
+%25 = OpConstantComposite %v2int %int_0 %int_0
+%v4float = OpTypeVector %float 4
+%uint_0 = OpConstant %uint 0
+%uint_1 = OpConstant %uint 1
+%_ptr_Uniform_float = OpTypePointer Uniform %float
+%gl_LocalInvocationIndex = OpVariable %_ptr_Input_uint Input
+%_ptr_Workgroup_uint = OpTypePointer Workgroup %uint
+%shared = OpVariable %_ptr_Workgroup_uint Workgroup
+
+%RayGeneration = OpFunction %void None %3
+%5 = OpLabel
+%19 = OpAccessChain %_ptr_Uniform_uint %sbo %int_0
+%20 = OpLoad %uint %19
+%22 = OpAccessChain %_ptr_UniformConstant_13 %images %20
+%23 = OpLoad %13 %22
+%27 = OpImageRead %v4float %23 %25
+%29 = OpCompositeExtract %float %27 0
+%31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1
+OpStore %31 %29
+OpReturn
+OpFunctionEnd
+
+%compute = OpFunction %void None %3
+%66 = OpLabel
+%62 = OpLoad %uint %gl_LocalInvocationIndex
+%63 = OpLoad %uint %var
+%64 = OpIAdd %uint %62 %63
+%61 = OpAtomicIAdd %uint %shared %uint_1 %uint_0 %64
+OpReturn
+OpFunctionEnd
+)";
+
+ SinglePassRunAndMatch<SpreadVolatileSemantics>(text, true);
+}
+
+TEST_F(VolatileSpreadTest, RecursivelySpreadVolatile) {
+ const std::string text =
+ R"(
+OpCapability RuntimeDescriptorArray
+OpCapability RayTracingKHR
+OpCapability SubgroupBallotKHR
+OpCapability VulkanMemoryModel
+OpExtension "SPV_KHR_vulkan_memory_model"
+OpExtension "SPV_EXT_descriptor_indexing"
+OpExtension "SPV_KHR_ray_tracing"
+OpExtension "SPV_KHR_shader_ballot"
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical Vulkan
+OpEntryPoint RayGenerationKHR %RayGeneration "RayGeneration" %var0 %var1
+OpSource GLSL 460
+OpSourceExtension "GL_EXT_nonuniform_qualifier"
+OpSourceExtension "GL_KHR_ray_tracing"
+OpName %RayGeneration "RayGeneration"
+OpName %StorageBuffer "StorageBuffer"
+OpMemberName %StorageBuffer 0 "index"
+OpMemberName %StorageBuffer 1 "red"
+OpName %sbo "sbo"
+OpName %images "images"
+OpMemberDecorate %StorageBuffer 0 Offset 0
+OpMemberDecorate %StorageBuffer 1 Offset 4
+OpDecorate %StorageBuffer BufferBlock
+OpDecorate %sbo DescriptorSet 0
+OpDecorate %sbo Binding 0
+OpDecorate %images DescriptorSet 0
+OpDecorate %images Binding 1
+OpDecorate %images NonWritable
+
+; CHECK: OpDecorate [[var0:%\w+]] BuiltIn SubgroupEqMask
+; CHECK: OpDecorate [[var1:%\w+]] BuiltIn SubgroupGeMask
+OpDecorate %var0 BuiltIn SubgroupEqMask
+OpDecorate %var1 BuiltIn SubgroupGeMask
+
+%void = OpTypeVoid
+%3 = OpTypeFunction %void
+%uint = OpTypeInt 32 0
+%float = OpTypeFloat 32
+%StorageBuffer = OpTypeStruct %uint %float
+%_ptr_Uniform_StorageBuffer = OpTypePointer Uniform %StorageBuffer
+%sbo = OpVariable %_ptr_Uniform_StorageBuffer Uniform
+%int = OpTypeInt 32 1
+%int_1 = OpConstant %int 1
+%13 = OpTypeImage %float 2D 0 0 0 2 Rgba32f
+%_runtimearr_13 = OpTypeRuntimeArray %13
+%_ptr_UniformConstant__runtimearr_13 = OpTypePointer UniformConstant %_runtimearr_13
+%images = OpVariable %_ptr_UniformConstant__runtimearr_13 UniformConstant
+%v4uint = OpTypeVector %uint 4
+%_ptr_Input_v4uint = OpTypePointer Input %v4uint
+%_ptr_Input_uint = OpTypePointer Input %uint
+%var0 = OpVariable %_ptr_Input_v4uint Input
+%var1 = OpVariable %_ptr_Input_v4uint Input
+%int_0 = OpConstant %int 0
+%_ptr_Uniform_uint = OpTypePointer Uniform %uint
+%_ptr_UniformConstant_13 = OpTypePointer UniformConstant %13
+%v2int = OpTypeVector %int 2
+%25 = OpConstantComposite %v2int %int_0 %int_0
+%v4float = OpTypeVector %float 4
+%uint_0 = OpConstant %uint 0
+%uint_1 = OpConstant %uint 1
+%_ptr_Uniform_float = OpTypePointer Uniform %float
+
+%RayGeneration = OpFunction %void None %3
+%5 = OpLabel
+
+; CHECK: [[ptr0:%\w+]] = OpAccessChain %_ptr_Input_uint [[var0]] %int_0
+; CHECK: OpLoad {{%\w+}} [[ptr0]] Volatile
+%19 = OpAccessChain %_ptr_Input_uint %var0 %int_0
+%20 = OpLoad %uint %19
+
+%22 = OpAccessChain %_ptr_UniformConstant_13 %images %20
+%23 = OpLoad %13 %22
+%27 = OpImageRead %v4float %23 %25
+%29 = OpCompositeExtract %float %27 0
+%31 = OpAccessChain %_ptr_Uniform_float %sbo %uint_1
+
+; CHECK: OpLoad {{%\w+}} [[ptr0]] Volatile
+%24 = OpLoad %uint %19
+
+; CHECK: [[var2:%\w+]] = OpCopyObject %_ptr_Input_v4uint [[var0]]
+; CHECK: [[ptr2:%\w+]] = OpAccessChain %_ptr_Input_uint [[var2]] %int_1
+; CHECK: OpLoad {{%\w+}} [[ptr2]] Volatile
+%18 = OpCopyObject %_ptr_Input_v4uint %var0
+%21 = OpAccessChain %_ptr_Input_uint %18 %int_1
+%26 = OpLoad %uint %21
+
+%28 = OpIAdd %uint %24 %26
+%30 = OpConvertUToF %float %28
+
+; CHECK: [[ptr1:%\w+]] = OpAccessChain %_ptr_Input_uint [[var1]] %int_1
+; CHECK: OpLoad {{%\w+}} [[ptr1]] Volatile
+%32 = OpAccessChain %_ptr_Input_uint %var1 %int_1
+%33 = OpLoad %uint %32
+
+%34 = OpConvertUToF %float %33
+%35 = OpFAdd %float %34 %30
+%36 = OpFAdd %float %35 %29
+OpStore %31 %36
+OpReturn
+OpFunctionEnd
+)";
+
+ SinglePassRunAndMatch<SpreadVolatileSemantics>(text, true);
+}
+
+TEST_F(VolatileSpreadTest, SpreadVolatileOnlyForTargetEntryPoints) {
+ const std::string text =
+ R"(
+OpCapability RuntimeDescriptorArray
+OpCapability RayTracingKHR
+OpCapability SubgroupBallotKHR
+OpCapability VulkanMemoryModel
+OpCapability VulkanMemoryModelDeviceScopeKHR
+OpExtension "SPV_KHR_vulkan_memory_model"
+OpExtension "SPV_EXT_descriptor_indexing"
+OpExtension "SPV_KHR_ray_tracing"
+OpExtension "SPV_KHR_shader_ballot"
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical Vulkan
+OpEntryPoint RayGenerationKHR %RayGeneration "RayGeneration" %var0 %var1
+OpEntryPoint GLCompute %compute "Compute" %var0 %var1
+OpExecutionMode %compute LocalSize 16 16 1
+OpSource GLSL 460
+OpSourceExtension "GL_EXT_nonuniform_qualifier"
+OpSourceExtension "GL_KHR_ray_tracing"
+OpName %RayGeneration "RayGeneration"
+OpName %StorageBuffer "StorageBuffer"
+OpMemberName %StorageBuffer 0 "index"
+OpMemberName %StorageBuffer 1 "red"
+OpName %sbo "sbo"
+OpName %images "images"
+OpMemberDecorate %StorageBuffer 0 Offset 0
+OpMemberDecorate %StorageBuffer 1 Offset 4
+OpDecorate %StorageBuffer BufferBlock
+OpDecorate %sbo DescriptorSet 0
+OpDecorate %sbo Binding 0
+OpDecorate %images DescriptorSet 0
+OpDecorate %images Binding 1
+OpDecorate %images NonWritable
+
+; CHECK: OpDecorate [[var0:%\w+]] BuiltIn SubgroupEqMask
+; CHECK: OpDecorate [[var1:%\w+]] BuiltIn SubgroupGeMask
+OpDecorate %var0 BuiltIn SubgroupEqMask
+OpDecorate %var1 BuiltIn SubgroupGeMask
+
+%void = OpTypeVoid
+%3 = OpTypeFunction %void
+%uint = OpTypeInt 32 0
+%float = OpTypeFloat 32
+%StorageBuffer = OpTypeStruct %uint %float
+%_ptr_Uniform_StorageBuffer = OpTypePointer Uniform %StorageBuffer
+%sbo = OpVariable %_ptr_Uniform_StorageBuffer Uniform
+%int = OpTypeInt 32 1
+%int_1 = OpConstant %int 1
+%13 = OpTypeImage %float 2D 0 0 0 2 Rgba32f
+%_runtimearr_13 = OpTypeRuntimeArray %13
+%_ptr_UniformConstant__runtimearr_13 = OpTypePointer UniformConstant %_runtimearr_13
+%images = OpVariable %_ptr_UniformConstant__runtimearr_13 UniformConstant
+%v4uint = OpTypeVector %uint 4
+%_ptr_Input_v4uint = OpTypePointer Input %v4uint
+%_ptr_Input_uint = OpTypePointer Input %uint
+%var0 = OpVariable %_ptr_Input_v4uint Input
+%var1 = OpVariable %_ptr_Input_v4uint Input
+%int_0 = OpConstant %int 0
+%_ptr_Uniform_uint = OpTypePointer Uniform %uint
+%_ptr_UniformConstant_13 = OpTypePointer UniformConstant %13
+%v2int = OpTypeVector %int 2
+%25 = OpConstantComposite %v2int %int_0 %int_0
+%v4float = OpTypeVector %float 4
+%uint_0 = OpConstant %uint 0
+%uint_1 = OpConstant %uint 1
+%_ptr_Uniform_float = OpTypePointer Uniform %float
+%_ptr_Workgroup_uint = OpTypePointer Workgroup %uint
+%shared = OpVariable %_ptr_Workgroup_uint Workgroup
+
+%RayGeneration = OpFunction %void None %3
+%5 = OpLabel
+
+; CHECK: [[ptr0:%\w+]] = OpAccessChain %_ptr_Input_uint [[var0]] %int_0
+; CHECK: OpLoad {{%\w+}} [[ptr0]] Volatile
+%19 = OpAccessChain %_ptr_Input_uint %var0 %int_0
+%20 = OpLoad %uint %19
+
+%22 = OpAccessChain %_ptr_UniformConstant_13 %images %20
+%23 = OpLoad %13 %22
+%27 = OpImageRead %v4float %23 %25
+%29 = OpCompositeExtract %float %27 0
+%31 = OpAccessChain %_ptr_Uniform_float %sbo %uint_1
+
+; CHECK: OpLoad {{%\w+}} [[ptr0]] Volatile
+%24 = OpLoad %uint %19
+
+; CHECK: [[var2:%\w+]] = OpCopyObject %_ptr_Input_v4uint [[var0]]
+; CHECK: [[ptr2:%\w+]] = OpAccessChain %_ptr_Input_uint [[var2]] %int_1
+; CHECK: OpLoad {{%\w+}} [[ptr2]] Volatile
+%18 = OpCopyObject %_ptr_Input_v4uint %var0
+%21 = OpAccessChain %_ptr_Input_uint %18 %int_1
+%26 = OpLoad %uint %21
+
+%28 = OpIAdd %uint %24 %26
+%30 = OpConvertUToF %float %28
+
+; CHECK: [[ptr1:%\w+]] = OpAccessChain %_ptr_Input_uint [[var1]] %int_1
+; CHECK: OpLoad {{%\w+}} [[ptr1]] Volatile
+%32 = OpAccessChain %_ptr_Input_uint %var1 %int_1
+%33 = OpLoad %uint %32
+
+%34 = OpConvertUToF %float %33
+%35 = OpFAdd %float %34 %30
+%36 = OpFAdd %float %35 %29
+OpStore %31 %36
+OpReturn
+OpFunctionEnd
+
+%compute = OpFunction %void None %3
+%66 = OpLabel
+
+; CHECK-NOT: OpLoad {{%\w+}} {{%\w+}} Volatile
+%62 = OpLoad %v4uint %var0
+%63 = OpLoad %v4uint %var1
+%64 = OpIAdd %v4uint %62 %63
+%65 = OpCompositeExtract %uint %64 0
+%61 = OpAtomicIAdd %uint %shared %uint_1 %uint_0 %65
+OpReturn
+OpFunctionEnd
+)";
+
+ SinglePassRunAndMatch<SpreadVolatileSemantics>(text, true);
+}
+
+} // namespace
+} // namespace opt
+} // namespace spvtools
diff --git a/third_party/SPIRV-Tools/test/opt/strip_reflect_info_test.cpp b/third_party/SPIRV-Tools/test/opt/strip_nonsemantic_info_test.cpp
similarity index 64%
rename from third_party/SPIRV-Tools/test/opt/strip_reflect_info_test.cpp
rename to third_party/SPIRV-Tools/test/opt/strip_nonsemantic_info_test.cpp
index f3fc115..3aacffa 100644
--- a/third_party/SPIRV-Tools/test/opt/strip_reflect_info_test.cpp
+++ b/third_party/SPIRV-Tools/test/opt/strip_nonsemantic_info_test.cpp
@@ -13,10 +13,9 @@
// limitations under the License.
#include <string>
+
#include "gmock/gmock.h"
-
#include "spirv-tools/optimizer.hpp"
-
#include "test/opt/pass_fixture.h"
#include "test/opt/pass_utils.h"
@@ -24,7 +23,6 @@
namespace opt {
namespace {
-using StripLineReflectInfoTest = PassTest<::testing::Test>;
using StripNonSemanticInfoTest = PassTest<::testing::Test>;
// This test acts as an end-to-end code example on how to strip
@@ -33,7 +31,7 @@
// option -fhlsl_functionality1 to insert reflection information,
// but then want to filter out the extra instructions before sending
// it to a driver that does not implement VK_GOOGLE_hlsl_functionality1.
-TEST_F(StripLineReflectInfoTest, StripReflectEnd2EndExample) {
+TEST_F(StripNonSemanticInfoTest, StripReflectEnd2EndExample) {
// This is a non-sensical example, but exercises the instructions.
std::string before = R"(OpCapability Shader
OpCapability Linkage
@@ -49,11 +47,11 @@
std::vector<uint32_t> binary_in;
tools.Assemble(before, &binary_in);
- // Instantiate the optimizer, and run the strip-reflection-info
+ // Instantiate the optimizer, and run the strip-nonsemantic-info
// pass over the |binary_in| module, and place the modified module
// into |binary_out|.
spvtools::Optimizer optimizer(SPV_ENV_UNIVERSAL_1_1);
- optimizer.RegisterPass(spvtools::CreateStripReflectInfoPass());
+ optimizer.RegisterPass(spvtools::CreateStripNonSemanticInfoPass());
std::vector<uint32_t> binary_out;
optimizer.Run(binary_in.data(), binary_in.size(), &binary_out);
@@ -71,7 +69,7 @@
// This test is functionally the same as the end-to-end test above,
// but uses the test SinglePassRunAndCheck test fixture instead.
-TEST_F(StripLineReflectInfoTest, StripHlslSemantic) {
+TEST_F(StripNonSemanticInfoTest, StripHlslSemantic) {
// This is a non-sensical example, but exercises the instructions.
std::string before = R"(OpCapability Shader
OpCapability Linkage
@@ -90,10 +88,10 @@
%float = OpTypeFloat 32
)";
- SinglePassRunAndCheck<StripReflectInfoPass>(before, after, false);
+ SinglePassRunAndCheck<StripNonSemanticInfoPass>(before, after, false);
}
-TEST_F(StripLineReflectInfoTest, StripHlslCounterBuffer) {
+TEST_F(StripNonSemanticInfoTest, StripHlslCounterBuffer) {
std::string before = R"(OpCapability Shader
OpCapability Linkage
OpExtension "SPV_GOOGLE_hlsl_functionality1"
@@ -109,10 +107,10 @@
%float = OpTypeFloat 32
)";
- SinglePassRunAndCheck<StripReflectInfoPass>(before, after, false);
+ SinglePassRunAndCheck<StripNonSemanticInfoPass>(before, after, false);
}
-TEST_F(StripLineReflectInfoTest, StripHlslSemanticOnMember) {
+TEST_F(StripNonSemanticInfoTest, StripHlslSemanticOnMember) {
// This is a non-sensical example, but exercises the instructions.
std::string before = R"(OpCapability Shader
OpCapability Linkage
@@ -130,7 +128,7 @@
%_struct_3 = OpTypeStruct %float
)";
- SinglePassRunAndCheck<StripReflectInfoPass>(before, after, false);
+ SinglePassRunAndCheck<StripNonSemanticInfoPass>(before, after, false);
}
TEST_F(StripNonSemanticInfoTest, StripNonSemanticImport) {
@@ -144,7 +142,7 @@
OpMemoryModel Logical GLSL450
)";
- SinglePassRunAndMatch<StripReflectInfoPass>(text, true);
+ SinglePassRunAndMatch<StripNonSemanticInfoPass>(text, true);
}
TEST_F(StripNonSemanticInfoTest, StripNonSemanticGlobal) {
@@ -159,7 +157,7 @@
%1 = OpExtInst %void %ext 1
)";
- SinglePassRunAndMatch<StripReflectInfoPass>(text, true);
+ SinglePassRunAndMatch<StripNonSemanticInfoPass>(text, true);
}
TEST_F(StripNonSemanticInfoTest, StripNonSemanticInFunction) {
@@ -179,7 +177,7 @@
OpFunctionEnd
)";
- SinglePassRunAndMatch<StripReflectInfoPass>(text, true);
+ SinglePassRunAndMatch<StripNonSemanticInfoPass>(text, true);
}
TEST_F(StripNonSemanticInfoTest, StripNonSemanticAfterFunction) {
@@ -199,7 +197,7 @@
%1 = OpExtInst %void %ext 1 %foo
)";
- SinglePassRunAndMatch<StripReflectInfoPass>(text, true);
+ SinglePassRunAndMatch<StripNonSemanticInfoPass>(text, true);
}
TEST_F(StripNonSemanticInfoTest, StripNonSemanticBetweenFunctions) {
@@ -223,7 +221,74 @@
OpFunctionEnd
)";
- SinglePassRunAndMatch<StripReflectInfoPass>(text, true);
+ SinglePassRunAndMatch<StripNonSemanticInfoPass>(text, true);
+}
+
+// Make sure that strip reflect does not remove the debug info (OpString and
+// OpLine).
+TEST_F(StripNonSemanticInfoTest, DontStripDebug) {
+ std::string text = R"(OpCapability Shader
+OpMemoryModel Logical Simple
+OpEntryPoint Fragment %1 "main"
+OpExecutionMode %1 OriginUpperLeft
+%2 = OpString "file"
+%void = OpTypeVoid
+%4 = OpTypeFunction %void
+%1 = OpFunction %void None %4
+%5 = OpLabel
+OpLine %2 1 1
+OpReturn
+OpFunctionEnd
+)";
+
+ SinglePassRunAndCheck<StripNonSemanticInfoPass>(text, text, false);
+}
+
+TEST_F(StripNonSemanticInfoTest, RemovedNonSemanticDebugInfo) {
+ const std::string text = R"(
+;CHECK-NOT: OpExtension "SPV_KHR_non_semantic_info
+;CHECK-NOT: OpExtInstImport "NonSemantic.Shader.DebugInfo.100
+;CHECK-NOT: OpExtInst %void {{%\w+}} DebugSource
+;CHECK-NOT: OpExtInst %void {{%\w+}} DebugLine
+ OpCapability Shader
+ OpExtension "SPV_KHR_non_semantic_info"
+ %1 = OpExtInstImport "NonSemantic.Shader.DebugInfo.100"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %PSMain "PSMain" %in_var_COLOR %out_var_SV_TARGET
+ OpExecutionMode %PSMain OriginUpperLeft
+ %5 = OpString "t.hlsl"
+ %6 = OpString "float"
+ %7 = OpString "color"
+ %8 = OpString "PSInput"
+ %9 = OpString "PSMain"
+ %10 = OpString ""
+ %11 = OpString "input"
+ OpName %in_var_COLOR "in.var.COLOR"
+ OpName %out_var_SV_TARGET "out.var.SV_TARGET"
+ OpName %PSMain "PSMain"
+ OpDecorate %in_var_COLOR Location 0
+ OpDecorate %out_var_SV_TARGET Location 0
+ %uint = OpTypeInt 32 0
+ %float = OpTypeFloat 32
+ %v4float = OpTypeVector %float 4
+%_ptr_Input_v4float = OpTypePointer Input %v4float
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+ %void = OpTypeVoid
+ %uint_1 = OpConstant %uint 1
+ %uint_9 = OpConstant %uint 9
+ %21 = OpTypeFunction %void
+%in_var_COLOR = OpVariable %_ptr_Input_v4float Input
+%out_var_SV_TARGET = OpVariable %_ptr_Output_v4float Output
+ %13 = OpExtInst %void %1 DebugSource %5
+ %PSMain = OpFunction %void None %21
+ %22 = OpLabel
+ %23 = OpLoad %v4float %in_var_COLOR
+ OpStore %out_var_SV_TARGET %23
+ %24 = OpExtInst %void %1 DebugLine %13 %uint_9 %uint_9 %uint_1 %uint_1
+ OpReturn
+ OpFunctionEnd
+)";
+ SinglePassRunAndMatch<StripNonSemanticInfoPass>(text, true);
}
} // namespace
diff --git a/third_party/SPIRV-Tools/test/opt/type_manager_test.cpp b/third_party/SPIRV-Tools/test/opt/type_manager_test.cpp
index fdae2ef..df216bc 100644
--- a/third_party/SPIRV-Tools/test/opt/type_manager_test.cpp
+++ b/third_party/SPIRV-Tools/test/opt/type_manager_test.cpp
@@ -167,10 +167,25 @@
types.emplace_back(new NamedBarrier());
types.emplace_back(new AccelerationStructureNV());
types.emplace_back(new CooperativeMatrixNV(f32, 24, 24, 24));
+ types.emplace_back(new RayQueryKHR());
return types;
}
+TEST(TypeManager, GenerateAllTypesGeneratesAllTypes) {
+ std::set<Type::Kind> generated_types;
+ for (auto& type : GenerateAllTypes()) {
+ generated_types.insert(type->kind());
+ }
+
+ std::vector<Type::Kind> all_types;
+ for (uint32_t kind = 0; kind != Type::Kind::kLast; ++kind) {
+ all_types.push_back(static_cast<Type::Kind>(kind));
+ }
+
+ EXPECT_THAT(generated_types, testing::UnorderedElementsAreArray(all_types));
+}
+
TEST(TypeManager, TypeStrings) {
const std::string text = R"(
OpDecorate %spec_const_with_id SpecId 99
@@ -1065,6 +1080,7 @@
; CHECK: OpTypeNamedBarrier
; CHECK: OpTypeAccelerationStructureKHR
; CHECK: OpTypeCooperativeMatrixNV [[f32]] [[uint24]] [[uint24]] [[uint24]]
+; CHECK: OpTypeRayQueryKHR
OpCapability Shader
OpCapability Int64
OpCapability Linkage
diff --git a/third_party/SPIRV-Tools/test/opt/unify_const_test.cpp b/third_party/SPIRV-Tools/test/opt/unify_const_test.cpp
index 6ed2173..0d7c30b 100644
--- a/third_party/SPIRV-Tools/test/opt/unify_const_test.cpp
+++ b/third_party/SPIRV-Tools/test/opt/unify_const_test.cpp
@@ -263,7 +263,7 @@
// decorated flat struct
"%flat_d = OpTypeStruct %int %float",
"%_pf_flat_d = OpTypePointer Function %flat_d",
- // perserved contants. %flat_1 and %flat_d has same members, but
+ // preserved constants. %flat_1 and %flat_d has same members, but
// their type are different in decorations, so they should not be
// used to replace each other.
"%int_1 = OpConstant %int 1",
@@ -682,7 +682,7 @@
// zero-valued composite constant built from zero-valued constant
// component. inner_zero should not be replace by null_inner.
"%inner_zero = OpConstantComposite %inner_struct %bool_zero %float_zero",
- // zero-valued composite contant built from zero-valued constants
+ // zero-valued composite constant built from zero-valued constants
// and null constants.
"%outer_zero = OpConstantComposite %outer_struct %inner_zero %int_null %double_null",
// outer_struct type null constant, it should not be replaced by
@@ -820,7 +820,7 @@
{
"%spec_signed_add_duplicate = OpSpecConstantOp %int IAdd %spec_signed_1 %spec_signed_2",
},
- // use duplicated contants in main
+ // use duplicated constants in main
{
"%int_var = OpVariable %_pf_int Function",
"OpStore %int_var %spec_signed_add_duplicate",
diff --git a/third_party/SPIRV-Tools/test/target_env_test.cpp b/third_party/SPIRV-Tools/test/target_env_test.cpp
index 4acb8ff..7917cbf 100644
--- a/third_party/SPIRV-Tools/test/target_env_test.cpp
+++ b/third_party/SPIRV-Tools/test/target_env_test.cpp
@@ -135,7 +135,8 @@
{VK(1, 0), SPV(1, 3), true, SPV_ENV_VULKAN_1_1},
{VK(1, 0), SPV(1, 4), true, SPV_ENV_VULKAN_1_1_SPIRV_1_4},
{VK(1, 0), SPV(1, 5), true, SPV_ENV_VULKAN_1_2},
- {VK(1, 0), SPV(1, 6), false, SPV_ENV_UNIVERSAL_1_0},
+ {VK(1, 0), SPV(1, 6), true, SPV_ENV_VULKAN_1_3},
+ {VK(1, 0), SPV(1, 7), false, SPV_ENV_UNIVERSAL_1_0},
// Vulkan 1.1 cases
{VK(1, 1), SPV(1, 0), true, SPV_ENV_VULKAN_1_1},
{VK(1, 1), SPV(1, 1), true, SPV_ENV_VULKAN_1_1},
@@ -143,7 +144,8 @@
{VK(1, 1), SPV(1, 3), true, SPV_ENV_VULKAN_1_1},
{VK(1, 1), SPV(1, 4), true, SPV_ENV_VULKAN_1_1_SPIRV_1_4},
{VK(1, 1), SPV(1, 5), true, SPV_ENV_VULKAN_1_2},
- {VK(1, 1), SPV(1, 6), false, SPV_ENV_UNIVERSAL_1_0},
+ {VK(1, 1), SPV(1, 6), true, SPV_ENV_VULKAN_1_3},
+ {VK(1, 1), SPV(1, 7), false, SPV_ENV_UNIVERSAL_1_0},
// Vulkan 1.2 cases
{VK(1, 2), SPV(1, 0), true, SPV_ENV_VULKAN_1_2},
{VK(1, 2), SPV(1, 1), true, SPV_ENV_VULKAN_1_2},
@@ -151,9 +153,17 @@
{VK(1, 2), SPV(1, 3), true, SPV_ENV_VULKAN_1_2},
{VK(1, 2), SPV(1, 4), true, SPV_ENV_VULKAN_1_2},
{VK(1, 2), SPV(1, 5), true, SPV_ENV_VULKAN_1_2},
- {VK(1, 2), SPV(1, 6), false, SPV_ENV_UNIVERSAL_1_0},
+ {VK(1, 2), SPV(1, 6), true, SPV_ENV_VULKAN_1_3},
+ {VK(1, 2), SPV(1, 7), false, SPV_ENV_UNIVERSAL_1_0},
// Vulkan 1.3 cases
- {VK(1, 3), SPV(1, 0), false, SPV_ENV_UNIVERSAL_1_0},
+ {VK(1, 3), SPV(1, 0), true, SPV_ENV_VULKAN_1_3},
+ {VK(1, 3), SPV(1, 1), true, SPV_ENV_VULKAN_1_3},
+ {VK(1, 3), SPV(1, 2), true, SPV_ENV_VULKAN_1_3},
+ {VK(1, 3), SPV(1, 3), true, SPV_ENV_VULKAN_1_3},
+ {VK(1, 3), SPV(1, 4), true, SPV_ENV_VULKAN_1_3},
+ {VK(1, 3), SPV(1, 5), true, SPV_ENV_VULKAN_1_3},
+ {VK(1, 3), SPV(1, 6), true, SPV_ENV_VULKAN_1_3},
+ {VK(1, 3), SPV(1, 7), false, SPV_ENV_UNIVERSAL_1_0},
// Vulkan 2.0 cases
{VK(2, 0), SPV(1, 0), false, SPV_ENV_UNIVERSAL_1_0},
// Vulkan 99.0 cases
diff --git a/third_party/SPIRV-Tools/test/test_fixture.h b/third_party/SPIRV-Tools/test/test_fixture.h
index 0c5bfc9..029fc85 100644
--- a/third_party/SPIRV-Tools/test/test_fixture.h
+++ b/third_party/SPIRV-Tools/test/test_fixture.h
@@ -15,6 +15,7 @@
#ifndef TEST_TEST_FIXTURE_H_
#define TEST_TEST_FIXTURE_H_
+#include <algorithm>
#include <string>
#include <vector>
@@ -91,12 +92,26 @@
return diagnostic->error;
}
+ // Potentially flip the words in the binary representation to the other
+ // endianness
+ template <class It>
+ void MaybeFlipWords(bool flip_words, It begin, It end) {
+ SCOPED_TRACE(flip_words ? "Flipped Endianness" : "Normal Endianness");
+ if (flip_words) {
+ std::transform(begin, end, begin, [](const uint32_t raw_word) {
+ return spvFixWord(raw_word, I32_ENDIAN_HOST == I32_ENDIAN_BIG
+ ? SPV_ENDIANNESS_LITTLE
+ : SPV_ENDIANNESS_BIG);
+ });
+ }
+ }
+
// Encodes SPIR-V text into binary and then decodes the binary using
// given options. Returns the decoded text.
std::string EncodeAndDecodeSuccessfully(
const std::string& txt,
uint32_t disassemble_options = SPV_BINARY_TO_TEXT_OPTION_NONE,
- spv_target_env env = SPV_ENV_UNIVERSAL_1_0) {
+ spv_target_env env = SPV_ENV_UNIVERSAL_1_0, bool flip_words = false) {
DestroyBinary();
DestroyDiagnostic();
ScopedContext context(env);
@@ -110,6 +125,8 @@
EXPECT_EQ(SPV_SUCCESS, error);
if (!binary) return "";
+ MaybeFlipWords(flip_words, binary->code, binary->code + binary->wordCount);
+
spv_text decoded_text;
error = spvBinaryToText(context.context, binary->code, binary->wordCount,
disassemble_options, &decoded_text, &diagnostic);
diff --git a/third_party/SPIRV-Tools/test/text_to_binary.control_flow_test.cpp b/third_party/SPIRV-Tools/test/text_to_binary.control_flow_test.cpp
index 3e117b8..abae6a2 100644
--- a/third_party/SPIRV-Tools/test/text_to_binary.control_flow_test.cpp
+++ b/third_party/SPIRV-Tools/test/text_to_binary.control_flow_test.cpp
@@ -379,7 +379,7 @@
"OpTypeQueue",
"OpTypePipe ReadOnly",
- // Skip OpTypeForwardPointer becasuse it doesn't even produce a result
+ // Skip OpTypeForwardPointer because it doesn't even produce a result
// ID.
// At least one thing that isn't a type at all
diff --git a/third_party/SPIRV-Tools/test/text_to_binary.extension_test.cpp b/third_party/SPIRV-Tools/test/text_to_binary.extension_test.cpp
index 1324206..e5f152e 100644
--- a/third_party/SPIRV-Tools/test/text_to_binary.extension_test.cpp
+++ b/third_party/SPIRV-Tools/test/text_to_binary.extension_test.cpp
@@ -197,7 +197,7 @@
SpvBuiltInSubgroupLtMask})},
})));
-// The old builtin names (with KHR suffix) still work in the assmebler, and
+// The old builtin names (with KHR suffix) still work in the assembler, and
// map to the enums without the KHR.
INSTANTIATE_TEST_SUITE_P(
SPV_KHR_shader_ballot_vulkan_1_1_alias_check, ExtensionAssemblyTest,
@@ -957,61 +957,62 @@
INSTANTIATE_TEST_SUITE_P(
SPV_KHR_integer_dot_product, ExtensionRoundTripTest,
Combine(
- Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_5, SPV_ENV_VULKAN_1_0,
- SPV_ENV_VULKAN_1_1, SPV_ENV_VULKAN_1_2),
+ Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_5,
+ SPV_ENV_UNIVERSAL_1_6, SPV_ENV_VULKAN_1_0, SPV_ENV_VULKAN_1_1,
+ SPV_ENV_VULKAN_1_2, SPV_ENV_VULKAN_1_3),
ValuesIn(std::vector<AssemblyCase>{
{"OpExtension \"SPV_KHR_integer_dot_product\"\n",
MakeInstruction(SpvOpExtension,
MakeVector("SPV_KHR_integer_dot_product"))},
- {"OpCapability DotProductInputAllKHR\n",
+ {"OpCapability DotProductInputAll\n",
MakeInstruction(SpvOpCapability,
{SpvCapabilityDotProductInputAllKHR})},
- {"OpCapability DotProductInput4x8BitKHR\n",
+ {"OpCapability DotProductInput4x8Bit\n",
MakeInstruction(SpvOpCapability,
{SpvCapabilityDotProductInput4x8BitKHR})},
- {"OpCapability DotProductInput4x8BitPackedKHR\n",
+ {"OpCapability DotProductInput4x8BitPacked\n",
MakeInstruction(SpvOpCapability,
{SpvCapabilityDotProductInput4x8BitPackedKHR})},
- {"OpCapability DotProductKHR\n",
+ {"OpCapability DotProduct\n",
MakeInstruction(SpvOpCapability, {SpvCapabilityDotProductKHR})},
- {"%2 = OpSDotKHR %1 %3 %4\n",
+ {"%2 = OpSDot %1 %3 %4\n",
MakeInstruction(SpvOpSDotKHR, {1, 2, 3, 4})},
- {"%2 = OpSDotKHR %1 %3 %4 PackedVectorFormat4x8BitKHR\n",
+ {"%2 = OpSDot %1 %3 %4 PackedVectorFormat4x8Bit\n",
MakeInstruction(
SpvOpSDotKHR,
{1, 2, 3, 4,
SpvPackedVectorFormatPackedVectorFormat4x8BitKHR})},
- {"%2 = OpUDotKHR %1 %3 %4\n",
+ {"%2 = OpUDot %1 %3 %4\n",
MakeInstruction(SpvOpUDotKHR, {1, 2, 3, 4})},
- {"%2 = OpUDotKHR %1 %3 %4 PackedVectorFormat4x8BitKHR\n",
+ {"%2 = OpUDot %1 %3 %4 PackedVectorFormat4x8Bit\n",
MakeInstruction(
SpvOpUDotKHR,
{1, 2, 3, 4,
SpvPackedVectorFormatPackedVectorFormat4x8BitKHR})},
- {"%2 = OpSUDotKHR %1 %3 %4\n",
+ {"%2 = OpSUDot %1 %3 %4\n",
MakeInstruction(SpvOpSUDotKHR, {1, 2, 3, 4})},
- {"%2 = OpSUDotKHR %1 %3 %4 PackedVectorFormat4x8BitKHR\n",
+ {"%2 = OpSUDot %1 %3 %4 PackedVectorFormat4x8Bit\n",
MakeInstruction(
SpvOpSUDotKHR,
{1, 2, 3, 4,
SpvPackedVectorFormatPackedVectorFormat4x8BitKHR})},
- {"%2 = OpSDotAccSatKHR %1 %3 %4 %5\n",
+ {"%2 = OpSDotAccSat %1 %3 %4 %5\n",
MakeInstruction(SpvOpSDotAccSatKHR, {1, 2, 3, 4, 5})},
- {"%2 = OpSDotAccSatKHR %1 %3 %4 %5 PackedVectorFormat4x8BitKHR\n",
+ {"%2 = OpSDotAccSat %1 %3 %4 %5 PackedVectorFormat4x8Bit\n",
MakeInstruction(
SpvOpSDotAccSatKHR,
{1, 2, 3, 4, 5,
SpvPackedVectorFormatPackedVectorFormat4x8BitKHR})},
- {"%2 = OpUDotAccSatKHR %1 %3 %4 %5\n",
+ {"%2 = OpUDotAccSat %1 %3 %4 %5\n",
MakeInstruction(SpvOpUDotAccSatKHR, {1, 2, 3, 4, 5})},
- {"%2 = OpUDotAccSatKHR %1 %3 %4 %5 PackedVectorFormat4x8BitKHR\n",
+ {"%2 = OpUDotAccSat %1 %3 %4 %5 PackedVectorFormat4x8Bit\n",
MakeInstruction(
SpvOpUDotAccSatKHR,
{1, 2, 3, 4, 5,
SpvPackedVectorFormatPackedVectorFormat4x8BitKHR})},
- {"%2 = OpSUDotAccSatKHR %1 %3 %4 %5\n",
+ {"%2 = OpSUDotAccSat %1 %3 %4 %5\n",
MakeInstruction(SpvOpSUDotAccSatKHR, {1, 2, 3, 4, 5})},
- {"%2 = OpSUDotAccSatKHR %1 %3 %4 %5 PackedVectorFormat4x8BitKHR\n",
+ {"%2 = OpSUDotAccSat %1 %3 %4 %5 PackedVectorFormat4x8Bit\n",
MakeInstruction(
SpvOpSUDotAccSatKHR,
{1, 2, 3, 4, 5,
diff --git a/third_party/SPIRV-Tools/test/text_to_binary_test.cpp b/third_party/SPIRV-Tools/test/text_to_binary_test.cpp
index 99d9ed6..0b348e8 100644
--- a/third_party/SPIRV-Tools/test/text_to_binary_test.cpp
+++ b/third_party/SPIRV-Tools/test/text_to_binary_test.cpp
@@ -65,7 +65,7 @@
{SPV_OPERAND_TYPE_FP_FAST_MATH_MODE, 1, "NotNaN"},
{SPV_OPERAND_TYPE_FP_FAST_MATH_MODE, 2, "NotInf"},
{SPV_OPERAND_TYPE_FP_FAST_MATH_MODE, 3, "NotNaN|NotInf"},
- // Mask experssions are symmetric.
+ // Mask expressions are symmetric.
{SPV_OPERAND_TYPE_FP_FAST_MATH_MODE, 3, "NotInf|NotNaN"},
// Repeating a value has no effect.
{SPV_OPERAND_TYPE_FP_FAST_MATH_MODE, 3, "NotInf|NotNaN|NotInf"},
diff --git a/third_party/SPIRV-Tools/test/tools/expect.py b/third_party/SPIRV-Tools/test/tools/expect.py
index 0b51adc..7351c02 100755
--- a/third_party/SPIRV-Tools/test/tools/expect.py
+++ b/third_party/SPIRV-Tools/test/tools/expect.py
@@ -285,6 +285,21 @@
return True, ''
+class ValidObjectFile1_6(ReturnCodeIsZero, CorrectObjectFilePreamble):
+ """Mixin class for checking that every input file generates a valid SPIR-V 1.6
+ object file following the object file naming rule, and there is no output on
+ stdout/stderr."""
+
+ def check_object_file_preamble(self, status):
+ for input_filename in status.input_filenames:
+ object_filename = get_object_filename(input_filename)
+ success, message = self.verify_object_file_preamble(
+ os.path.join(status.directory, object_filename), 0x10600)
+ if not success:
+ return False, message
+ return True, ''
+
+
class ValidObjectFileWithAssemblySubstr(SuccessfulReturn,
CorrectObjectFilePreamble):
"""Mixin class for checking that every input file generates a valid object
diff --git a/third_party/SPIRV-Tools/test/tools/opt/flags.py b/third_party/SPIRV-Tools/test/tools/opt/flags.py
index c79f680..52a43c5 100644
--- a/third_party/SPIRV-Tools/test/tools/opt/flags.py
+++ b/third_party/SPIRV-Tools/test/tools/opt/flags.py
@@ -34,7 +34,7 @@
@inside_spirv_testsuite('SpirvOptBase')
-class TestAssemblyFileAsOnlyParameter(expect.ValidObjectFile1_5):
+class TestAssemblyFileAsOnlyParameter(expect.ValidObjectFile1_6):
"""Tests that spirv-opt accepts a SPIR-V object file."""
shader = placeholder.FileSPIRVShader(empty_main_assembly(), '.spvasm')
@@ -52,7 +52,7 @@
@inside_spirv_testsuite('SpirvOptFlags')
-class TestValidPassFlags(expect.ValidObjectFile1_5,
+class TestValidPassFlags(expect.ValidObjectFile1_6,
expect.ExecutedListOfPasses):
"""Tests that spirv-opt accepts all valid optimization flags."""
@@ -72,7 +72,7 @@
'--private-to-local', '--reduce-load-size', '--redundancy-elimination',
'--remove-duplicates', '--replace-invalid-opcode', '--ssa-rewrite',
'--scalar-replacement', '--scalar-replacement=42', '--strength-reduction',
- '--strip-debug', '--strip-reflect', '--vector-dce', '--workaround-1209',
+ '--strip-debug', '--strip-nonsemantic', '--vector-dce', '--workaround-1209',
'--unify-const', '--graphics-robust-access', '--wrap-opkill', '--amd-ext-to-khr'
]
expected_passes = [
@@ -117,7 +117,7 @@
'scalar-replacement=42',
'strength-reduction',
'strip-debug',
- 'strip-reflect',
+ 'strip-nonsemantic',
'vector-dce',
'workaround-1209',
'unify-const',
@@ -132,7 +132,7 @@
@inside_spirv_testsuite('SpirvOptFlags')
-class TestPerformanceOptimizationPasses(expect.ValidObjectFile1_5,
+class TestPerformanceOptimizationPasses(expect.ValidObjectFile1_6,
expect.ExecutedListOfPasses):
"""Tests that spirv-opt schedules all the passes triggered by -O."""
@@ -190,7 +190,7 @@
@inside_spirv_testsuite('SpirvOptFlags')
-class TestSizeOptimizationPasses(expect.ValidObjectFile1_5,
+class TestSizeOptimizationPasses(expect.ValidObjectFile1_6,
expect.ExecutedListOfPasses):
"""Tests that spirv-opt schedules all the passes triggered by -Os."""
@@ -237,7 +237,7 @@
@inside_spirv_testsuite('SpirvOptFlags')
-class TestLegalizationPasses(expect.ValidObjectFile1_5,
+class TestLegalizationPasses(expect.ValidObjectFile1_6,
expect.ExecutedListOfPasses):
"""Tests that spirv-opt schedules all the passes triggered by --legalize-hlsl.
"""
diff --git a/third_party/SPIRV-Tools/test/util/CMakeLists.txt b/third_party/SPIRV-Tools/test/util/CMakeLists.txt
index 6679dba..6808783 100644
--- a/third_party/SPIRV-Tools/test/util/CMakeLists.txt
+++ b/third_party/SPIRV-Tools/test/util/CMakeLists.txt
@@ -16,6 +16,8 @@
SRCS ilist_test.cpp
bit_vector_test.cpp
bitutils_test.cpp
+ hash_combine_test.cpp
+ pooled_linked_list_test.cpp
small_vector_test.cpp
LIBS SPIRV-Tools-opt
)
diff --git a/third_party/SPIRV-Tools/test/util/hash_combine_test.cpp b/third_party/SPIRV-Tools/test/util/hash_combine_test.cpp
new file mode 100644
index 0000000..9cd1d87
--- /dev/null
+++ b/third_party/SPIRV-Tools/test/util/hash_combine_test.cpp
@@ -0,0 +1,43 @@
+// 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.
+
+#include <utility>
+#include <vector>
+
+#include "gmock/gmock.h"
+#include "source/util/hash_combine.h"
+
+namespace spvtools {
+namespace utils {
+namespace {
+
+using HashCombineTest = ::testing::Test;
+
+TEST(HashCombineTest, Identity) { EXPECT_EQ(hash_combine(0), 0); }
+
+TEST(HashCombineTest, Variadic) {
+ // Expect manual and variadic template versions be the same.
+ EXPECT_EQ(hash_combine(hash_combine(hash_combine(0, 1), 2), 3),
+ hash_combine(0, 1, 2, 3));
+}
+
+TEST(HashCombineTest, Vector) {
+ // Expect variadic and vector versions be the same.
+ EXPECT_EQ(hash_combine(0, std::vector<uint32_t>({1, 2, 3})),
+ hash_combine(0, 1, 2, 3));
+}
+
+} // namespace
+} // namespace utils
+} // namespace spvtools
diff --git a/third_party/SPIRV-Tools/test/util/pooled_linked_list_test.cpp b/third_party/SPIRV-Tools/test/util/pooled_linked_list_test.cpp
new file mode 100644
index 0000000..82fb4ac
--- /dev/null
+++ b/third_party/SPIRV-Tools/test/util/pooled_linked_list_test.cpp
@@ -0,0 +1,185 @@
+// Copyright (c) 2021 The Khronos Group Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <algorithm>
+#include <list>
+#include <utility>
+#include <vector>
+
+#include "gmock/gmock.h"
+#include "source/util/pooled_linked_list.h"
+
+namespace spvtools {
+namespace utils {
+namespace {
+
+using PooledLinkedListTest = ::testing::Test;
+
+template <typename T>
+static std::vector<T> ToVector(const PooledLinkedList<T>& list) {
+ std::vector<T> vec;
+ for (auto it = list.begin(); it != list.end(); ++it) {
+ vec.push_back(*it);
+ }
+ return vec;
+}
+
+template <typename T>
+static void AppendVector(PooledLinkedList<T>& list, const std::vector<T>& vec) {
+ for (const T& t : vec) {
+ list.push_back(t);
+ }
+}
+
+TEST(PooledLinkedListTest, Empty) {
+ PooledLinkedListNodes<uint32_t> pool;
+ PooledLinkedList<uint32_t> ll(&pool);
+ EXPECT_TRUE(ll.empty());
+
+ ll.push_back(1u);
+ EXPECT_TRUE(!ll.empty());
+}
+
+TEST(PooledLinkedListTest, Iterator) {
+ PooledLinkedListNodes<uint32_t> pool;
+ PooledLinkedList<uint32_t> ll(&pool);
+
+ EXPECT_EQ(ll.begin(), ll.end());
+
+ ll.push_back(1);
+ EXPECT_NE(ll.begin(), ll.end());
+
+ auto it = ll.begin();
+ EXPECT_EQ(*it, 1);
+ ++it;
+ EXPECT_EQ(it, ll.end());
+}
+
+TEST(PooledLinkedListTest, Iterator_algorithms) {
+ PooledLinkedListNodes<uint32_t> pool;
+ PooledLinkedList<uint32_t> ll(&pool);
+
+ AppendVector(ll, {3, 2, 0, 1});
+ EXPECT_EQ(std::distance(ll.begin(), ll.end()), 4);
+ EXPECT_EQ(*std::min_element(ll.begin(), ll.end()), 0);
+ EXPECT_EQ(*std::max_element(ll.begin(), ll.end()), 3);
+}
+
+TEST(PooledLinkedListTest, FrontBack) {
+ PooledLinkedListNodes<uint32_t> pool;
+ PooledLinkedList<uint32_t> ll(&pool);
+
+ ll.push_back(1);
+ EXPECT_EQ(ll.front(), 1);
+ EXPECT_EQ(ll.back(), 1);
+
+ ll.push_back(2);
+ EXPECT_EQ(ll.front(), 1);
+ EXPECT_EQ(ll.back(), 2);
+}
+
+TEST(PooledLinkedListTest, PushBack) {
+ const std::vector<uint32_t> vec = {1, 2, 3, 4, 5, 6};
+
+ PooledLinkedListNodes<uint32_t> pool;
+ PooledLinkedList<uint32_t> ll(&pool);
+
+ AppendVector(ll, vec);
+ EXPECT_EQ(vec, ToVector(ll));
+}
+
+TEST(PooledLinkedListTest, RemoveFirst) {
+ const std::vector<uint32_t> vec = {1, 2, 3, 4, 5, 6};
+
+ PooledLinkedListNodes<uint32_t> pool;
+ PooledLinkedList<uint32_t> ll(&pool);
+
+ EXPECT_FALSE(ll.remove_first(0));
+ AppendVector(ll, vec);
+ EXPECT_FALSE(ll.remove_first(0));
+
+ std::vector<uint32_t> tmp = vec;
+ while (!tmp.empty()) {
+ size_t mid = tmp.size() / 2;
+ uint32_t elt = tmp[mid];
+ tmp.erase(tmp.begin() + mid);
+
+ EXPECT_TRUE(ll.remove_first(elt));
+ EXPECT_FALSE(ll.remove_first(elt));
+ EXPECT_EQ(tmp, ToVector(ll));
+ }
+ EXPECT_TRUE(ll.empty());
+}
+
+TEST(PooledLinkedListTest, RemoveFirst_Duplicates) {
+ const std::vector<uint32_t> vec = {3, 1, 2, 3, 3, 3, 3, 4, 3, 5, 3, 6, 3};
+
+ PooledLinkedListNodes<uint32_t> pool;
+ PooledLinkedList<uint32_t> ll(&pool);
+ AppendVector(ll, vec);
+
+ std::vector<uint32_t> tmp = vec;
+ while (!tmp.empty()) {
+ size_t mid = tmp.size() / 2;
+ uint32_t elt = tmp[mid];
+ tmp.erase(std::find(tmp.begin(), tmp.end(), elt));
+
+ EXPECT_TRUE(ll.remove_first(elt));
+ EXPECT_EQ(tmp, ToVector(ll));
+ }
+ EXPECT_TRUE(ll.empty());
+}
+
+TEST(PooledLinkedList, MoveTo) {
+ const std::vector<uint32_t> vec = {1, 2, 3, 4, 5, 6};
+
+ PooledLinkedListNodes<uint32_t> pool;
+ PooledLinkedList<uint32_t> ll1(&pool);
+ PooledLinkedList<uint32_t> ll2(&pool);
+ PooledLinkedList<uint32_t> ll3(&pool);
+
+ AppendVector(ll1, vec);
+ AppendVector(ll2, vec);
+ AppendVector(ll3, vec);
+ EXPECT_EQ(pool.total_nodes(), vec.size() * 3);
+ EXPECT_EQ(pool.total_nodes(), vec.size() * 3);
+ EXPECT_EQ(pool.free_nodes(), 0);
+
+ // Move two lists to the new pool
+ PooledLinkedListNodes<uint32_t> pool_new;
+ ll1.move_nodes(&pool_new);
+ ll2.move_nodes(&pool_new);
+
+ // Moved nodes should belong to new pool
+ EXPECT_EQ(ll1.pool(), &pool_new);
+ EXPECT_EQ(ll2.pool(), &pool_new);
+
+ // Old pool should be smaller & have free nodes.
+ EXPECT_EQ(pool.used_nodes(), vec.size());
+ EXPECT_EQ(pool.free_nodes(), vec.size() * 2);
+
+ // New pool should be sized exactly and no free nodes.
+ EXPECT_EQ(pool_new.total_nodes(), vec.size() * 2);
+ EXPECT_EQ(pool_new.used_nodes(), vec.size() * 2);
+ EXPECT_EQ(pool_new.free_nodes(), 0);
+
+ // All lists should be preserved
+ EXPECT_EQ(ToVector(ll1), vec);
+ EXPECT_EQ(ToVector(ll2), vec);
+ EXPECT_EQ(ToVector(ll3), vec);
+}
+
+} // namespace
+} // namespace utils
+} // namespace spvtools
diff --git a/third_party/SPIRV-Tools/test/util/small_vector_test.cpp b/third_party/SPIRV-Tools/test/util/small_vector_test.cpp
index 01d7df1..b8f068e 100644
--- a/third_party/SPIRV-Tools/test/util/small_vector_test.cpp
+++ b/third_party/SPIRV-Tools/test/util/small_vector_test.cpp
@@ -56,6 +56,18 @@
}
}
+TEST(SmallVectorTest, Initialize_list3) {
+ std::vector<uint32_t> result = {0, 1, 2, 3};
+ SmallVector<uint32_t, 6> vec(result.begin(), result.end());
+
+ EXPECT_FALSE(vec.empty());
+ EXPECT_EQ(vec.size(), 4);
+
+ for (uint32_t i = 0; i < vec.size(); ++i) {
+ EXPECT_EQ(vec[i], result[i]);
+ }
+}
+
TEST(SmallVectorTest, Initialize_copy1) {
SmallVector<uint32_t, 6> vec1 = {0, 1, 2, 3};
SmallVector<uint32_t, 6> vec2(vec1);
@@ -593,6 +605,68 @@
EXPECT_EQ(vec, result);
}
+TEST(SmallVectorTest, Pop_back) {
+ SmallVector<uint32_t, 8> vec = {0, 1, 2, 10, 10, 10};
+ SmallVector<uint32_t, 8> result = {0, 1, 2};
+
+ EXPECT_EQ(vec.size(), 6);
+ vec.pop_back();
+ vec.pop_back();
+ vec.pop_back();
+ EXPECT_EQ(vec.size(), 3);
+ EXPECT_EQ(vec, result);
+}
+
+TEST(SmallVectorTest, Pop_back_TestDestructor) {
+ // Tracks number of constructions and destructions to ensure they are called.
+ struct TracksDtor {
+ TracksDtor& operator=(TracksDtor&&) = delete;
+ TracksDtor& operator=(const TracksDtor&) = delete;
+
+ TracksDtor(int& num_ctors, int& num_dtors)
+ : num_ctors_(num_ctors), num_dtors_(num_dtors) {
+ num_ctors_++;
+ }
+ TracksDtor(const TracksDtor& that)
+ : TracksDtor(that.num_ctors_, that.num_dtors_) {}
+ TracksDtor(TracksDtor&& that)
+ : TracksDtor(that.num_ctors_, that.num_dtors_) {}
+ ~TracksDtor() { num_dtors_++; }
+
+ int& num_ctors_;
+ int& num_dtors_;
+ };
+
+ constexpr int capacity = 4;
+ SmallVector<TracksDtor, capacity> vec;
+
+ int num_ctors = 0;
+ int num_dtors = 0;
+
+ // Make sure it works when staying within the smallvector capacity
+ for (int i = 0; i < capacity; ++i) {
+ vec.emplace_back(num_ctors, num_dtors);
+ }
+
+ EXPECT_EQ(num_ctors, capacity);
+ while (!vec.empty()) {
+ vec.pop_back();
+ }
+
+ EXPECT_EQ(num_ctors, capacity);
+ EXPECT_EQ(num_dtors, num_ctors);
+
+ // And when larger than builtin capacity
+ for (int i = 0; i < capacity * 2; ++i) {
+ vec.emplace_back(num_ctors, num_dtors);
+ }
+
+ while (!vec.empty()) {
+ vec.pop_back();
+ }
+ EXPECT_EQ(num_dtors, num_ctors);
+}
+
} // namespace
} // namespace utils
} // namespace spvtools
diff --git a/third_party/SPIRV-Tools/test/val/val_arithmetics_test.cpp b/third_party/SPIRV-Tools/test/val/val_arithmetics_test.cpp
index 856ad02..4c093e9 100644
--- a/third_party/SPIRV-Tools/test/val/val_arithmetics_test.cpp
+++ b/third_party/SPIRV-Tools/test/val/val_arithmetics_test.cpp
@@ -656,7 +656,7 @@
EXPECT_THAT(
getDiagnosticString(),
HasSubstr(
- "Expected operands to have the same number of componenets: Dot"));
+ "Expected operands to have the same number of components: Dot"));
}
TEST_F(ValidateArithmetics, VectorTimesScalarSuccess) {
diff --git a/third_party/SPIRV-Tools/test/val/val_atomics_test.cpp b/third_party/SPIRV-Tools/test/val/val_atomics_test.cpp
index d1a030a..a0308d5 100644
--- a/third_party/SPIRV-Tools/test/val/val_atomics_test.cpp
+++ b/third_party/SPIRV-Tools/test/val/val_atomics_test.cpp
@@ -280,7 +280,7 @@
AnyVUID("VUID-StandaloneSpirv-None-04645"));
EXPECT_THAT(
getDiagnosticString(),
- HasSubstr("in Vulkan evironment, Workgroup Storage Class is limited to "
+ HasSubstr("in Vulkan environment, Workgroup Storage Class is limited to "
"MeshNV, TaskNV, and GLCompute execution model"));
}
@@ -708,7 +708,7 @@
AnyVUID("VUID-StandaloneSpirv-None-04645"));
EXPECT_THAT(
getDiagnosticString(),
- HasSubstr("in Vulkan evironment, Workgroup Storage Class is limited to "
+ HasSubstr("in Vulkan environment, Workgroup Storage Class is limited to "
"MeshNV, TaskNV, and GLCompute execution model"));
}
diff --git a/third_party/SPIRV-Tools/test/val/val_builtins_test.cpp b/third_party/SPIRV-Tools/test/val/val_builtins_test.cpp
index dff9adf..d749c5a 100644
--- a/third_party/SPIRV-Tools/test/val/val_builtins_test.cpp
+++ b/third_party/SPIRV-Tools/test/val/val_builtins_test.cpp
@@ -93,7 +93,8 @@
generator.extensions_ += extensions;
}
- generator.before_types_ = "OpMemberDecorate %built_in_type 0 BuiltIn ";
+ generator.before_types_ = R"(OpDecorate %built_in_type Block
+ OpMemberDecorate %built_in_type 0 BuiltIn )";
generator.before_types_ += built_in;
generator.before_types_ += "\n";
@@ -251,7 +252,8 @@
generator.extensions_ += extensions;
}
- generator.before_types_ = "OpMemberDecorate %built_in_type 0 BuiltIn ";
+ generator.before_types_ = R"(OpDecorate %built_in_type Block
+ OpMemberDecorate %built_in_type 0 BuiltIn )";
generator.before_types_ += built_in;
generator.before_types_ += "\n";
@@ -3098,6 +3100,8 @@
CodeGenerator generator = CodeGenerator::GetDefaultShaderCodeGenerator();
generator.before_types_ = R"(
+OpDecorate %input_type Block
+OpDecorate %output_type Block
OpMemberDecorate %input_type 0 BuiltIn FragCoord
OpMemberDecorate %output_type 0 BuiltIn Position
)";
@@ -3138,6 +3142,8 @@
CodeGenerator generator = CodeGenerator::GetDefaultShaderCodeGenerator();
generator.before_types_ = R"(
+OpDecorate %input_type Block
+OpDecorate %output_type Block
OpMemberDecorate %input_type 0 BuiltIn Position
OpMemberDecorate %output_type 0 BuiltIn FragCoord
)";
@@ -3201,6 +3207,7 @@
TEST_F(ValidateBuiltIns, FragmentPositionTwoEntryPoints) {
CodeGenerator generator = CodeGenerator::GetDefaultShaderCodeGenerator();
generator.before_types_ = R"(
+OpDecorate %output_type Block
OpMemberDecorate %output_type 0 BuiltIn Position
)";
@@ -3252,6 +3259,7 @@
CodeGenerator generator = CodeGenerator::GetDefaultShaderCodeGenerator();
generator.before_types_ = R"(
+OpDecorate %output_type Block
OpMemberDecorate %output_type 0 BuiltIn FragDepth
)";
@@ -3303,6 +3311,7 @@
CodeGenerator generator = CodeGenerator::GetDefaultShaderCodeGenerator();
generator.before_types_ = R"(
+OpDecorate %output_type Block
OpMemberDecorate %output_type 0 BuiltIn FragDepth
)";
@@ -3374,6 +3383,7 @@
)";
generator.before_types_ = R"(
+OpDecorate %input_type Block
OpMemberDecorate %input_type 0 BuiltIn InstanceId
)";
@@ -3609,6 +3619,7 @@
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %foo "foo"
OpExecutionMode %foo LocalSize 1 1 1
+OpDecorate %struct Block
OpMemberDecorate %struct 0 BuiltIn SubgroupEqMask
%void = OpTypeVoid
%int = OpTypeInt 32 0
@@ -3663,6 +3674,7 @@
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %foo "foo"
OpExecutionMode %foo LocalSize 1 1 1
+OpDecorate %struct Block
OpMemberDecorate %struct 0 BuiltIn SubgroupSize
%void = OpTypeVoid
%int = OpTypeInt 32 0
@@ -3723,6 +3735,7 @@
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %foo "foo"
OpExecutionMode %foo LocalSize 1 1 1
+OpDecorate %struct Block
OpMemberDecorate %struct 0 BuiltIn SubgroupId
%void = OpTypeVoid
%int = OpTypeInt 32 0
diff --git a/third_party/SPIRV-Tools/test/val/val_cfg_test.cpp b/third_party/SPIRV-Tools/test/val/val_cfg_test.cpp
index 311cfa7..7647746 100644
--- a/third_party/SPIRV-Tools/test/val/val_cfg_test.cpp
+++ b/third_party/SPIRV-Tools/test/val/val_cfg_test.cpp
@@ -65,7 +65,7 @@
/// Creates a Block with a given label
///
/// @param[in]: label the label id of the block
- /// @param[in]: type the branch instruciton that ends the block
+ /// @param[in]: type the branch instruction that ends the block
explicit Block(std::string label, SpvOp type = SpvOpBranch)
: label_(label), body_(), type_(type), successors_() {}
@@ -3523,7 +3523,7 @@
EXPECT_THAT(
getDiagnosticString(),
HasSubstr(
- "OpSwitch must be preceeded by an OpSelectionMerge instruction"));
+ "OpSwitch must be preceded by an OpSelectionMerge instruction"));
}
TEST_F(ValidateCFG, MissingMergeSwitchBad2) {
@@ -3550,7 +3550,7 @@
EXPECT_THAT(
getDiagnosticString(),
HasSubstr(
- "OpSwitch must be preceeded by an OpSelectionMerge instruction"));
+ "OpSwitch must be preceded by an OpSelectionMerge instruction"));
}
TEST_F(ValidateCFG, MissingMergeOneBranchToMergeGood) {
@@ -3622,7 +3622,7 @@
EXPECT_THAT(
getDiagnosticString(),
HasSubstr(
- "OpSwitch must be preceeded by an OpSelectionMerge instruction"));
+ "OpSwitch must be preceded by an OpSelectionMerge instruction"));
}
TEST_F(ValidateCFG, MissingMergeOneUnseenTargetSwitchBad) {
@@ -3654,7 +3654,7 @@
EXPECT_THAT(
getDiagnosticString(),
HasSubstr(
- "OpSwitch must be preceeded by an OpSelectionMerge instruction"));
+ "OpSwitch must be preceded by an OpSelectionMerge instruction"));
}
TEST_F(ValidateCFG, MissingMergeLoopBreakGood) {
@@ -4579,6 +4579,51 @@
EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
}
+TEST_F(ValidateCFG, BranchConditionalDifferentTargetsPre1p6) {
+ const std::string text = R"(
+OpCapability Shader
+OpCapability Linkage
+OpMemoryModel Logical GLSL450
+%void = OpTypeVoid
+%bool = OpTypeBool
+%undef = OpUndef %bool
+%void_fn = OpTypeFunction %void
+%func = OpFunction %void None %void_fn
+%entry = OpLabel
+OpBranchConditional %undef %target %target
+%target = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+ CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_5);
+ EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_5));
+}
+
+TEST_F(ValidateCFG, BranchConditionalDifferentTargetsPost1p6) {
+ const std::string text = R"(
+OpCapability Shader
+OpCapability Linkage
+OpMemoryModel Logical GLSL450
+%void = OpTypeVoid
+%bool = OpTypeBool
+%undef = OpUndef %bool
+%void_fn = OpTypeFunction %void
+%func = OpFunction %void None %void_fn
+%entry = OpLabel
+OpBranchConditional %undef %target %target
+%target = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+ CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_6);
+ EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_6));
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("In SPIR-V 1.6 or later, True Label and False Label "
+ "must be different labels"));
+}
+
} // namespace
} // namespace val
} // namespace spvtools
diff --git a/third_party/SPIRV-Tools/test/val/val_decoration_test.cpp b/third_party/SPIRV-Tools/test/val/val_decoration_test.cpp
index f2953ed..6f5a246 100644
--- a/third_party/SPIRV-Tools/test/val/val_decoration_test.cpp
+++ b/third_party/SPIRV-Tools/test/val/val_decoration_test.cpp
@@ -226,6 +226,7 @@
OpCapability Shader
OpCapability Linkage
OpMemoryModel Logical GLSL450
+ OpDecorate %_struct_1 Block
OpMemberDecorate %_struct_1 0 BuiltIn Position
OpMemberDecorate %_struct_1 1 BuiltIn Position
OpMemberDecorate %_struct_1 2 BuiltIn Position
@@ -243,6 +244,7 @@
OpCapability Shader
OpCapability Linkage
OpMemoryModel Logical GLSL450
+ OpDecorate %_struct_1 Block
OpMemberDecorate %_struct_1 0 BuiltIn Position
OpMemberDecorate %_struct_1 1 BuiltIn Position
%float = OpTypeFloat 32
@@ -265,6 +267,7 @@
OpCapability Shader
OpCapability Linkage
OpMemoryModel Logical GLSL450
+ OpDecorate %_struct_1 Block
OpMemberDecorate %_struct_1 0 BuiltIn Position
OpMemberDecorate %_struct_1 1 BuiltIn Position
OpMemberDecorate %_struct_1 2 BuiltIn Position
@@ -305,6 +308,8 @@
OpEntryPoint Geometry %main "main" %in_1 %in_2
OpExecutionMode %main InputPoints
OpExecutionMode %main OutputPoints
+ OpDecorate %struct_1 Block
+ OpDecorate %struct_2 Block
OpMemberDecorate %struct_1 0 BuiltIn InvocationId
OpMemberDecorate %struct_2 0 BuiltIn Position
%int = OpTypeInt 32 1
@@ -339,6 +344,8 @@
OpEntryPoint Geometry %main "main" %in_1 %out_1
OpExecutionMode %main InputPoints
OpExecutionMode %main OutputPoints
+ OpDecorate %struct_1 Block
+ OpDecorate %struct_2 Block
OpMemberDecorate %struct_1 0 BuiltIn InvocationId
OpMemberDecorate %struct_2 0 BuiltIn Position
%int = OpTypeInt 32 1
@@ -560,6 +567,8 @@
CompileSuccessfully(spirv, env);
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState(env));
EXPECT_THAT(getDiagnosticString(),
+ AnyVUID("VUID-StandaloneSpirv-Location-04915"));
+ EXPECT_THAT(getDiagnosticString(),
HasSubstr("A BuiltIn variable (id 2) cannot have any Location or "
"Component decorations"));
}
@@ -594,10 +603,354 @@
CompileSuccessfully(spirv, env);
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState(env));
EXPECT_THAT(getDiagnosticString(),
+ AnyVUID("VUID-StandaloneSpirv-Location-04915"));
+ EXPECT_THAT(getDiagnosticString(),
HasSubstr("A BuiltIn variable (id 2) cannot have any Location or "
"Component decorations"));
}
+TEST_F(ValidateDecorations, LocationDecorationOnNumericTypeBad) {
+ const spv_target_env env = SPV_ENV_VULKAN_1_0;
+ std::string spirv = R"(
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %main "main" %fragCoord
+ OpExecutionMode %main OriginUpperLeft
+ OpDecorate %fragCoord Location 0
+ OpDecorate %v4float Location 1
+ %void = OpTypeVoid
+ %voidfn = OpTypeFunction %void
+ %float = OpTypeFloat 32
+ %v4float = OpTypeVector %float 4
+%ptr_v4float = OpTypePointer Output %v4float
+ %fragCoord = OpVariable %ptr_v4float Output
+%non_interface = OpVariable %ptr_v4float Output
+ %main = OpFunction %void None %voidfn
+ %label = OpLabel
+ OpReturn
+ OpFunctionEnd
+)";
+
+ CompileSuccessfully(spirv, env);
+ EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState(env));
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("Location decoration on target <id> '3[%v4float]' must "
+ "be a variable"));
+}
+
+TEST_F(ValidateDecorations, LocationDecorationOnStructBad) {
+ const spv_target_env env = SPV_ENV_VULKAN_1_0;
+ std::string spirv = R"(
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %main "main" %fragCoord
+ OpExecutionMode %main OriginUpperLeft
+ OpDecorate %fragCoord Location 0
+ OpDecorate %struct Location 1
+ %void = OpTypeVoid
+ %voidfn = OpTypeFunction %void
+ %float = OpTypeFloat 32
+ %struct = OpTypeStruct %float
+ %v4float = OpTypeVector %float 4
+%ptr_v4float = OpTypePointer Output %v4float
+ %fragCoord = OpVariable %ptr_v4float Output
+%non_interface = OpVariable %ptr_v4float Output
+ %main = OpFunction %void None %voidfn
+ %label = OpLabel
+ OpReturn
+ OpFunctionEnd
+)";
+
+ CompileSuccessfully(spirv, env);
+ EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState(env));
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("Location decoration on target <id> '3[%_struct_3]' "
+ "must be a variable"));
+}
+
+TEST_F(ValidateDecorations,
+ LocationDecorationUnusedNonInterfaceVariableVulkan_Ignored) {
+ const spv_target_env env = SPV_ENV_VULKAN_1_0;
+ std::string spirv = R"(
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %main "main" %fragCoord
+ OpExecutionMode %main OriginUpperLeft
+ OpSource GLSL 450
+ OpDecorate %fragCoord Location 0
+ OpDecorate %non_interface Location 1
+ %void = OpTypeVoid
+ %voidfn = OpTypeFunction %void
+ %float = OpTypeFloat 32
+ %v4float = OpTypeVector %float 4
+%ptr_v4float = OpTypePointer Output %v4float
+ %fragCoord = OpVariable %ptr_v4float Output
+%non_interface = OpVariable %ptr_v4float Output
+ %main = OpFunction %void None %voidfn
+ %label = OpLabel
+ OpReturn
+ OpFunctionEnd
+)";
+
+ CompileSuccessfully(spirv, env);
+ EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState(env));
+ EXPECT_EQ(getDiagnosticString(), "");
+}
+
+TEST_F(ValidateDecorations,
+ LocationDecorationNonInterfaceStructVulkan_Ignored) {
+ const spv_target_env env = SPV_ENV_VULKAN_1_0;
+ std::string spirv = R"(
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %main "main" %fragCoord
+ OpExecutionMode %main OriginUpperLeft
+ OpDecorate %fragCoord Location 0
+ OpMemberDecorate %block 0 Location 2
+ OpMemberDecorate %block 0 Component 1
+ OpDecorate %block Block
+ %void = OpTypeVoid
+ %voidfn = OpTypeFunction %void
+ %float = OpTypeFloat 32
+ %vec3 = OpTypeVector %float 3
+%outvar_ptr = OpTypePointer Output %vec3
+ %fragCoord = OpVariable %outvar_ptr Output
+ %block = OpTypeStruct %vec3
+ %invar_ptr = OpTypePointer Input %block
+%non_interface = OpVariable %invar_ptr Input
+ %main = OpFunction %void None %voidfn
+ %label = OpLabel
+ OpReturn
+ OpFunctionEnd
+)";
+
+ CompileSuccessfully(spirv, env);
+ EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState(env));
+ EXPECT_EQ(getDiagnosticString(), "");
+}
+
+TEST_F(ValidateDecorations, LocationDecorationNonInterfaceStructVulkanGood) {
+ const spv_target_env env = SPV_ENV_VULKAN_1_0;
+ std::string spirv = R"(
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %main "main" %fragCoord %interface
+ OpExecutionMode %main OriginUpperLeft
+ OpDecorate %fragCoord Location 0
+ OpMemberDecorate %block 0 Location 2
+ OpMemberDecorate %block 0 Component 1
+ OpDecorate %block Block
+ %void = OpTypeVoid
+ %voidfn = OpTypeFunction %void
+ %float = OpTypeFloat 32
+ %vec3 = OpTypeVector %float 3
+%outvar_ptr = OpTypePointer Output %vec3
+ %fragCoord = OpVariable %outvar_ptr Output
+ %block = OpTypeStruct %vec3
+ %invar_ptr = OpTypePointer Input %block
+ %interface = OpVariable %invar_ptr Input ;; this variable is unused. Ignore it
+ %main = OpFunction %void None %voidfn
+ %label = OpLabel
+ OpReturn
+ OpFunctionEnd
+)";
+
+ CompileSuccessfully(spirv, env);
+ EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState(env));
+}
+
+TEST_F(ValidateDecorations, LocationDecorationVariableNonStructVulkanBad) {
+ const spv_target_env env = SPV_ENV_VULKAN_1_0;
+ std::string spirv = R"(
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %main "main" %fragCoord %nonblock_var
+ OpExecutionMode %main OriginUpperLeft
+ OpSource GLSL 450
+ OpDecorate %fragCoord Location 0
+ %void = OpTypeVoid
+ %voidfn = OpTypeFunction %void
+ %float = OpTypeFloat 32
+ %v4float = OpTypeVector %float 4
+%ptr_v4float = OpTypePointer Output %v4float
+ %fragCoord = OpVariable %ptr_v4float Output
+%nonblock_var = OpVariable %ptr_v4float Output
+ %main = OpFunction %void None %voidfn
+ %label = OpLabel
+ OpReturn
+ OpFunctionEnd
+)";
+
+ CompileSuccessfully(spirv, env);
+ EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateAndRetrieveValidationState(env));
+ EXPECT_THAT(getDiagnosticString(),
+ AnyVUID("VUID-StandaloneSpirv-Location-04916"));
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("Variable must be decorated with a location"));
+}
+
+TEST_F(ValidateDecorations, LocationDecorationVariableStructNoBlockVulkanBad) {
+ const spv_target_env env = SPV_ENV_VULKAN_1_0;
+ std::string spirv = R"(
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %main "main" %fragCoord %block_var
+ OpExecutionMode %main OriginUpperLeft
+ OpSource GLSL 450
+ OpDecorate %fragCoord Location 0
+ %void = OpTypeVoid
+ %voidfn = OpTypeFunction %void
+ %float = OpTypeFloat 32
+ %v4float = OpTypeVector %float 4
+%ptr_v4float = OpTypePointer Output %v4float
+ %fragCoord = OpVariable %ptr_v4float Output
+ %block = OpTypeStruct %v4float
+ %block_ptr = OpTypePointer Output %block
+ %block_var = OpVariable %block_ptr Output
+ %main = OpFunction %void None %voidfn
+ %label = OpLabel
+ OpReturn
+ OpFunctionEnd
+)";
+
+ CompileSuccessfully(spirv, env);
+ EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateAndRetrieveValidationState(env));
+ EXPECT_THAT(getDiagnosticString(),
+ AnyVUID("VUID-StandaloneSpirv-Location-04917"));
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("Variable must be decorated with a location"));
+}
+
+TEST_F(ValidateDecorations, LocationDecorationVariableNoBlockVulkanGood) {
+ const spv_target_env env = SPV_ENV_VULKAN_1_0;
+ std::string spirv = R"(
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %main "main" %fragCoord %block_var
+ OpExecutionMode %main OriginUpperLeft
+ OpSource GLSL 450
+ OpDecorate %fragCoord Location 0
+ OpDecorate %block_var Location 1
+ %void = OpTypeVoid
+ %voidfn = OpTypeFunction %void
+ %float = OpTypeFloat 32
+ %v4float = OpTypeVector %float 4
+%ptr_v4float = OpTypePointer Output %v4float
+ %fragCoord = OpVariable %ptr_v4float Output
+ %block = OpTypeStruct %v4float
+ %block_ptr = OpTypePointer Output %block
+ %block_var = OpVariable %block_ptr Output
+ %main = OpFunction %void None %voidfn
+ %label = OpLabel
+ OpReturn
+ OpFunctionEnd
+)";
+
+ CompileSuccessfully(spirv, env);
+ EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
+}
+
+TEST_F(ValidateDecorations, LocationDecorationVariableExtraMemeberVulkan) {
+ const spv_target_env env = SPV_ENV_VULKAN_1_0;
+ std::string spirv = R"(
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %main "main" %fragCoord %block_var
+ OpExecutionMode %main OriginUpperLeft
+ OpSource GLSL 450
+ OpDecorate %fragCoord Location 0
+ OpDecorate %block Block
+ OpDecorate %block_var Location 1
+ OpMemberDecorate %block 0 Location 1
+ %void = OpTypeVoid
+ %voidfn = OpTypeFunction %void
+ %float = OpTypeFloat 32
+ %v4float = OpTypeVector %float 4
+%ptr_v4float = OpTypePointer Output %v4float
+ %fragCoord = OpVariable %ptr_v4float Output
+ %block = OpTypeStruct %v4float
+ %block_ptr = OpTypePointer Output %block
+ %block_var = OpVariable %block_ptr Output
+ %main = OpFunction %void None %voidfn
+ %label = OpLabel
+ OpReturn
+ OpFunctionEnd
+
+)";
+
+ CompileSuccessfully(spirv, env);
+ EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateAndRetrieveValidationState(env));
+ EXPECT_THAT(getDiagnosticString(),
+ AnyVUID("VUID-StandaloneSpirv-Location-04918"));
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("Members cannot be assigned a location"));
+}
+
+TEST_F(ValidateDecorations, LocationDecorationVariableMissingMemeberVulkan) {
+ const spv_target_env env = SPV_ENV_VULKAN_1_0;
+ std::string spirv = R"(
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %main "main" %fragCoord %block_var
+ OpExecutionMode %main OriginUpperLeft
+ OpSource GLSL 450
+ OpDecorate %fragCoord Location 0
+ OpDecorate %block Block
+ OpMemberDecorate %block 0 Location 1
+ %void = OpTypeVoid
+ %voidfn = OpTypeFunction %void
+ %float = OpTypeFloat 32
+ %v4float = OpTypeVector %float 4
+%ptr_v4float = OpTypePointer Output %v4float
+ %fragCoord = OpVariable %ptr_v4float Output
+ %block = OpTypeStruct %v4float %v4float
+ %block_ptr = OpTypePointer Output %block
+ %block_var = OpVariable %block_ptr Output
+ %main = OpFunction %void None %voidfn
+ %label = OpLabel
+ OpReturn
+ OpFunctionEnd
+)";
+
+ CompileSuccessfully(spirv, env);
+ EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateAndRetrieveValidationState(env));
+ EXPECT_THAT(getDiagnosticString(),
+ AnyVUID("VUID-StandaloneSpirv-Location-04919"));
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("Member index 1 is missing a location assignment"));
+}
+
+TEST_F(ValidateDecorations, LocationDecorationVariableOnlyMemeberVulkanGood) {
+ const spv_target_env env = SPV_ENV_VULKAN_1_0;
+ std::string spirv = R"(
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %main "main" %fragCoord %block_var
+ OpExecutionMode %main OriginUpperLeft
+ OpSource GLSL 450
+ OpDecorate %fragCoord Location 0
+ OpDecorate %block Block
+ OpMemberDecorate %block 0 Location 1
+ OpMemberDecorate %block 1 Location 4
+ %void = OpTypeVoid
+ %voidfn = OpTypeFunction %void
+ %float = OpTypeFloat 32
+ %v4float = OpTypeVector %float 4
+%ptr_v4float = OpTypePointer Output %v4float
+ %fragCoord = OpVariable %ptr_v4float Output
+ %block = OpTypeStruct %v4float %v4float
+ %block_ptr = OpTypePointer Output %block
+ %block_var = OpVariable %block_ptr Output
+ %main = OpFunction %void None %voidfn
+ %label = OpLabel
+ OpReturn
+ OpFunctionEnd
+)";
+
+ CompileSuccessfully(spirv, env);
+ EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
+}
+
// #version 440
// #extension GL_EXT_nonuniform_qualifier : enable
// layout(binding = 1) uniform sampler2D s2d[];
diff --git a/third_party/SPIRV-Tools/test/val/val_ext_inst_debug_test.cpp b/third_party/SPIRV-Tools/test/val/val_ext_inst_debug_test.cpp
index 307a800..e153072 100644
--- a/third_party/SPIRV-Tools/test/val/val_ext_inst_debug_test.cpp
+++ b/third_party/SPIRV-Tools/test/val/val_ext_inst_debug_test.cpp
@@ -1547,7 +1547,7 @@
"integer scalar type"));
}
-TEST_F(ValidateVulkan100DebugInfo, DebugTypeArrayFailComponentCountZero) {
+TEST_F(ValidateVulkan100DebugInfo, DebugTypeArrayComponentCountZero) {
const std::string src = R"(
%src = OpString "simple.hlsl"
%code = OpString "main() {}"
@@ -1574,12 +1574,7 @@
CompileSuccessfully(GenerateShaderCodeForDebugInfo(
src, constants, dbg_inst_header, "", extension, "Vertex"));
- ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
- EXPECT_THAT(getDiagnosticString(),
- HasSubstr("Component Count must be OpConstant with a 32- or "
- "64-bits integer scalar type or DebugGlobalVariable or "
- "DebugLocalVariable with a 32- or 64-bits unsigned "
- "integer scalar type"));
+ ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
}
TEST_F(ValidateVulkan100DebugInfo, DebugTypeArrayFailVariableSizeTypeFloat) {
diff --git a/third_party/SPIRV-Tools/test/val/val_ext_inst_test.cpp b/third_party/SPIRV-Tools/test/val/val_ext_inst_test.cpp
index 2b6df04..a2109db 100644
--- a/third_party/SPIRV-Tools/test/val/val_ext_inst_test.cpp
+++ b/third_party/SPIRV-Tools/test/val/val_ext_inst_test.cpp
@@ -6045,6 +6045,18 @@
"declared without SPV_KHR_non_semantic_info"));
}
+TEST_F(ValidateClspvReflection, DoesNotRequiresNonSemanticExtensionPost1p6) {
+ const std::string text = R"(
+OpCapability Shader
+OpCapability Linkage
+%1 = OpExtInstImport "NonSemantic.ClspvReflection.1"
+OpMemoryModel Logical GLSL450
+)";
+
+ CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_6);
+ ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_6));
+}
+
TEST_F(ValidateClspvReflection, MissingVersion) {
const std::string text = R"(
OpCapability Shader
diff --git a/third_party/SPIRV-Tools/test/val/val_extension_spv_khr_terminate_invocation.cpp b/third_party/SPIRV-Tools/test/val/val_extension_spv_khr_terminate_invocation.cpp
index 4cabf9e..8d92414 100644
--- a/third_party/SPIRV-Tools/test/val/val_extension_spv_khr_terminate_invocation.cpp
+++ b/third_party/SPIRV-Tools/test/val/val_extension_spv_khr_terminate_invocation.cpp
@@ -55,7 +55,7 @@
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
}
-TEST_F(ValidateSpvKHRTerminateInvocation, RequiresExtension) {
+TEST_F(ValidateSpvKHRTerminateInvocation, RequiresExtensionPre1p6) {
const std::string str = R"(
OpCapability Shader
OpMemoryModel Logical Simple
@@ -72,9 +72,30 @@
)";
CompileSuccessfully(str.c_str());
EXPECT_NE(SPV_SUCCESS, ValidateInstructions());
- EXPECT_THAT(getDiagnosticString(),
- HasSubstr("TerminateInvocation requires one of the following "
- "extensions: SPV_KHR_terminate_invocation"));
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr(
+ "TerminateInvocation requires SPIR-V version 1.6 at minimum or one "
+ "of the following extensions: SPV_KHR_terminate_invocation"));
+}
+
+TEST_F(ValidateSpvKHRTerminateInvocation, RequiresNoExtensionPost1p6) {
+ const std::string str = R"(
+ OpCapability Shader
+ OpMemoryModel Logical Simple
+ OpEntryPoint Fragment %main "main"
+ OpExecutionMode %main OriginUpperLeft
+
+ %void = OpTypeVoid
+ %void_fn = OpTypeFunction %void
+
+ %main = OpFunction %void None %void_fn
+ %entry = OpLabel
+ OpTerminateInvocation
+ OpFunctionEnd
+)";
+ CompileSuccessfully(str.c_str(), SPV_ENV_UNIVERSAL_1_6);
+ EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_6));
}
TEST_F(ValidateSpvKHRTerminateInvocation, RequiresShaderCapability) {
diff --git a/third_party/SPIRV-Tools/test/val/val_id_test.cpp b/third_party/SPIRV-Tools/test/val/val_id_test.cpp
index ac05749..69257a5 100644
--- a/third_party/SPIRV-Tools/test/val/val_id_test.cpp
+++ b/third_party/SPIRV-Tools/test/val/val_id_test.cpp
@@ -1015,7 +1015,7 @@
"type."));
}
// TODO: Object of this type can only be created with OpVariable using the
-// Unifrom Storage Class
+// Uniform Storage Class
TEST_F(ValidateIdWithMessage, OpTypeStructGood) {
std::string spirv = kGLSL450MemoryModel + R"(
@@ -2859,7 +2859,7 @@
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
}
-// Same code as the last test excect for an extra decoration on one of the
+// Same code as the last test except for an extra decoration on one of the
// members. With the relaxed rules, the code is still valid.
TEST_F(ValidateIdWithMessage, OpStoreTypeRelaxedStructWithExtraDecoration) {
std::string spirv = kGLSL450MemoryModel + R"(
diff --git a/third_party/SPIRV-Tools/test/val/val_image_test.cpp b/third_party/SPIRV-Tools/test/val/val_image_test.cpp
index 11b14fb..a11d07c 100644
--- a/third_party/SPIRV-Tools/test/val/val_image_test.cpp
+++ b/third_party/SPIRV-Tools/test/val/val_image_test.cpp
@@ -61,8 +61,11 @@
// In 1.4, the entry point must list all module-scope variables used. Just
// list all of them.
- std::string interface_vars = (env != SPV_ENV_UNIVERSAL_1_4) ? "" :
- R"(
+ //
+ // For Vulkan, anything Location decoration needs to be an interface variable
+ std::string interface_vars =
+ (env != SPV_ENV_UNIVERSAL_1_4) ? "%input_flat_u32" :
+ R"(
%uniform_image_f32_1d_0001
%uniform_image_f32_1d_0002_rgba32f
%uniform_image_f32_2d_0001
@@ -1059,7 +1062,7 @@
CompileSuccessfully(GenerateShaderCode(body).c_str());
ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
- EXPECT_THAT(getDiagnosticString(), HasSubstr("Operand 136[%136] cannot be a "
+ EXPECT_THAT(getDiagnosticString(), HasSubstr("Operand 137[%137] cannot be a "
"type"));
}
@@ -3131,7 +3134,7 @@
CompileSuccessfully(GenerateShaderCode(body).c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(),
- HasSubstr("Expected Image Operand ConstOffsets array componenets "
+ HasSubstr("Expected Image Operand ConstOffsets array components "
"to be int vectors of size 2"));
}
@@ -3146,7 +3149,7 @@
CompileSuccessfully(GenerateShaderCode(body).c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(),
- HasSubstr("Expected Image Operand ConstOffsets array componenets "
+ HasSubstr("Expected Image Operand ConstOffsets array components "
"to be int vectors of size 2"));
}
@@ -6099,6 +6102,57 @@
"execution mode for GLCompute execution model"));
}
+TEST_F(ValidateImage, TypeSampledImageNotBufferPost1p6) {
+ const std::string text = R"(
+OpCapability Shader
+OpCapability Linkage
+OpCapability SampledBuffer
+OpMemoryModel Logical GLSL450
+%float = OpTypeFloat 32
+%image = OpTypeImage %float Buffer 0 0 0 1 Unknown
+%sampled = OpTypeSampledImage %image
+)";
+
+ CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_6);
+ EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_6));
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("In SPIR-V 1.6 or later, sampled image dimension must "
+ "not be Buffer"));
+}
+
+TEST_F(ValidateImage, NonTemporalImage) {
+ const std::string text = R"(
+OpCapability Shader
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %2 " " %4 %5
+OpExecutionMode %2 OriginUpperLeft
+%void = OpTypeVoid
+%8 = OpTypeFunction %void
+%float = OpTypeFloat 32
+%v4float = OpTypeVector %float 4
+%12 = OpTypeImage %float 2D 0 0 0 1 Rgba8ui
+%13 = OpTypeSampledImage %12
+%_ptr_UniformConstant_13 = OpTypePointer UniformConstant %13
+%5 = OpVariable %_ptr_UniformConstant_13 UniformConstant
+%_ptr_Input_v4float = OpTypePointer Input %v4float
+%4 = OpVariable %_ptr_Input_v4float Input
+%v2float = OpTypeVector %float 2
+%float_1_35631564en19 = OpConstant %float 1.35631564e-19
+%2 = OpFunction %void None %8
+%8224 = OpLabel
+%6 = OpLoad %13 %5
+%19 = OpLoad %v4float %4
+%20 = OpVectorShuffle %v2float %19 %19 0 1
+%21 = OpVectorTimesScalar %v2float %20 %float_1_35631564en19
+%65312 = OpImageSampleImplicitLod %v4float %6 %21 Nontemporal
+OpReturn
+OpFunctionEnd
+)";
+
+ CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_6);
+ EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_6));
+}
+
} // namespace
} // namespace val
} // namespace spvtools
diff --git a/third_party/SPIRV-Tools/test/val/val_interfaces_test.cpp b/third_party/SPIRV-Tools/test/val/val_interfaces_test.cpp
index a01fc19..bec8d02 100644
--- a/third_party/SPIRV-Tools/test/val/val_interfaces_test.cpp
+++ b/third_party/SPIRV-Tools/test/val/val_interfaces_test.cpp
@@ -448,6 +448,8 @@
CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
EXPECT_THAT(getDiagnosticString(),
+ AnyVUID("VUID-StandaloneSpirv-Location-04918"));
+ EXPECT_THAT(getDiagnosticString(),
HasSubstr("Members cannot be assigned a location"));
}
@@ -476,6 +478,8 @@
CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
EXPECT_THAT(getDiagnosticString(),
+ AnyVUID("VUID-StandaloneSpirv-Location-04918"));
+ EXPECT_THAT(getDiagnosticString(),
HasSubstr("Members cannot be assigned a location"));
}
@@ -1496,6 +1500,42 @@
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
}
+TEST_F(ValidateInterfacesTest, StructWithBuiltinsMissingBlock_Bad) {
+ // See https://github.com/KhronosGroup/SPIRV-Registry/issues/134
+ //
+ // When a shader input or output is a struct that does not have Block,
+ // then it must have a Location.
+ // But BuiltIns must not have locations.
+ const std::string text = R"(
+OpCapability Shader
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %main "main" %in
+OpExecutionMode %main OriginUpperLeft
+; %struct needs a Block decoration
+OpMemberDecorate %struct 0 BuiltIn Position
+%void = OpTypeVoid
+%float = OpTypeFloat 32
+%v4float = OpTypeVector %float 4
+%struct = OpTypeStruct %v4float
+%in_ptr = OpTypePointer Input %struct
+%in = OpVariable %in_ptr Input
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%entry = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+ CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
+ EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
+ EXPECT_THAT(getDiagnosticString(),
+ AnyVUID("VUID-StandaloneSpirv-Location-04919"));
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr(
+ "Interface struct has no Block decoration but has BuiltIn members."));
+}
+
} // namespace
} // namespace val
} // namespace spvtools
diff --git a/third_party/SPIRV-Tools/test/val/val_limits_test.cpp b/third_party/SPIRV-Tools/test/val/val_limits_test.cpp
index 8fb80a4..364d514 100644
--- a/third_party/SPIRV-Tools/test/val/val_limits_test.cpp
+++ b/third_party/SPIRV-Tools/test/val/val_limits_test.cpp
@@ -750,7 +750,7 @@
}
// Valid. The purpose here is to test the CFG depth calculation code when a loop
-// continue target is the loop iteself. It also exercises the case where a loop
+// continue target is the loop itself. It also exercises the case where a loop
// is unreachable.
TEST_F(ValidateLimits, ControlFlowNoEntryToLoopGood) {
std::string str = header + R"(
diff --git a/third_party/SPIRV-Tools/test/val/val_literals_test.cpp b/third_party/SPIRV-Tools/test/val/val_literals_test.cpp
index 6eadf32..7c9aad6 100644
--- a/third_party/SPIRV-Tools/test/val/val_literals_test.cpp
+++ b/third_party/SPIRV-Tools/test/val/val_literals_test.cpp
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-// Validation tests for ilegal literals
+// Validation tests for illegal literals
#include <string>
#include <utility>
diff --git a/third_party/SPIRV-Tools/test/val/val_memory_test.cpp b/third_party/SPIRV-Tools/test/val/val_memory_test.cpp
index 2a884c4..8ff40e1 100644
--- a/third_party/SPIRV-Tools/test/val/val_memory_test.cpp
+++ b/third_party/SPIRV-Tools/test/val/val_memory_test.cpp
@@ -4048,7 +4048,7 @@
const std::string spirv = R"(
OpCapability Shader
OpMemoryModel Logical GLSL450
-OpEntryPoint Vertex %main "main"
+OpEntryPoint Vertex %main "main" %var
OpDecorate %var Location 0
OpDecorate %var Invariant
%void = OpTypeVoid
@@ -4070,7 +4070,7 @@
const std::string spirv = R"(
OpCapability Shader
OpMemoryModel Logical GLSL450
-OpEntryPoint Fragment %main "main"
+OpEntryPoint Fragment %main "main" %var
OpExecutionMode %main OriginUpperLeft
OpDecorate %var Location 0
OpMemberDecorate %struct 1 Invariant
diff --git a/third_party/SPIRV-Tools/test/val/val_modes_test.cpp b/third_party/SPIRV-Tools/test/val/val_modes_test.cpp
index 02a6132..a37989b 100644
--- a/third_party/SPIRV-Tools/test/val/val_modes_test.cpp
+++ b/third_party/SPIRV-Tools/test/val/val_modes_test.cpp
@@ -1178,6 +1178,26 @@
HasSubstr("Expected bool scalar type as Result Type"));
}
+TEST_F(ValidateMode, LocalSizeIdVulkan1p3DoesNotRequireOption) {
+ const std::string spirv = R"(
+OpCapability Shader
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %main "main"
+OpExecutionModeId %main LocalSizeId %int_1 %int_1 %int_1
+%void = OpTypeVoid
+%int = OpTypeInt 32 0
+%int_1 = OpConstant %int 1
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%entry = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+ CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_3);
+ EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_3));
+}
+
} // namespace
} // namespace val
} // namespace spvtools
diff --git a/third_party/SPIRV-Tools/test/val/val_non_semantic_test.cpp b/third_party/SPIRV-Tools/test/val/val_non_semantic_test.cpp
index b80bb1a..210cd1a 100644
--- a/third_party/SPIRV-Tools/test/val/val_non_semantic_test.cpp
+++ b/third_party/SPIRV-Tools/test/val/val_non_semantic_test.cpp
@@ -105,7 +105,7 @@
Values(""), Values(TestResult())));
INSTANTIATE_TEST_SUITE_P(
- MissingOpExtension, ValidateNonSemanticGenerated,
+ MissingOpExtensionPre1p6, ValidateNonSemanticGenerated,
Combine(Values(false), Values(true), Values(""), Values(""),
Values(TestResult(
SPV_ERROR_INVALID_DATA,
@@ -190,6 +190,26 @@
HasSubstr("ID 2[%2] has not been defined"));
}
+TEST_F(ValidateNonSemanticString, MissingOpExtensionPost1p6) {
+ const std::string spirv = R"(
+OpCapability Shader
+%extinst = OpExtInstImport "NonSemantic.Testing.Set"
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %main "main"
+OpExecutionMode %main OriginUpperLeft
+%void = OpTypeVoid
+%test = OpExtInst %void %extinst 3
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%entry = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+ CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_6);
+ EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_6));
+}
+
} // namespace
} // namespace val
} // namespace spvtools
diff --git a/third_party/SPIRV-Tools/test/val/val_storage_test.cpp b/third_party/SPIRV-Tools/test/val/val_storage_test.cpp
index 35f6a8d..ae4047b 100644
--- a/third_party/SPIRV-Tools/test/val/val_storage_test.cpp
+++ b/third_party/SPIRV-Tools/test/val/val_storage_test.cpp
@@ -280,7 +280,7 @@
AnyVUID("VUID-StandaloneSpirv-None-04644"));
EXPECT_THAT(
getDiagnosticString(),
- HasSubstr("in Vulkan evironment, Output Storage Class must not be used "
+ HasSubstr("in Vulkan environment, Output Storage Class must not be used "
"in GLCompute, RayGenerationKHR, IntersectionKHR, AnyHitKHR, "
"ClosestHitKHR, MissKHR, or CallableKHR execution models"));
}
diff --git a/third_party/SPIRV-Tools/test/val/val_version_test.cpp b/third_party/SPIRV-Tools/test/val/val_version_test.cpp
index 98565dd..6b7c4fe 100644
--- a/third_party/SPIRV-Tools/test/val/val_version_test.cpp
+++ b/third_party/SPIRV-Tools/test/val/val_version_test.cpp
@@ -74,6 +74,12 @@
case SPV_ENV_UNIVERSAL_1_4:
case SPV_ENV_VULKAN_1_1_SPIRV_1_4:
return "1.4";
+ case SPV_ENV_UNIVERSAL_1_5:
+ case SPV_ENV_VULKAN_1_2:
+ return "1.5";
+ case SPV_ENV_UNIVERSAL_1_6:
+ case SPV_ENV_VULKAN_1_3:
+ return "1.6";
default:
return "0";
}
@@ -103,8 +109,14 @@
std::make_tuple(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1, vulkan_spirv, true),
std::make_tuple(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_2, vulkan_spirv, true),
std::make_tuple(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_3, vulkan_spirv, true),
+ std::make_tuple(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_4, vulkan_spirv, true),
+ std::make_tuple(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_5, vulkan_spirv, true),
+ std::make_tuple(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_6, vulkan_spirv, true),
std::make_tuple(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_VULKAN_1_0, vulkan_spirv, true),
std::make_tuple(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_VULKAN_1_1, vulkan_spirv, true),
+ std::make_tuple(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_VULKAN_1_1_SPIRV_1_4,vulkan_spirv, true),
+ std::make_tuple(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_VULKAN_1_2, vulkan_spirv, true),
+ std::make_tuple(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_VULKAN_1_3, vulkan_spirv, true),
std::make_tuple(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_OPENGL_4_0, vulkan_spirv, true),
std::make_tuple(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_OPENGL_4_1, vulkan_spirv, true),
std::make_tuple(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_OPENGL_4_2, vulkan_spirv, true),
@@ -115,8 +127,14 @@
std::make_tuple(SPV_ENV_UNIVERSAL_1_1, SPV_ENV_UNIVERSAL_1_1, vulkan_spirv, true),
std::make_tuple(SPV_ENV_UNIVERSAL_1_1, SPV_ENV_UNIVERSAL_1_2, vulkan_spirv, true),
std::make_tuple(SPV_ENV_UNIVERSAL_1_1, SPV_ENV_UNIVERSAL_1_3, vulkan_spirv, true),
+ std::make_tuple(SPV_ENV_UNIVERSAL_1_1, SPV_ENV_UNIVERSAL_1_4, vulkan_spirv, true),
+ std::make_tuple(SPV_ENV_UNIVERSAL_1_1, SPV_ENV_UNIVERSAL_1_5, vulkan_spirv, true),
+ std::make_tuple(SPV_ENV_UNIVERSAL_1_1, SPV_ENV_UNIVERSAL_1_6, vulkan_spirv, true),
std::make_tuple(SPV_ENV_UNIVERSAL_1_1, SPV_ENV_VULKAN_1_0, vulkan_spirv, false),
std::make_tuple(SPV_ENV_UNIVERSAL_1_1, SPV_ENV_VULKAN_1_1, vulkan_spirv, true),
+ std::make_tuple(SPV_ENV_UNIVERSAL_1_1, SPV_ENV_VULKAN_1_1_SPIRV_1_4, vulkan_spirv, true),
+ std::make_tuple(SPV_ENV_UNIVERSAL_1_1, SPV_ENV_VULKAN_1_2, vulkan_spirv, true),
+ std::make_tuple(SPV_ENV_UNIVERSAL_1_1, SPV_ENV_VULKAN_1_3, vulkan_spirv, true),
std::make_tuple(SPV_ENV_UNIVERSAL_1_1, SPV_ENV_OPENGL_4_0, vulkan_spirv, false),
std::make_tuple(SPV_ENV_UNIVERSAL_1_1, SPV_ENV_OPENGL_4_1, vulkan_spirv, false),
std::make_tuple(SPV_ENV_UNIVERSAL_1_1, SPV_ENV_OPENGL_4_2, vulkan_spirv, false),
@@ -127,8 +145,14 @@
std::make_tuple(SPV_ENV_UNIVERSAL_1_2, SPV_ENV_UNIVERSAL_1_1, vulkan_spirv, false),
std::make_tuple(SPV_ENV_UNIVERSAL_1_2, SPV_ENV_UNIVERSAL_1_2, vulkan_spirv, true),
std::make_tuple(SPV_ENV_UNIVERSAL_1_2, SPV_ENV_UNIVERSAL_1_3, vulkan_spirv, true),
+ std::make_tuple(SPV_ENV_UNIVERSAL_1_2, SPV_ENV_UNIVERSAL_1_4, vulkan_spirv, true),
+ std::make_tuple(SPV_ENV_UNIVERSAL_1_2, SPV_ENV_UNIVERSAL_1_5, vulkan_spirv, true),
+ std::make_tuple(SPV_ENV_UNIVERSAL_1_2, SPV_ENV_UNIVERSAL_1_6, vulkan_spirv, true),
std::make_tuple(SPV_ENV_UNIVERSAL_1_2, SPV_ENV_VULKAN_1_0, vulkan_spirv, false),
std::make_tuple(SPV_ENV_UNIVERSAL_1_2, SPV_ENV_VULKAN_1_1, vulkan_spirv, true),
+ std::make_tuple(SPV_ENV_UNIVERSAL_1_2, SPV_ENV_VULKAN_1_1_SPIRV_1_4, vulkan_spirv, true),
+ std::make_tuple(SPV_ENV_UNIVERSAL_1_2, SPV_ENV_VULKAN_1_2, vulkan_spirv, true),
+ std::make_tuple(SPV_ENV_UNIVERSAL_1_2, SPV_ENV_VULKAN_1_3, vulkan_spirv, true),
std::make_tuple(SPV_ENV_UNIVERSAL_1_2, SPV_ENV_OPENGL_4_0, vulkan_spirv, false),
std::make_tuple(SPV_ENV_UNIVERSAL_1_2, SPV_ENV_OPENGL_4_1, vulkan_spirv, false),
std::make_tuple(SPV_ENV_UNIVERSAL_1_2, SPV_ENV_OPENGL_4_2, vulkan_spirv, false),
@@ -139,13 +163,73 @@
std::make_tuple(SPV_ENV_UNIVERSAL_1_3, SPV_ENV_UNIVERSAL_1_1, vulkan_spirv, false),
std::make_tuple(SPV_ENV_UNIVERSAL_1_3, SPV_ENV_UNIVERSAL_1_2, vulkan_spirv, false),
std::make_tuple(SPV_ENV_UNIVERSAL_1_3, SPV_ENV_UNIVERSAL_1_3, vulkan_spirv, true),
+ std::make_tuple(SPV_ENV_UNIVERSAL_1_3, SPV_ENV_UNIVERSAL_1_4, vulkan_spirv, true),
+ std::make_tuple(SPV_ENV_UNIVERSAL_1_3, SPV_ENV_UNIVERSAL_1_5, vulkan_spirv, true),
+ std::make_tuple(SPV_ENV_UNIVERSAL_1_3, SPV_ENV_UNIVERSAL_1_6, vulkan_spirv, true),
std::make_tuple(SPV_ENV_UNIVERSAL_1_3, SPV_ENV_VULKAN_1_0, vulkan_spirv, false),
std::make_tuple(SPV_ENV_UNIVERSAL_1_3, SPV_ENV_VULKAN_1_1, vulkan_spirv, true),
+ std::make_tuple(SPV_ENV_UNIVERSAL_1_3, SPV_ENV_VULKAN_1_1_SPIRV_1_4, vulkan_spirv, true),
+ std::make_tuple(SPV_ENV_UNIVERSAL_1_3, SPV_ENV_VULKAN_1_2, vulkan_spirv, true),
+ std::make_tuple(SPV_ENV_UNIVERSAL_1_3, SPV_ENV_VULKAN_1_3, vulkan_spirv, true),
std::make_tuple(SPV_ENV_UNIVERSAL_1_3, SPV_ENV_OPENGL_4_0, vulkan_spirv, false),
std::make_tuple(SPV_ENV_UNIVERSAL_1_3, SPV_ENV_OPENGL_4_1, vulkan_spirv, false),
std::make_tuple(SPV_ENV_UNIVERSAL_1_3, SPV_ENV_OPENGL_4_2, vulkan_spirv, false),
std::make_tuple(SPV_ENV_UNIVERSAL_1_3, SPV_ENV_OPENGL_4_3, vulkan_spirv, false),
- std::make_tuple(SPV_ENV_UNIVERSAL_1_3, SPV_ENV_OPENGL_4_5, vulkan_spirv, false)
+ std::make_tuple(SPV_ENV_UNIVERSAL_1_3, SPV_ENV_OPENGL_4_5, vulkan_spirv, false),
+
+ std::make_tuple(SPV_ENV_UNIVERSAL_1_4, SPV_ENV_UNIVERSAL_1_0, vulkan_spirv, false),
+ std::make_tuple(SPV_ENV_UNIVERSAL_1_4, SPV_ENV_UNIVERSAL_1_1, vulkan_spirv, false),
+ std::make_tuple(SPV_ENV_UNIVERSAL_1_4, SPV_ENV_UNIVERSAL_1_2, vulkan_spirv, false),
+ std::make_tuple(SPV_ENV_UNIVERSAL_1_4, SPV_ENV_UNIVERSAL_1_3, vulkan_spirv, false),
+ std::make_tuple(SPV_ENV_UNIVERSAL_1_4, SPV_ENV_UNIVERSAL_1_4, vulkan_spirv, true),
+ std::make_tuple(SPV_ENV_UNIVERSAL_1_4, SPV_ENV_UNIVERSAL_1_5, vulkan_spirv, true),
+ std::make_tuple(SPV_ENV_UNIVERSAL_1_4, SPV_ENV_UNIVERSAL_1_6, vulkan_spirv, true),
+ std::make_tuple(SPV_ENV_UNIVERSAL_1_4, SPV_ENV_VULKAN_1_0, vulkan_spirv, false),
+ std::make_tuple(SPV_ENV_UNIVERSAL_1_4, SPV_ENV_VULKAN_1_1, vulkan_spirv, false),
+ std::make_tuple(SPV_ENV_UNIVERSAL_1_4, SPV_ENV_VULKAN_1_1_SPIRV_1_4, vulkan_spirv, true),
+ std::make_tuple(SPV_ENV_UNIVERSAL_1_4, SPV_ENV_VULKAN_1_2, vulkan_spirv, true),
+ std::make_tuple(SPV_ENV_UNIVERSAL_1_4, SPV_ENV_VULKAN_1_3, vulkan_spirv, true),
+ std::make_tuple(SPV_ENV_UNIVERSAL_1_4, SPV_ENV_OPENGL_4_0, vulkan_spirv, false),
+ std::make_tuple(SPV_ENV_UNIVERSAL_1_4, SPV_ENV_OPENGL_4_1, vulkan_spirv, false),
+ std::make_tuple(SPV_ENV_UNIVERSAL_1_4, SPV_ENV_OPENGL_4_2, vulkan_spirv, false),
+ std::make_tuple(SPV_ENV_UNIVERSAL_1_4, SPV_ENV_OPENGL_4_3, vulkan_spirv, false),
+ std::make_tuple(SPV_ENV_UNIVERSAL_1_4, SPV_ENV_OPENGL_4_5, vulkan_spirv, false),
+
+ std::make_tuple(SPV_ENV_UNIVERSAL_1_5, SPV_ENV_UNIVERSAL_1_0, vulkan_spirv, false),
+ std::make_tuple(SPV_ENV_UNIVERSAL_1_5, SPV_ENV_UNIVERSAL_1_1, vulkan_spirv, false),
+ std::make_tuple(SPV_ENV_UNIVERSAL_1_5, SPV_ENV_UNIVERSAL_1_2, vulkan_spirv, false),
+ std::make_tuple(SPV_ENV_UNIVERSAL_1_5, SPV_ENV_UNIVERSAL_1_3, vulkan_spirv, false),
+ std::make_tuple(SPV_ENV_UNIVERSAL_1_5, SPV_ENV_UNIVERSAL_1_4, vulkan_spirv, false),
+ std::make_tuple(SPV_ENV_UNIVERSAL_1_5, SPV_ENV_UNIVERSAL_1_5, vulkan_spirv, true),
+ std::make_tuple(SPV_ENV_UNIVERSAL_1_5, SPV_ENV_UNIVERSAL_1_6, vulkan_spirv, true),
+ std::make_tuple(SPV_ENV_UNIVERSAL_1_5, SPV_ENV_VULKAN_1_0, vulkan_spirv, false),
+ std::make_tuple(SPV_ENV_UNIVERSAL_1_5, SPV_ENV_VULKAN_1_1, vulkan_spirv, false),
+ std::make_tuple(SPV_ENV_UNIVERSAL_1_5, SPV_ENV_VULKAN_1_1_SPIRV_1_4, vulkan_spirv, false),
+ std::make_tuple(SPV_ENV_UNIVERSAL_1_5, SPV_ENV_VULKAN_1_2, vulkan_spirv, true),
+ std::make_tuple(SPV_ENV_UNIVERSAL_1_5, SPV_ENV_VULKAN_1_3, vulkan_spirv, true),
+ std::make_tuple(SPV_ENV_UNIVERSAL_1_5, SPV_ENV_OPENGL_4_0, vulkan_spirv, false),
+ std::make_tuple(SPV_ENV_UNIVERSAL_1_5, SPV_ENV_OPENGL_4_1, vulkan_spirv, false),
+ std::make_tuple(SPV_ENV_UNIVERSAL_1_5, SPV_ENV_OPENGL_4_2, vulkan_spirv, false),
+ std::make_tuple(SPV_ENV_UNIVERSAL_1_5, SPV_ENV_OPENGL_4_3, vulkan_spirv, false),
+ std::make_tuple(SPV_ENV_UNIVERSAL_1_5, SPV_ENV_OPENGL_4_5, vulkan_spirv, false),
+
+ std::make_tuple(SPV_ENV_UNIVERSAL_1_6, SPV_ENV_UNIVERSAL_1_0, vulkan_spirv, false),
+ std::make_tuple(SPV_ENV_UNIVERSAL_1_6, SPV_ENV_UNIVERSAL_1_1, vulkan_spirv, false),
+ std::make_tuple(SPV_ENV_UNIVERSAL_1_6, SPV_ENV_UNIVERSAL_1_2, vulkan_spirv, false),
+ std::make_tuple(SPV_ENV_UNIVERSAL_1_6, SPV_ENV_UNIVERSAL_1_3, vulkan_spirv, false),
+ std::make_tuple(SPV_ENV_UNIVERSAL_1_6, SPV_ENV_UNIVERSAL_1_4, vulkan_spirv, false),
+ std::make_tuple(SPV_ENV_UNIVERSAL_1_6, SPV_ENV_UNIVERSAL_1_5, vulkan_spirv, false),
+ std::make_tuple(SPV_ENV_UNIVERSAL_1_6, SPV_ENV_UNIVERSAL_1_6, vulkan_spirv, true),
+ std::make_tuple(SPV_ENV_UNIVERSAL_1_6, SPV_ENV_VULKAN_1_0, vulkan_spirv, false),
+ std::make_tuple(SPV_ENV_UNIVERSAL_1_6, SPV_ENV_VULKAN_1_1, vulkan_spirv, false),
+ std::make_tuple(SPV_ENV_UNIVERSAL_1_6, SPV_ENV_VULKAN_1_1_SPIRV_1_4, vulkan_spirv, false),
+ std::make_tuple(SPV_ENV_UNIVERSAL_1_6, SPV_ENV_VULKAN_1_2, vulkan_spirv, false),
+ std::make_tuple(SPV_ENV_UNIVERSAL_1_6, SPV_ENV_VULKAN_1_3, vulkan_spirv, true),
+ std::make_tuple(SPV_ENV_UNIVERSAL_1_6, SPV_ENV_OPENGL_4_0, vulkan_spirv, false),
+ std::make_tuple(SPV_ENV_UNIVERSAL_1_6, SPV_ENV_OPENGL_4_1, vulkan_spirv, false),
+ std::make_tuple(SPV_ENV_UNIVERSAL_1_6, SPV_ENV_OPENGL_4_2, vulkan_spirv, false),
+ std::make_tuple(SPV_ENV_UNIVERSAL_1_6, SPV_ENV_OPENGL_4_3, vulkan_spirv, false),
+ std::make_tuple(SPV_ENV_UNIVERSAL_1_6, SPV_ENV_OPENGL_4_5, vulkan_spirv, false)
)
);
@@ -156,27 +240,91 @@
std::make_tuple(SPV_ENV_VULKAN_1_0, SPV_ENV_UNIVERSAL_1_1, vulkan_spirv, true),
std::make_tuple(SPV_ENV_VULKAN_1_0, SPV_ENV_UNIVERSAL_1_2, vulkan_spirv, true),
std::make_tuple(SPV_ENV_VULKAN_1_0, SPV_ENV_UNIVERSAL_1_3, vulkan_spirv, true),
+ std::make_tuple(SPV_ENV_VULKAN_1_0, SPV_ENV_UNIVERSAL_1_4, vulkan_spirv, true),
+ std::make_tuple(SPV_ENV_VULKAN_1_0, SPV_ENV_UNIVERSAL_1_5, vulkan_spirv, true),
+ std::make_tuple(SPV_ENV_VULKAN_1_0, SPV_ENV_UNIVERSAL_1_6, vulkan_spirv, true),
std::make_tuple(SPV_ENV_VULKAN_1_0, SPV_ENV_VULKAN_1_0, vulkan_spirv, true),
std::make_tuple(SPV_ENV_VULKAN_1_0, SPV_ENV_VULKAN_1_1, vulkan_spirv, true),
+ std::make_tuple(SPV_ENV_VULKAN_1_0, SPV_ENV_VULKAN_1_1_SPIRV_1_4, vulkan_spirv, true),
+ std::make_tuple(SPV_ENV_VULKAN_1_0, SPV_ENV_VULKAN_1_2, vulkan_spirv, true),
+ std::make_tuple(SPV_ENV_VULKAN_1_0, SPV_ENV_VULKAN_1_3, vulkan_spirv, true),
std::make_tuple(SPV_ENV_VULKAN_1_0, SPV_ENV_OPENGL_4_0, vulkan_spirv, true),
std::make_tuple(SPV_ENV_VULKAN_1_0, SPV_ENV_OPENGL_4_1, vulkan_spirv, true),
std::make_tuple(SPV_ENV_VULKAN_1_0, SPV_ENV_OPENGL_4_2, vulkan_spirv, true),
std::make_tuple(SPV_ENV_VULKAN_1_0, SPV_ENV_OPENGL_4_3, vulkan_spirv, true),
std::make_tuple(SPV_ENV_VULKAN_1_0, SPV_ENV_OPENGL_4_5, vulkan_spirv, true),
- std::make_tuple(SPV_ENV_VULKAN_1_0, SPV_ENV_VULKAN_1_1_SPIRV_1_4, vulkan_spirv, true),
std::make_tuple(SPV_ENV_VULKAN_1_1, SPV_ENV_UNIVERSAL_1_0, vulkan_spirv, false),
std::make_tuple(SPV_ENV_VULKAN_1_1, SPV_ENV_UNIVERSAL_1_1, vulkan_spirv, false),
std::make_tuple(SPV_ENV_VULKAN_1_1, SPV_ENV_UNIVERSAL_1_2, vulkan_spirv, false),
std::make_tuple(SPV_ENV_VULKAN_1_1, SPV_ENV_UNIVERSAL_1_3, vulkan_spirv, true),
+ std::make_tuple(SPV_ENV_VULKAN_1_1, SPV_ENV_UNIVERSAL_1_4, vulkan_spirv, true),
+ std::make_tuple(SPV_ENV_VULKAN_1_1, SPV_ENV_UNIVERSAL_1_5, vulkan_spirv, true),
+ std::make_tuple(SPV_ENV_VULKAN_1_1, SPV_ENV_UNIVERSAL_1_6, vulkan_spirv, true),
std::make_tuple(SPV_ENV_VULKAN_1_1, SPV_ENV_VULKAN_1_0, vulkan_spirv, false),
std::make_tuple(SPV_ENV_VULKAN_1_1, SPV_ENV_VULKAN_1_1, vulkan_spirv, true),
+ std::make_tuple(SPV_ENV_VULKAN_1_1, SPV_ENV_VULKAN_1_1_SPIRV_1_4, vulkan_spirv, true),
+ std::make_tuple(SPV_ENV_VULKAN_1_1, SPV_ENV_VULKAN_1_2, vulkan_spirv, true),
+ std::make_tuple(SPV_ENV_VULKAN_1_1, SPV_ENV_VULKAN_1_3, vulkan_spirv, true),
std::make_tuple(SPV_ENV_VULKAN_1_1, SPV_ENV_OPENGL_4_0, vulkan_spirv, false),
std::make_tuple(SPV_ENV_VULKAN_1_1, SPV_ENV_OPENGL_4_1, vulkan_spirv, false),
std::make_tuple(SPV_ENV_VULKAN_1_1, SPV_ENV_OPENGL_4_2, vulkan_spirv, false),
std::make_tuple(SPV_ENV_VULKAN_1_1, SPV_ENV_OPENGL_4_3, vulkan_spirv, false),
std::make_tuple(SPV_ENV_VULKAN_1_1, SPV_ENV_OPENGL_4_5, vulkan_spirv, false),
- std::make_tuple(SPV_ENV_VULKAN_1_1, SPV_ENV_VULKAN_1_1_SPIRV_1_4, vulkan_spirv, true)
+
+ std::make_tuple(SPV_ENV_VULKAN_1_1_SPIRV_1_4, SPV_ENV_UNIVERSAL_1_0, vulkan_spirv, false),
+ std::make_tuple(SPV_ENV_VULKAN_1_1_SPIRV_1_4, SPV_ENV_UNIVERSAL_1_1, vulkan_spirv, false),
+ std::make_tuple(SPV_ENV_VULKAN_1_1_SPIRV_1_4, SPV_ENV_UNIVERSAL_1_2, vulkan_spirv, false),
+ std::make_tuple(SPV_ENV_VULKAN_1_1_SPIRV_1_4, SPV_ENV_UNIVERSAL_1_3, vulkan_spirv, false),
+ std::make_tuple(SPV_ENV_VULKAN_1_1_SPIRV_1_4, SPV_ENV_UNIVERSAL_1_4, vulkan_spirv, true),
+ std::make_tuple(SPV_ENV_VULKAN_1_1_SPIRV_1_4, SPV_ENV_UNIVERSAL_1_5, vulkan_spirv, true),
+ std::make_tuple(SPV_ENV_VULKAN_1_1_SPIRV_1_4, SPV_ENV_UNIVERSAL_1_6, vulkan_spirv, true),
+ std::make_tuple(SPV_ENV_VULKAN_1_1_SPIRV_1_4, SPV_ENV_VULKAN_1_0, vulkan_spirv, false),
+ std::make_tuple(SPV_ENV_VULKAN_1_1_SPIRV_1_4, SPV_ENV_VULKAN_1_1, vulkan_spirv, false),
+ std::make_tuple(SPV_ENV_VULKAN_1_1_SPIRV_1_4, SPV_ENV_VULKAN_1_1_SPIRV_1_4, vulkan_spirv, true),
+ std::make_tuple(SPV_ENV_VULKAN_1_1_SPIRV_1_4, SPV_ENV_VULKAN_1_2, vulkan_spirv, true),
+ std::make_tuple(SPV_ENV_VULKAN_1_1_SPIRV_1_4, SPV_ENV_VULKAN_1_3, vulkan_spirv, true),
+ std::make_tuple(SPV_ENV_VULKAN_1_1_SPIRV_1_4, SPV_ENV_OPENGL_4_0, vulkan_spirv, false),
+ std::make_tuple(SPV_ENV_VULKAN_1_1_SPIRV_1_4, SPV_ENV_OPENGL_4_1, vulkan_spirv, false),
+ std::make_tuple(SPV_ENV_VULKAN_1_1_SPIRV_1_4, SPV_ENV_OPENGL_4_2, vulkan_spirv, false),
+ std::make_tuple(SPV_ENV_VULKAN_1_1_SPIRV_1_4, SPV_ENV_OPENGL_4_3, vulkan_spirv, false),
+ std::make_tuple(SPV_ENV_VULKAN_1_1_SPIRV_1_4, SPV_ENV_OPENGL_4_5, vulkan_spirv, false),
+
+ std::make_tuple(SPV_ENV_VULKAN_1_2, SPV_ENV_UNIVERSAL_1_0, vulkan_spirv, false),
+ std::make_tuple(SPV_ENV_VULKAN_1_2, SPV_ENV_UNIVERSAL_1_1, vulkan_spirv, false),
+ std::make_tuple(SPV_ENV_VULKAN_1_2, SPV_ENV_UNIVERSAL_1_2, vulkan_spirv, false),
+ std::make_tuple(SPV_ENV_VULKAN_1_2, SPV_ENV_UNIVERSAL_1_3, vulkan_spirv, false),
+ std::make_tuple(SPV_ENV_VULKAN_1_2, SPV_ENV_UNIVERSAL_1_4, vulkan_spirv, false),
+ std::make_tuple(SPV_ENV_VULKAN_1_2, SPV_ENV_UNIVERSAL_1_5, vulkan_spirv, true),
+ std::make_tuple(SPV_ENV_VULKAN_1_2, SPV_ENV_UNIVERSAL_1_6, vulkan_spirv, true),
+ std::make_tuple(SPV_ENV_VULKAN_1_2, SPV_ENV_VULKAN_1_0, vulkan_spirv, false),
+ std::make_tuple(SPV_ENV_VULKAN_1_2, SPV_ENV_VULKAN_1_1, vulkan_spirv, false),
+ std::make_tuple(SPV_ENV_VULKAN_1_2, SPV_ENV_VULKAN_1_1_SPIRV_1_4, vulkan_spirv, false),
+ std::make_tuple(SPV_ENV_VULKAN_1_2, SPV_ENV_VULKAN_1_2, vulkan_spirv, true),
+ std::make_tuple(SPV_ENV_VULKAN_1_2, SPV_ENV_VULKAN_1_3, vulkan_spirv, true),
+ std::make_tuple(SPV_ENV_VULKAN_1_2, SPV_ENV_OPENGL_4_0, vulkan_spirv, false),
+ std::make_tuple(SPV_ENV_VULKAN_1_2, SPV_ENV_OPENGL_4_1, vulkan_spirv, false),
+ std::make_tuple(SPV_ENV_VULKAN_1_2, SPV_ENV_OPENGL_4_2, vulkan_spirv, false),
+ std::make_tuple(SPV_ENV_VULKAN_1_2, SPV_ENV_OPENGL_4_3, vulkan_spirv, false),
+ std::make_tuple(SPV_ENV_VULKAN_1_2, SPV_ENV_OPENGL_4_5, vulkan_spirv, false),
+
+ std::make_tuple(SPV_ENV_VULKAN_1_3, SPV_ENV_UNIVERSAL_1_0, vulkan_spirv, false),
+ std::make_tuple(SPV_ENV_VULKAN_1_3, SPV_ENV_UNIVERSAL_1_1, vulkan_spirv, false),
+ std::make_tuple(SPV_ENV_VULKAN_1_3, SPV_ENV_UNIVERSAL_1_2, vulkan_spirv, false),
+ std::make_tuple(SPV_ENV_VULKAN_1_3, SPV_ENV_UNIVERSAL_1_3, vulkan_spirv, false),
+ std::make_tuple(SPV_ENV_VULKAN_1_3, SPV_ENV_UNIVERSAL_1_4, vulkan_spirv, false),
+ std::make_tuple(SPV_ENV_VULKAN_1_3, SPV_ENV_UNIVERSAL_1_5, vulkan_spirv, false),
+ std::make_tuple(SPV_ENV_VULKAN_1_3, SPV_ENV_UNIVERSAL_1_6, vulkan_spirv, true),
+ std::make_tuple(SPV_ENV_VULKAN_1_3, SPV_ENV_VULKAN_1_0, vulkan_spirv, false),
+ std::make_tuple(SPV_ENV_VULKAN_1_3, SPV_ENV_VULKAN_1_1, vulkan_spirv, false),
+ std::make_tuple(SPV_ENV_VULKAN_1_3, SPV_ENV_VULKAN_1_1_SPIRV_1_4, vulkan_spirv, false),
+ std::make_tuple(SPV_ENV_VULKAN_1_3, SPV_ENV_VULKAN_1_2, vulkan_spirv, false),
+ std::make_tuple(SPV_ENV_VULKAN_1_3, SPV_ENV_VULKAN_1_3, vulkan_spirv, true),
+ std::make_tuple(SPV_ENV_VULKAN_1_3, SPV_ENV_OPENGL_4_0, vulkan_spirv, false),
+ std::make_tuple(SPV_ENV_VULKAN_1_3, SPV_ENV_OPENGL_4_1, vulkan_spirv, false),
+ std::make_tuple(SPV_ENV_VULKAN_1_3, SPV_ENV_OPENGL_4_2, vulkan_spirv, false),
+ std::make_tuple(SPV_ENV_VULKAN_1_3, SPV_ENV_OPENGL_4_3, vulkan_spirv, false),
+ std::make_tuple(SPV_ENV_VULKAN_1_3, SPV_ENV_OPENGL_4_5, vulkan_spirv, false)
)
);
@@ -187,6 +335,9 @@
std::make_tuple(SPV_ENV_OPENCL_2_0, SPV_ENV_UNIVERSAL_1_1, opencl_spirv, true),
std::make_tuple(SPV_ENV_OPENCL_2_0, SPV_ENV_UNIVERSAL_1_2, opencl_spirv, true),
std::make_tuple(SPV_ENV_OPENCL_2_0, SPV_ENV_UNIVERSAL_1_3, opencl_spirv, true),
+ std::make_tuple(SPV_ENV_OPENCL_2_0, SPV_ENV_UNIVERSAL_1_4, opencl_spirv, true),
+ std::make_tuple(SPV_ENV_OPENCL_2_0, SPV_ENV_UNIVERSAL_1_5, opencl_spirv, true),
+ std::make_tuple(SPV_ENV_OPENCL_2_0, SPV_ENV_UNIVERSAL_1_6, opencl_spirv, true),
std::make_tuple(SPV_ENV_OPENCL_2_0, SPV_ENV_OPENCL_2_0, opencl_spirv, true),
std::make_tuple(SPV_ENV_OPENCL_2_0, SPV_ENV_OPENCL_2_1, opencl_spirv, true),
std::make_tuple(SPV_ENV_OPENCL_2_0, SPV_ENV_OPENCL_2_2, opencl_spirv, true),
@@ -199,6 +350,9 @@
std::make_tuple(SPV_ENV_OPENCL_2_1, SPV_ENV_UNIVERSAL_1_1, opencl_spirv, true),
std::make_tuple(SPV_ENV_OPENCL_2_1, SPV_ENV_UNIVERSAL_1_2, opencl_spirv, true),
std::make_tuple(SPV_ENV_OPENCL_2_1, SPV_ENV_UNIVERSAL_1_3, opencl_spirv, true),
+ std::make_tuple(SPV_ENV_OPENCL_2_1, SPV_ENV_UNIVERSAL_1_4, opencl_spirv, true),
+ std::make_tuple(SPV_ENV_OPENCL_2_1, SPV_ENV_UNIVERSAL_1_5, opencl_spirv, true),
+ std::make_tuple(SPV_ENV_OPENCL_2_1, SPV_ENV_UNIVERSAL_1_6, opencl_spirv, true),
std::make_tuple(SPV_ENV_OPENCL_2_1, SPV_ENV_OPENCL_2_0, opencl_spirv, true),
std::make_tuple(SPV_ENV_OPENCL_2_1, SPV_ENV_OPENCL_2_1, opencl_spirv, true),
std::make_tuple(SPV_ENV_OPENCL_2_1, SPV_ENV_OPENCL_2_2, opencl_spirv, true),
@@ -211,6 +365,9 @@
std::make_tuple(SPV_ENV_OPENCL_2_2, SPV_ENV_UNIVERSAL_1_1, opencl_spirv, false),
std::make_tuple(SPV_ENV_OPENCL_2_2, SPV_ENV_UNIVERSAL_1_2, opencl_spirv, true),
std::make_tuple(SPV_ENV_OPENCL_2_2, SPV_ENV_UNIVERSAL_1_3, opencl_spirv, true),
+ std::make_tuple(SPV_ENV_OPENCL_2_2, SPV_ENV_UNIVERSAL_1_4, opencl_spirv, true),
+ std::make_tuple(SPV_ENV_OPENCL_2_2, SPV_ENV_UNIVERSAL_1_5, opencl_spirv, true),
+ std::make_tuple(SPV_ENV_OPENCL_2_2, SPV_ENV_UNIVERSAL_1_6, opencl_spirv, true),
std::make_tuple(SPV_ENV_OPENCL_2_2, SPV_ENV_OPENCL_2_0, opencl_spirv, false),
std::make_tuple(SPV_ENV_OPENCL_2_2, SPV_ENV_OPENCL_2_1, opencl_spirv, false),
std::make_tuple(SPV_ENV_OPENCL_2_2, SPV_ENV_OPENCL_2_2, opencl_spirv, true),
@@ -223,6 +380,9 @@
std::make_tuple(SPV_ENV_OPENCL_1_2, SPV_ENV_UNIVERSAL_1_1, opencl_spirv, true),
std::make_tuple(SPV_ENV_OPENCL_1_2, SPV_ENV_UNIVERSAL_1_2, opencl_spirv, true),
std::make_tuple(SPV_ENV_OPENCL_1_2, SPV_ENV_UNIVERSAL_1_3, opencl_spirv, true),
+ std::make_tuple(SPV_ENV_OPENCL_1_2, SPV_ENV_UNIVERSAL_1_4, opencl_spirv, true),
+ std::make_tuple(SPV_ENV_OPENCL_1_2, SPV_ENV_UNIVERSAL_1_5, opencl_spirv, true),
+ std::make_tuple(SPV_ENV_OPENCL_1_2, SPV_ENV_UNIVERSAL_1_6, opencl_spirv, true),
std::make_tuple(SPV_ENV_OPENCL_1_2, SPV_ENV_OPENCL_2_0, opencl_spirv, true),
std::make_tuple(SPV_ENV_OPENCL_1_2, SPV_ENV_OPENCL_2_1, opencl_spirv, true),
std::make_tuple(SPV_ENV_OPENCL_1_2, SPV_ENV_OPENCL_2_2, opencl_spirv, true),
diff --git a/third_party/SPIRV-Tools/tools/CMakeLists.txt b/third_party/SPIRV-Tools/tools/CMakeLists.txt
index 6039089..86d0bc4 100644
--- a/third_party/SPIRV-Tools/tools/CMakeLists.txt
+++ b/third_party/SPIRV-Tools/tools/CMakeLists.txt
@@ -41,10 +41,11 @@
if (NOT ${SPIRV_SKIP_EXECUTABLES})
add_spvtools_tool(TARGET spirv-as SRCS as/as.cpp LIBS ${SPIRV_TOOLS_FULL_VISIBILITY})
+ add_spvtools_tool(TARGET spirv-diff SRCS diff/diff.cpp util/cli_consumer.cpp LIBS SPIRV-Tools-diff SPIRV-Tools-opt ${SPIRV_TOOLS_FULL_VISIBILITY})
add_spvtools_tool(TARGET spirv-dis SRCS dis/dis.cpp LIBS ${SPIRV_TOOLS_FULL_VISIBILITY})
add_spvtools_tool(TARGET spirv-val SRCS val/val.cpp util/cli_consumer.cpp LIBS ${SPIRV_TOOLS_FULL_VISIBILITY})
add_spvtools_tool(TARGET spirv-opt SRCS opt/opt.cpp util/cli_consumer.cpp LIBS SPIRV-Tools-opt ${SPIRV_TOOLS_FULL_VISIBILITY})
- if (NOT DEFINED IOS_PLATFORM) # iOS does not allow std::system calls which spirv-reduce requires
+ if(NOT (${CMAKE_SYSTEM_NAME} STREQUAL "iOS")) # iOS does not allow std::system calls which spirv-reduce requires
add_spvtools_tool(TARGET spirv-reduce SRCS reduce/reduce.cpp util/cli_consumer.cpp LIBS SPIRV-Tools-reduce ${SPIRV_TOOLS_FULL_VISIBILITY})
endif()
add_spvtools_tool(TARGET spirv-link SRCS link/linker.cpp LIBS SPIRV-Tools-link ${SPIRV_TOOLS_FULL_VISIBILITY})
@@ -58,7 +59,7 @@
${SPIRV_HEADER_INCLUDE_DIR})
set(SPIRV_INSTALL_TARGETS spirv-as spirv-dis spirv-val spirv-opt
spirv-cfg spirv-link spirv-lint)
- if(NOT DEFINED IOS_PLATFORM)
+ if(NOT (${CMAKE_SYSTEM_NAME} STREQUAL "iOS"))
set(SPIRV_INSTALL_TARGETS ${SPIRV_INSTALL_TARGETS} spirv-reduce)
endif()
@@ -68,9 +69,6 @@
endif(SPIRV_BUILD_FUZZER)
if(ENABLE_SPIRV_TOOLS_INSTALL)
- install(TARGETS ${SPIRV_INSTALL_TARGETS}
- RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
- LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
- ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
+ install(TARGETS ${SPIRV_INSTALL_TARGETS} DESTINATION ${CMAKE_INSTALL_BINDIR})
endif(ENABLE_SPIRV_TOOLS_INSTALL)
endif()
diff --git a/third_party/SPIRV-Tools/tools/as/as.cpp b/third_party/SPIRV-Tools/tools/as/as.cpp
index c8a4445..506b058 100644
--- a/third_party/SPIRV-Tools/tools/as/as.cpp
+++ b/third_party/SPIRV-Tools/tools/as/as.cpp
@@ -48,7 +48,7 @@
argv0, argv0, target_env_list.c_str());
}
-static const auto kDefaultEnvironment = SPV_ENV_UNIVERSAL_1_5;
+static const auto kDefaultEnvironment = SPV_ENV_UNIVERSAL_1_6;
int main(int argc, char** argv) {
const char* inFile = nullptr;
diff --git a/third_party/SPIRV-Tools/tools/cfg/bin_to_dot.cpp b/third_party/SPIRV-Tools/tools/cfg/bin_to_dot.cpp
index 2561eea..72e7693 100644
--- a/third_party/SPIRV-Tools/tools/cfg/bin_to_dot.cpp
+++ b/third_party/SPIRV-Tools/tools/cfg/bin_to_dot.cpp
@@ -57,13 +57,13 @@
// Ends processing for the current block, emitting its dot code.
void FlushBlock(const std::vector<uint32_t>& successors);
- // The ID of the current functio, or 0 if outside of a function.
+ // The ID of the current function, or 0 if outside of a function.
uint32_t current_function_id_ = 0;
// The ID of the current basic block, or 0 if outside of a block.
uint32_t current_block_id_ = 0;
- // Have we completed processing for the entry block to this fuction?
+ // Have we completed processing for the entry block to this function?
bool seen_function_entry_block_ = false;
// The Id of the merge block for this block if it exists, or 0 otherwise.
diff --git a/third_party/SPIRV-Tools/tools/cfg/bin_to_dot.h b/third_party/SPIRV-Tools/tools/cfg/bin_to_dot.h
index 4de2e07..a61c975 100644
--- a/third_party/SPIRV-Tools/tools/cfg/bin_to_dot.h
+++ b/third_party/SPIRV-Tools/tools/cfg/bin_to_dot.h
@@ -20,7 +20,7 @@
#include "spirv-tools/libspirv.h"
// Dumps the control flow graph for the given module to the output stream.
-// Returns SPV_SUCCESS on succes.
+// Returns SPV_SUCCESS on success.
spv_result_t BinaryToDot(const spv_const_context context, const uint32_t* words,
size_t num_words, std::iostream* out,
spv_diagnostic* diagnostic);
diff --git a/third_party/SPIRV-Tools/tools/cfg/cfg.cpp b/third_party/SPIRV-Tools/tools/cfg/cfg.cpp
index 6a5faa1..5380c21 100644
--- a/third_party/SPIRV-Tools/tools/cfg/cfg.cpp
+++ b/third_party/SPIRV-Tools/tools/cfg/cfg.cpp
@@ -44,7 +44,7 @@
argv0, argv0);
}
-static const auto kDefaultEnvironment = SPV_ENV_UNIVERSAL_1_5;
+static const auto kDefaultEnvironment = SPV_ENV_UNIVERSAL_1_6;
int main(int argc, char** argv) {
const char* inFile = nullptr;
diff --git a/third_party/SPIRV-Tools/tools/diff/diff.cpp b/third_party/SPIRV-Tools/tools/diff/diff.cpp
new file mode 100644
index 0000000..d3cad04
--- /dev/null
+++ b/third_party/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;
+}
diff --git a/third_party/SPIRV-Tools/tools/fuzz/fuzz.cpp b/third_party/SPIRV-Tools/tools/fuzz/fuzz.cpp
index 306f925..ca6633a 100644
--- a/third_party/SPIRV-Tools/tools/fuzz/fuzz.cpp
+++ b/third_party/SPIRV-Tools/tools/fuzz/fuzz.cpp
@@ -673,19 +673,6 @@
transformations_file.close();
}
-// The Chromium project applies the following patch to the protobuf library:
-//
-// source.chromium.org/chromium/chromium/src/+/main:third_party/protobuf/patches/0003-remove-static-initializers.patch
-//
-// This affects how Status objects must be constructed. This method provides a
-// convenient way to get the OK status that works both with and without the
-// patch. With the patch OK is a StatusPod, from which a Status can be
-// constructed. Without the patch, OK is already a Status, and we harmlessly
-// copy-construct the result from it.
-google::protobuf::util::Status GetProtobufOkStatus() {
- return google::protobuf::util::Status(google::protobuf::util::Status::OK);
-}
-
// Dumps |transformations| to file |filename| in JSON format. Useful for
// interactive debugging.
void DumpTransformationsJson(
@@ -696,7 +683,7 @@
json_options.add_whitespace = true;
auto json_generation_status = google::protobuf::util::MessageToJsonString(
transformations, &json_string, json_options);
- if (json_generation_status == GetProtobufOkStatus()) {
+ if (json_generation_status.ok()) {
std::ofstream transformations_json_file(filename);
transformations_json_file << json_string;
transformations_json_file.close();
@@ -747,8 +734,9 @@
std::string facts_json_string((std::istreambuf_iterator<char>(facts_input)),
std::istreambuf_iterator<char>());
facts_input.close();
- if (GetProtobufOkStatus() != google::protobuf::util::JsonStringToMessage(
- facts_json_string, &initial_facts)) {
+ if (!google::protobuf::util::JsonStringToMessage(facts_json_string,
+ &initial_facts)
+ .ok()) {
spvtools::Error(FuzzDiagnostic, nullptr, {}, "Error reading facts data");
return 1;
}
@@ -828,7 +816,7 @@
json_options.add_whitespace = true;
auto json_generation_status = google::protobuf::util::MessageToJsonString(
transformations_applied, &json_string, json_options);
- if (json_generation_status != GetProtobufOkStatus()) {
+ if (!json_generation_status.ok()) {
spvtools::Error(FuzzDiagnostic, nullptr, {},
"Error writing out transformations in JSON format");
return 1;
diff --git a/third_party/SPIRV-Tools/tools/link/linker.cpp b/third_party/SPIRV-Tools/tools/link/linker.cpp
index 359e803..bdddeb8 100644
--- a/third_party/SPIRV-Tools/tools/link/linker.cpp
+++ b/third_party/SPIRV-Tools/tools/link/linker.cpp
@@ -25,7 +25,7 @@
namespace {
-const auto kDefaultEnvironment = SPV_ENV_UNIVERSAL_1_5;
+const auto kDefaultEnvironment = SPV_ENV_UNIVERSAL_1_6;
void print_usage(const char* program) {
std::string target_env_list = spvTargetEnvList(16, 80);
@@ -49,15 +49,18 @@
--create-library
Link the binaries into a library, keeping all exported symbols.
-h, --help
- Print this help.
+ Print this help.
--target-env <env>
- Set the target environment. Without this flag the target
- environment defaults to spv1.5. <env> must be one of
- {%s}
+ Set the environment used for interpreting the inputs. Without
+ this option the environment defaults to spv1.6. <env> must be
+ one of {%s}.
+ NOTE: The SPIR-V version used by the linked binary module
+ depends only on the version of the inputs, and is not affected
+ by this option.
--verify-ids
Verify that IDs in the resulting modules are truly unique.
--version
- Display linker version information
+ Display linker version information.
)",
program, program, target_env_list.c_str());
}
@@ -160,10 +163,11 @@
std::vector<uint32_t> linkingResult;
spv_result_t status = Link(context, contents, &linkingResult, options);
+ if (status != SPV_SUCCESS && status != SPV_WARNING) return 1;
if (!WriteFile<uint32_t>(outFile, "wb", linkingResult.data(),
linkingResult.size()))
return 1;
- return status == SPV_SUCCESS ? 0 : 1;
+ return 0;
}
diff --git a/third_party/SPIRV-Tools/tools/lint/lint.cpp b/third_party/SPIRV-Tools/tools/lint/lint.cpp
index 5c2a82a..d37df83 100644
--- a/third_party/SPIRV-Tools/tools/lint/lint.cpp
+++ b/third_party/SPIRV-Tools/tools/lint/lint.cpp
@@ -19,7 +19,7 @@
#include "tools/io.h"
#include "tools/util/cli_consumer.h"
-const auto kDefaultEnvironment = SPV_ENV_UNIVERSAL_1_5;
+const auto kDefaultEnvironment = SPV_ENV_UNIVERSAL_1_6;
namespace {
// Status and actions to perform after parsing command-line arguments.
diff --git a/third_party/SPIRV-Tools/tools/opt/opt.cpp b/third_party/SPIRV-Tools/tools/opt/opt.cpp
index 04f81b8..63511a6 100644
--- a/third_party/SPIRV-Tools/tools/opt/opt.cpp
+++ b/third_party/SPIRV-Tools/tools/opt/opt.cpp
@@ -44,7 +44,7 @@
// initialization and setup. Note that |source| and |position| are irrelevant
// here because we are still not processing a SPIR-V input file.
void opt_diagnostic(spv_message_level_t level, const char* /*source*/,
- const spv_position_t& /*positon*/, const char* message) {
+ const spv_position_t& /*position*/, const char* message) {
if (level == SPV_MSG_ERROR) {
fprintf(stderr, "error: ");
}
@@ -59,7 +59,7 @@
return ss.str();
}
-const auto kDefaultEnvironment = SPV_ENV_UNIVERSAL_1_5;
+const auto kDefaultEnvironment = SPV_ENV_UNIVERSAL_1_6;
std::string GetLegalizationPasses() {
spvtools::Optimizer optimizer(kDefaultEnvironment);
@@ -168,6 +168,16 @@
with a switch that has a case for every possible value of the
index.)");
printf(R"(
+ --spread-volatile-semantics
+ Spread Volatile semantics to variables with SMIDNV, WarpIDNV,
+ SubgroupSize, SubgroupLocalInvocationId, SubgroupEqMask,
+ SubgroupGeMask, SubgroupGtMask, SubgroupLeMask, or SubgroupLtMask
+ BuiltIn decorations or OpLoad for them when the shader model is
+ ray generation, closest hit, miss, intersection, or callable.
+ For the SPIR-V version is 1.6 or above, it also spreads Volatile
+ semantics to a variable with HelperInvocation BuiltIn decoration
+ in the fragement shader.)");
+ printf(R"(
--descriptor-scalar-replacement
Replaces every array variable |desc| that has a DescriptorSet
and Binding decorations with a new variable for each element of
@@ -479,10 +489,13 @@
--strip-debug
Remove all debug instructions.)");
printf(R"(
+ --strip-nonsemantic
+ Remove all reflection and nonsemantic information.)");
+ printf(R"(
--strip-reflect
- Remove all reflection information. For now, this covers
- reflection information defined by SPV_GOOGLE_hlsl_functionality1
- and SPV_KHR_non_semantic_info)");
+ DEPRECATED. Remove all reflection information. For now, this
+ covers reflection information defined by
+ SPV_GOOGLE_hlsl_functionality1 and SPV_KHR_non_semantic_info)");
printf(R"(
--target-env=<env>
Set the target environment. Without this flag the target
diff --git a/third_party/SPIRV-Tools/tools/reduce/reduce.cpp b/third_party/SPIRV-Tools/tools/reduce/reduce.cpp
index 4447b35..3760054 100644
--- a/third_party/SPIRV-Tools/tools/reduce/reduce.cpp
+++ b/third_party/SPIRV-Tools/tools/reduce/reduce.cpp
@@ -262,7 +262,7 @@
DumpShader(binary, filename);
}
-const auto kDefaultEnvironment = SPV_ENV_UNIVERSAL_1_5;
+const auto kDefaultEnvironment = SPV_ENV_UNIVERSAL_1_6;
int main(int argc, const char** argv) {
std::string in_binary_file;
diff --git a/third_party/SPIRV-Tools/tools/sva/README.md b/third_party/SPIRV-Tools/tools/sva/README.md
index d80b4d2..cd3d13c 100644
--- a/third_party/SPIRV-Tools/tools/sva/README.md
+++ b/third_party/SPIRV-Tools/tools/sva/README.md
@@ -1,6 +1,6 @@
# SVA
-SPIR-V Assember for WebGPU. The SPIR-V Assembler is a JavaScript library to
+SPIR-V Assembler for WebGPU. The SPIR-V Assembler is a JavaScript library to
convert SPIR-V assembly (as produced by spirv-dis in SPIR-V Tools) into a
SPIR-V binary. The assembler assumes it is generating WebGPU SPIR-V and thus has
the following limitations.
diff --git a/third_party/SPIRV-Tools/tools/sva/yarn.lock b/third_party/SPIRV-Tools/tools/sva/yarn.lock
index afa11f6..e7b735e 100644
--- a/third_party/SPIRV-Tools/tools/sva/yarn.lock
+++ b/third_party/SPIRV-Tools/tools/sva/yarn.lock
@@ -1260,9 +1260,9 @@
integrity sha512-gu9bD6Ta5bwGrrU8muHzVOBFFREpp2iRkVfhBJahwJ6p6Xw20SjT0MxLnwkjOibQmGSYhiUnf2FLe7k+jcFmGQ==
pathval@^1.1.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.0.tgz#b942e6d4bde653005ef6b71361def8727d0645e0"
- integrity sha1-uULm1L3mUwBe9rcTYd74cn0GReA=
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.1.tgz#8534e77a77ce7ac5a2512ea21e0fdb8fcf6c3d8d"
+ integrity sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==
prelude-ls@~1.1.2:
version "1.1.2"
diff --git a/third_party/SPIRV-Tools/tools/val/val.cpp b/third_party/SPIRV-Tools/tools/val/val.cpp
index 55321da..880ce46 100644
--- a/third_party/SPIRV-Tools/tools/val/val.cpp
+++ b/third_party/SPIRV-Tools/tools/val/val.cpp
@@ -77,7 +77,7 @@
int main(int argc, char** argv) {
const char* inFile = nullptr;
- spv_target_env target_env = SPV_ENV_UNIVERSAL_1_5;
+ spv_target_env target_env = SPV_ENV_UNIVERSAL_1_6;
spvtools::ValidatorOptions options;
bool continue_processing = true;
int return_code = 0;
@@ -111,17 +111,20 @@
printf("%s\n", spvSoftwareVersionDetailsString());
printf(
"Targets:\n %s\n %s\n %s\n %s\n %s\n %s\n %s\n %s\n %s\n "
- "%s\n",
+ "%s\n %s\n %s\n %s\n",
spvTargetEnvDescription(SPV_ENV_UNIVERSAL_1_0),
spvTargetEnvDescription(SPV_ENV_UNIVERSAL_1_1),
spvTargetEnvDescription(SPV_ENV_UNIVERSAL_1_2),
spvTargetEnvDescription(SPV_ENV_UNIVERSAL_1_3),
spvTargetEnvDescription(SPV_ENV_UNIVERSAL_1_4),
spvTargetEnvDescription(SPV_ENV_UNIVERSAL_1_5),
+ spvTargetEnvDescription(SPV_ENV_UNIVERSAL_1_6),
spvTargetEnvDescription(SPV_ENV_OPENCL_2_2),
spvTargetEnvDescription(SPV_ENV_VULKAN_1_0),
spvTargetEnvDescription(SPV_ENV_VULKAN_1_1),
- spvTargetEnvDescription(SPV_ENV_VULKAN_1_1_SPIRV_1_4));
+ spvTargetEnvDescription(SPV_ENV_VULKAN_1_1_SPIRV_1_4),
+ spvTargetEnvDescription(SPV_ENV_VULKAN_1_2),
+ spvTargetEnvDescription(SPV_ENV_VULKAN_1_3));
continue_processing = false;
return_code = 0;
} else if (0 == strcmp(cur_arg, "--help") || 0 == strcmp(cur_arg, "-h")) {
diff --git a/third_party/SPIRV-Tools/utils/check_copyright.py b/third_party/SPIRV-Tools/utils/check_copyright.py
index 49892ee..aa647af 100755
--- a/third_party/SPIRV-Tools/utils/check_copyright.py
+++ b/third_party/SPIRV-Tools/utils/check_copyright.py
@@ -14,6 +14,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
"""Checks for copyright notices in all the files that need them under the
+
current directory. Optionally insert them. When inserting, replaces
an MIT or Khronos free use license with Apache 2.
"""
@@ -41,11 +42,28 @@
'Mostafa Ashraf',
'Shiyu Liu',
'ZHOU He']
-CURRENT_YEAR='2021'
+CURRENT_YEAR = 2022
-YEARS = '(2014-2016|2015-2016|2015-2020|2016|2016-2017|2017|2017-2019|2018|2019|2020|2021)'
-COPYRIGHT_RE = re.compile(
- 'Copyright \(c\) {} ({})'.format(YEARS, '|'.join(AUTHORS)))
+FIRST_YEAR = 2014
+FINAL_YEAR = CURRENT_YEAR + 5
+# A regular expression to match the valid years in the copyright information.
+YEAR_REGEX = '(' + '|'.join(
+ str(year) for year in range(FIRST_YEAR, FINAL_YEAR + 1)) + ')'
+
+# A regular expression to make a range of years in the form <year1>-<year2>.
+YEAR_RANGE_REGEX = '('
+for year1 in range(FIRST_YEAR, FINAL_YEAR + 1):
+ for year2 in range(year1 + 1, FINAL_YEAR + 1):
+ YEAR_RANGE_REGEX += str(year1) + '-' + str(year2) + '|'
+YEAR_RANGE_REGEX = YEAR_RANGE_REGEX[:-1] + ')'
+
+# In the copyright info, the year can be a single year or a range. This is a
+# regex to make sure it matches one of them.
+YEAR_OR_RANGE_REGEX = '(' + YEAR_REGEX + '|' + YEAR_RANGE_REGEX + ')'
+
+# The final regular expression to match a valid copyright line.
+COPYRIGHT_RE = re.compile('Copyright \(c\) {} ({})'.format(
+ YEAR_OR_RANGE_REGEX, '|'.join(AUTHORS)))
MIT_BEGIN_RE = re.compile('Permission is hereby granted, '
'free of charge, to any person obtaining a')
diff --git a/third_party/SPIRV-Tools/utils/generate_grammar_tables.py b/third_party/SPIRV-Tools/utils/generate_grammar_tables.py
index 9ccf410..74aa282 100755
--- a/third_party/SPIRV-Tools/utils/generate_grammar_tables.py
+++ b/third_party/SPIRV-Tools/utils/generate_grammar_tables.py
@@ -23,7 +23,7 @@
PYGEN_VARIABLE_PREFIX = 'pygen_variable'
# Extensions to recognize, but which don't necessarily come from the SPIR-V
-# core or KHR grammar files. Get this list from the SPIR-V registery web page.
+# core or KHR grammar files. Get this list from the SPIR-V registry web page.
# NOTE: Only put things on this list if it is not in those grammar files.
EXTENSIONS_FROM_SPIRV_REGISTRY_AND_NOT_FROM_GRAMMARS = """
SPV_AMD_gcn_shader
diff --git a/third_party/SPIRV-Tools/utils/git-sync-deps b/third_party/SPIRV-Tools/utils/git-sync-deps
index eecfbe9..7a7e606 100755
--- a/third_party/SPIRV-Tools/utils/git-sync-deps
+++ b/third_party/SPIRV-Tools/utils/git-sync-deps
@@ -168,7 +168,7 @@
with open(os.devnull, 'w') as devnull:
# If this fails, we will fetch before trying again. Don't spam user
- # with error infomation.
+ # with error information.
if 0 == subprocess.call([git, 'checkout', '--quiet', checkoutable],
cwd=directory, stderr=devnull):
# if this succeeds, skip slow `git fetch`.
diff --git a/third_party/SPIRV-Tools/utils/roll_deps.sh b/third_party/SPIRV-Tools/utils/roll_deps.sh
index f61f2a3..cef8b52 100755
--- a/third_party/SPIRV-Tools/utils/roll_deps.sh
+++ b/third_party/SPIRV-Tools/utils/roll_deps.sh
@@ -23,9 +23,9 @@
effcee_dir="external/effcee/"
effcee_trunk="origin/main"
googletest_dir="external/googletest/"
-googletest_trunk="origin/master"
+googletest_trunk="origin/main"
re2_dir="external/re2/"
-re2_trunk="origin/master"
+re2_trunk="origin/main"
spirv_headers_dir="external/spirv-headers/"
spirv_headers_trunk="origin/master"
@@ -41,6 +41,7 @@
old_head=$(git rev-parse HEAD)
+set +e
roll-dep --ignore-dirty-tree --roll-to="${effcee_trunk}" "${effcee_dir}"
roll-dep --ignore-dirty-tree --roll-to="${googletest_trunk}" "${googletest_dir}"
roll-dep --ignore-dirty-tree --roll-to="${re2_trunk}" "${re2_dir}"
diff --git a/third_party/SPIRV-Tools/utils/vscode/src/lsp/jsonrpc2/jsonrpc2.go b/third_party/SPIRV-Tools/utils/vscode/src/lsp/jsonrpc2/jsonrpc2.go
index b8436d2..44dd220 100644
--- a/third_party/SPIRV-Tools/utils/vscode/src/lsp/jsonrpc2/jsonrpc2.go
+++ b/third_party/SPIRV-Tools/utils/vscode/src/lsp/jsonrpc2/jsonrpc2.go
@@ -48,7 +48,7 @@
requestDone
)
-// Request is sent to a server to represent a Call or Notify operaton.
+// Request is sent to a server to represent a Call or Notify operation.
type Request struct {
conn *Conn
cancel context.CancelFunc
diff --git a/third_party/SPIRV-Tools/utils/vscode/src/lsp/jsonrpc2/wire.go b/third_party/SPIRV-Tools/utils/vscode/src/lsp/jsonrpc2/wire.go
index 3e31c34..fed9a25 100644
--- a/third_party/SPIRV-Tools/utils/vscode/src/lsp/jsonrpc2/wire.go
+++ b/third_party/SPIRV-Tools/utils/vscode/src/lsp/jsonrpc2/wire.go
@@ -44,7 +44,7 @@
CodeServerOverloaded = -32000
)
-// WireRequest is sent to a server to represent a Call or Notify operaton.
+// WireRequest is sent to a server to represent a Call or Notify operation.
type WireRequest struct {
// VersionTag is always encoded as the string "2.0"
VersionTag VersionTag `json:"jsonrpc"`
diff --git a/third_party/SPIRV-Tools/utils/vscode/src/lsp/protocol/tsprotocol.go b/third_party/SPIRV-Tools/utils/vscode/src/lsp/protocol/tsprotocol.go
index 50543fc..e0a3594 100644
--- a/third_party/SPIRV-Tools/utils/vscode/src/lsp/protocol/tsprotocol.go
+++ b/third_party/SPIRV-Tools/utils/vscode/src/lsp/protocol/tsprotocol.go
@@ -143,7 +143,7 @@
* change notifications.
*
* If a strings is provided the string is treated as a ID
- * under which the notification is registed on the client
+ * under which the notification is registered on the client
* side. The ID can be used to unregister for these events
* using the `client/unregisterCapability` request.
*/
@@ -162,7 +162,7 @@
/*Name defined:
* The name of the workspace folder. Used to refer to this
- * workspace folder in thge user interface.
+ * workspace folder in the user interface.
*/
Name string `json:"name"`
}
@@ -1129,7 +1129,7 @@
* change notifications.
*
* If a strings is provided the string is treated as a ID
- * under which the notification is registed on the client
+ * under which the notification is registered on the client
* side. The ID can be used to unregister for these events
* using the `client/unregisterCapability` request.
*/
@@ -1803,7 +1803,7 @@
/*AllCommitCharacters defined:
* The list of all possible characters that commit a completion. This field can be used
- * if clients don't support individual commmit characters per completion item. See
+ * if clients don't support individual commit characters per completion item. See
* `ClientCapabilities.textDocument.completion.completionItem.commitCharactersSupport`
*
* @since 3.2.0
@@ -2844,7 +2844,7 @@
/*TargetSelectionRange defined:
* The range that should be selected and revealed when this link is being followed, e.g the name of a function.
- * Must be contained by the the `targetRange`. See also `DocumentSymbol#range`
+ * Must be contained by the `targetRange`. See also `DocumentSymbol#range`
*/
TargetSelectionRange Range `json:"targetSelectionRange"`
}
@@ -2881,7 +2881,7 @@
type ColorInformation struct {
/*Range defined:
- * The range in the document where this color appers.
+ * The range in the document where this color appears.
*/
Range Range `json:"range"`
@@ -3627,14 +3627,14 @@
/*Range defined:
* The range enclosing this symbol not including leading/trailing whitespace but everything else
- * like comments. This information is typically used to determine if the the clients cursor is
+ * like comments. This information is typically used to determine if the clients cursor is
* inside the symbol to reveal in the symbol in the UI.
*/
Range Range `json:"range"`
/*SelectionRange defined:
* The range that should be selected and revealed when this symbol is being picked, e.g the name of a function.
- * Must be contained by the the `range`.
+ * Must be contained by the `range`.
*/
SelectionRange Range `json:"selectionRange"`
@@ -3652,7 +3652,7 @@
/*Diagnostics defined:
* An array of diagnostics known on the client side overlapping the range provided to the
- * `textDocument/codeAction` request. They are provied so that the server knows which
+ * `textDocument/codeAction` request. They are provided so that the server knows which
* errors are currently presented to the user for the given range. There is no guarantee
* that these accurately reflect the error state of the resource. The primary parameter
* to compute code actions is the provided range.
@@ -4081,13 +4081,13 @@
/*TextOnlyTransactional defined:
* If the workspace edit contains only textual file changes they are executed transactional.
* If resource changes (create, rename or delete file) are part of the change the failure
- * handling startegy is abort.
+ * handling strategy is abort.
*/
TextOnlyTransactional FailureHandlingKind = "textOnlyTransactional"
/*Undo defined:
* The client tries to undo the operations already executed. But there is no
- * guaruntee that this is succeeding.
+ * guarantee that this is succeeding.
*/
Undo FailureHandlingKind = "undo"
diff --git a/third_party/SPIRV-Tools/utils/vscode/src/parser/parser.go b/third_party/SPIRV-Tools/utils/vscode/src/parser/parser.go
index cc6f333..4c0fa8f 100644
--- a/third_party/SPIRV-Tools/utils/vscode/src/parser/parser.go
+++ b/third_party/SPIRV-Tools/utils/vscode/src/parser/parser.go
@@ -798,7 +798,7 @@
References []*Token // all the places the identifier was referenced
}
-// Severity is an enumerator of diagnositc seeverities
+// Severity is an enumerator of diagnostic severities
type Severity int
// Severity levels