From 7fa9e746ef815b27f7747c9bab2689c113fb33d9 Mon Sep 17 00:00:00 2001 From: Shahbaz Youssefi Date: Wed, 2 Feb 2022 10:33:18 -0500 Subject: [PATCH] Introduce spirv-diff (#4611) spirv-diff is a new tool that produces diff-style output comparing two SPIR-V modules. 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, it's hard to match functions 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. This tool can be useful in a number of scenarios: - Compare the SPIR-V before and after modifying a shader - Compare the SPIR-V produced from a shader before and after compiler codegen changes. - Compare the SPIR-V produced from a shader before and after some transformation or optimization. - Compare the SPIR-V produced from a shader with different compilers. --- README.md | 27 + source/CMakeLists.txt | 1 + source/diff/CMakeLists.txt | 54 + source/diff/diff.cpp | 2658 +++++++++++++++++ source/diff/diff.h | 48 + source/diff/lcs.h | 195 ++ source/opt/instruction.h | 12 +- source/parsed_operand.cpp | 4 +- test/CMakeLists.txt | 1 + test/diff/CMakeLists.txt | 26 + test/diff/diff_files/.gitignore | 3 + .../OpExtInst_in_dst_only_autogen.cpp | 242 ++ .../OpExtInst_in_dst_only_dst.spvasm | 33 + .../OpExtInst_in_dst_only_src.spvasm | 33 + .../OpExtInst_in_src_only_autogen.cpp | 242 ++ .../OpExtInst_in_src_only_dst.spvasm | 30 + .../OpExtInst_in_src_only_src.spvasm | 36 + test/diff/diff_files/README.md | 17 + test/diff/diff_files/basic_autogen.cpp | 407 +++ test/diff/diff_files/basic_dst.spvasm | 49 + test/diff/diff_files/basic_src.spvasm | 50 + .../diff_files/diff_test_files_autogen.cmake | 35 + ...different_decorations_fragment_autogen.cpp | 1626 ++++++++++ .../different_decorations_fragment_dst.spvasm | 199 ++ .../different_decorations_fragment_src.spvasm | 198 ++ .../different_decorations_vertex_autogen.cpp | 1322 ++++++++ .../different_decorations_vertex_dst.spvasm | 159 + .../different_decorations_vertex_src.spvasm | 155 + .../diff_files/extra_if_block_autogen.cpp | 867 ++++++ .../diff/diff_files/extra_if_block_dst.spvasm | 136 + .../diff/diff_files/extra_if_block_src.spvasm | 137 + test/diff/diff_files/generate_tests.py | 304 ++ .../diff_files/index_signedness_autogen.cpp | 733 +++++ .../diff_files/index_signedness_dst.spvasm | 110 + .../diff_files/index_signedness_src.spvasm | 111 + .../int_vs_uint_constants_autogen.cpp | 396 +++ .../int_vs_uint_constants_dst.spvasm | 46 + .../int_vs_uint_constants_src.spvasm | 49 + .../large_functions_large_diffs_autogen.cpp | 1534 ++++++++++ .../large_functions_large_diffs_dst.spvasm | 213 ++ .../large_functions_large_diffs_src.spvasm | 230 ++ .../large_functions_small_diffs_autogen.cpp | 1364 +++++++++ .../large_functions_small_diffs_dst.spvasm | 229 ++ .../large_functions_small_diffs_src.spvasm | 226 ++ ...ultiple_different_entry_points_autogen.cpp | 330 ++ ...multiple_different_entry_points_dst.spvasm | 49 + ...multiple_different_entry_points_src.spvasm | 51 + .../multiple_same_entry_points_autogen.cpp | 375 +++ .../multiple_same_entry_points_dst.spvasm | 45 + .../multiple_same_entry_points_src.spvasm | 46 + .../reordered_if_blocks_autogen.cpp | 568 ++++ .../diff_files/reordered_if_blocks_dst.spvasm | 87 + .../diff_files/reordered_if_blocks_src.spvasm | 87 + .../reordered_switch_blocks_autogen.cpp | 582 ++++ .../reordered_switch_blocks_dst.spvasm | 91 + .../reordered_switch_blocks_src.spvasm | 92 + .../small_functions_small_diffs_autogen.cpp | 747 +++++ .../small_functions_small_diffs_dst.spvasm | 92 + .../small_functions_small_diffs_src.spvasm | 93 + .../diff_files/unrelated_shaders_autogen.cpp | 230 ++ .../diff_files/unrelated_shaders_dst.spvasm | 31 + .../diff_files/unrelated_shaders_src.spvasm | 25 + test/diff/diff_test.cpp | 228 ++ test/diff/diff_test_utils.cpp | 58 + test/diff/diff_test_utils.h | 30 + test/diff/lcs_test.cpp | 329 ++ tools/CMakeLists.txt | 1 + tools/diff/diff.cpp | 201 ++ 68 files changed, 19013 insertions(+), 2 deletions(-) create mode 100644 source/diff/CMakeLists.txt create mode 100644 source/diff/diff.cpp create mode 100644 source/diff/diff.h create mode 100644 source/diff/lcs.h create mode 100644 test/diff/CMakeLists.txt create mode 100644 test/diff/diff_files/.gitignore create mode 100644 test/diff/diff_files/OpExtInst_in_dst_only_autogen.cpp create mode 100644 test/diff/diff_files/OpExtInst_in_dst_only_dst.spvasm create mode 100644 test/diff/diff_files/OpExtInst_in_dst_only_src.spvasm create mode 100644 test/diff/diff_files/OpExtInst_in_src_only_autogen.cpp create mode 100644 test/diff/diff_files/OpExtInst_in_src_only_dst.spvasm create mode 100644 test/diff/diff_files/OpExtInst_in_src_only_src.spvasm create mode 100644 test/diff/diff_files/README.md create mode 100644 test/diff/diff_files/basic_autogen.cpp create mode 100644 test/diff/diff_files/basic_dst.spvasm create mode 100644 test/diff/diff_files/basic_src.spvasm create mode 100644 test/diff/diff_files/diff_test_files_autogen.cmake create mode 100644 test/diff/diff_files/different_decorations_fragment_autogen.cpp create mode 100644 test/diff/diff_files/different_decorations_fragment_dst.spvasm create mode 100644 test/diff/diff_files/different_decorations_fragment_src.spvasm create mode 100644 test/diff/diff_files/different_decorations_vertex_autogen.cpp create mode 100644 test/diff/diff_files/different_decorations_vertex_dst.spvasm create mode 100644 test/diff/diff_files/different_decorations_vertex_src.spvasm create mode 100644 test/diff/diff_files/extra_if_block_autogen.cpp create mode 100644 test/diff/diff_files/extra_if_block_dst.spvasm create mode 100644 test/diff/diff_files/extra_if_block_src.spvasm create mode 100755 test/diff/diff_files/generate_tests.py create mode 100644 test/diff/diff_files/index_signedness_autogen.cpp create mode 100644 test/diff/diff_files/index_signedness_dst.spvasm create mode 100644 test/diff/diff_files/index_signedness_src.spvasm create mode 100644 test/diff/diff_files/int_vs_uint_constants_autogen.cpp create mode 100644 test/diff/diff_files/int_vs_uint_constants_dst.spvasm create mode 100644 test/diff/diff_files/int_vs_uint_constants_src.spvasm create mode 100644 test/diff/diff_files/large_functions_large_diffs_autogen.cpp create mode 100644 test/diff/diff_files/large_functions_large_diffs_dst.spvasm create mode 100644 test/diff/diff_files/large_functions_large_diffs_src.spvasm create mode 100644 test/diff/diff_files/large_functions_small_diffs_autogen.cpp create mode 100644 test/diff/diff_files/large_functions_small_diffs_dst.spvasm create mode 100644 test/diff/diff_files/large_functions_small_diffs_src.spvasm create mode 100644 test/diff/diff_files/multiple_different_entry_points_autogen.cpp create mode 100644 test/diff/diff_files/multiple_different_entry_points_dst.spvasm create mode 100644 test/diff/diff_files/multiple_different_entry_points_src.spvasm create mode 100644 test/diff/diff_files/multiple_same_entry_points_autogen.cpp create mode 100644 test/diff/diff_files/multiple_same_entry_points_dst.spvasm create mode 100644 test/diff/diff_files/multiple_same_entry_points_src.spvasm create mode 100644 test/diff/diff_files/reordered_if_blocks_autogen.cpp create mode 100644 test/diff/diff_files/reordered_if_blocks_dst.spvasm create mode 100644 test/diff/diff_files/reordered_if_blocks_src.spvasm create mode 100644 test/diff/diff_files/reordered_switch_blocks_autogen.cpp create mode 100644 test/diff/diff_files/reordered_switch_blocks_dst.spvasm create mode 100644 test/diff/diff_files/reordered_switch_blocks_src.spvasm create mode 100644 test/diff/diff_files/small_functions_small_diffs_autogen.cpp create mode 100644 test/diff/diff_files/small_functions_small_diffs_dst.spvasm create mode 100644 test/diff/diff_files/small_functions_small_diffs_src.spvasm create mode 100644 test/diff/diff_files/unrelated_shaders_autogen.cpp create mode 100644 test/diff/diff_files/unrelated_shaders_dst.spvasm create mode 100644 test/diff/diff_files/unrelated_shaders_src.spvasm create mode 100644 test/diff/diff_test.cpp create mode 100644 test/diff/diff_test_utils.cpp create mode 100644 test/diff/diff_test_utils.h create mode 100644 test/diff/lcs_test.cpp create mode 100644 tools/diff/diff.cpp diff --git a/README.md b/README.md index 14db1e70..ad2af491 100644 --- a/README.md +++ b/README.md @@ -212,6 +212,24 @@ issue](https://github.com/KhronosGroup/SPIRV-Tools/issues]) with "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 @@ This is experimental. * `spirv-cfg` - the control flow graph dumper * `/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 + * ``/tools/diff` + ### Utility filters * `spirv-lesspipe.sh` - Automatically disassembles `.spv` binary files for the diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index 331ff675..41776c00 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -217,6 +217,7 @@ add_subdirectory(reduce) add_subdirectory(fuzz) add_subdirectory(link) add_subdirectory(lint) +add_subdirectory(diff) set(SPIRV_SOURCES ${spirv-tools_SOURCE_DIR}/include/spirv-tools/libspirv.h diff --git a/source/diff/CMakeLists.txt b/source/diff/CMakeLists.txt new file mode 100644 index 00000000..1328699a --- /dev/null +++ b/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 + $ + $ + $ + 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/source/diff/diff.cpp b/source/diff/diff.cpp new file mode 100644 index 00000000..f44a9ba1 --- /dev/null +++ b/source/diff/diff.cpp @@ -0,0 +1,2658 @@ +// 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; +// A map from an id to the instructions that decorate it, or name it, etc. +using IdToInfoMap = std::vector>; +// A map from an instruction to another, used for instructions without id. +using InstructionToInstructionMap = + std::unordered_map; +// A flat list of instructions in a function for easier iteration. +using InstructionList = std::vector; +// A map from a function to its list of instructions. +using FunctionInstMap = std::unordered_map; +// A list of ids with some similar property, for example functions with the same +// name. +using IdGroup = std::vector; +// 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; +using IdGroupMapByTypeId = std::map; + +// 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 src_ids; + std::vector dst_ids; +}; + +void CompactIds(std::vector& 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(id_map_.size()); } + + private: + // Given an id, returns the corresponding id in the other module, or 0 if not + // matched yet. + std::vector 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 section); + void MapIdsToInfos( + opt::IteratorRange 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 section, + std::vector& ids, + std::function filter, + std::function get_id); + void MatchIds( + PotentialIdMap& potential, + std::function + match); + // Helper functions that match id-less instructions between src and dst. + void MatchPreambleInstructions( + opt::IteratorRange src_insts, + opt::IteratorRange dst_insts); + InstructionList SortPreambleInstructions( + const opt::Module* module, + opt::IteratorRange 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 src_insts, + opt::IteratorRange 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 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; + + 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 + void GroupIds(const IdGroup& functions, bool is_src, + std::map* groups, + std::function 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 are_lines_identical, + std::function output_src_line, + std::function output_dst_line); + template + void OutputSection( + const InstList& src_insts, const InstList& dst_insts, + std::function + 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& parsed_operands, + std::vector& 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(id_map_.size()); + const uint32_t dst_id_bound = static_cast(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 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 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 section, + std::vector& ids, + std::function filter, + std::function 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 + 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 src_insts, + opt::IteratorRange 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 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 src_insts, + opt::IteratorRange 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 (IsConstantUint(src_id_to_, src_id) && + IsConstantUint(dst_id_to_, dst_id)) { + return GetConstantUint(src_id_to_, src_id) == + GetConstantUint(dst_id_to_, dst_id); + } + + 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::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 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 +void Differ::GroupIds( + const IdGroup& functions, bool is_src, std::map* groups, + std::function 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 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(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(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> lcs(src_body, + dst_body); + + size_t best_match_length = lcs.Get( + [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(best_match_length) * 2.0f / + static_cast(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>; + ExecutionModelMap src_entry_points_map; + ExecutionModelMap dst_entry_points_map; + std::set 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; + } + + return GetConstantUint(src_id_to_, + src_inst->GetInOperand(1).AsId()) == + GetConstantUint(dst_id_to_, dst_inst->GetInOperand(1).AsId()); + + 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: + // 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 SpvOpSpecConstantComposite: + 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 are_lines_identical, + std::function output_src_line, + std::function 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 +void Differ::OutputSection( + const InstList& src_insts, const InstList& dst_insts, + std::function + 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& parsed_operands, + std::vector& inst_binary) { + inst.ToBinaryWithoutAttachedDebugInsts(&inst_binary); + parsed_operands.resize(inst.NumOperands()); + + parsed_inst->words = inst_binary.data(); + parsed_inst->num_words = static_cast(inst_binary.size()); + parsed_inst->opcode = static_cast(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(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(offset); + parsed_operand.num_words = static_cast(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 parsed_operands; + std::vector 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/source/diff/diff.h b/source/diff/diff.h new file mode 100644 index 00000000..932de9ee --- /dev/null +++ b/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/source/diff/lcs.h b/source/diff/lcs.h new file mode 100644 index 00000000..486f43dc --- /dev/null +++ b/source/diff/lcs.h @@ -0,0 +1,195 @@ +// 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 +#include +#include +#include +#include + +namespace spvtools { +namespace diff { + +// The result of a diff. +using DiffMatch = std::vector; + +// Helper class to find the longest common subsequence between two function +// bodies. +template +class LongestCommonSubsequence { + public: + LongestCommonSubsequence(const Sequence& src, const Sequence& dst) + : src_(src), + dst_(dst), + table_(src.size(), std::vector(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 + size_t Get(std::function match, + DiffMatch* src_match_result, DiffMatch* dst_match_result); + + private: + template + size_t CalculateLCS(size_t src_start, size_t dst_start, + std::function match); + void RetrieveMatch(DiffMatch* src_match_result, DiffMatch* dst_match_result); + bool IsInBound(size_t src_index, size_t dst_index) { + return src_index < src_.size() && dst_index < dst_.size(); + } + bool IsCalculated(size_t src_index, size_t dst_index) { + assert(IsInBound(src_index, dst_index)); + return table_[src_index][dst_index].valid; + } + size_t GetMemoizedLength(size_t src_index, size_t dst_index) { + if (!IsInBound(src_index, dst_index)) { + return 0; + } + assert(IsCalculated(src_index, dst_index)); + return table_[src_index][dst_index].best_match_length; + } + bool IsMatched(size_t src_index, size_t dst_index) { + assert(IsCalculated(src_index, dst_index)); + return table_[src_index][dst_index].matched; + } + + const Sequence& src_; + const Sequence& dst_; + + struct DiffMatchEntry { + size_t best_match_length = 0; + // Whether src[i] and dst[j] matched. This is an optimization to avoid + // calling the `match` function again when walking the LCS table. + bool matched = false; + // Use for the recursive algorithm to know if the contents of this entry are + // valid. + bool valid = false; + }; + + std::vector> table_; +}; + +template +template +size_t LongestCommonSubsequence::Get( + std::function match, + DiffMatch* src_match_result, DiffMatch* dst_match_result) { + size_t best_match_length = CalculateLCS(0, 0, match); + RetrieveMatch(src_match_result, dst_match_result); + return best_match_length; +} + +template +template +size_t LongestCommonSubsequence::CalculateLCS( + size_t src_start, size_t dst_start, + std::function 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). + + // To avoid unnecessary recursion on long sequences, process a whole strip of + // matching elements in one go. + size_t src_cur = src_start; + size_t dst_cur = dst_start; + while (IsInBound(src_cur, dst_cur) && !IsCalculated(src_cur, dst_cur) && + match(src_[src_cur], dst_[dst_cur])) { + ++src_cur; + ++dst_cur; + } + + // We've reached a pair of elements that don't match. Recursively determine + // which one should be left unmatched. + size_t best_match_length = 0; + if (IsInBound(src_cur, dst_cur)) { + if (IsCalculated(src_cur, dst_cur)) { + best_match_length = GetMemoizedLength(src_cur, dst_cur); + } else { + best_match_length = std::max(CalculateLCS(src_cur + 1, dst_cur, match), + CalculateLCS(src_cur, dst_cur + 1, match)); + + // Fill the table with this information + DiffMatchEntry& entry = table_[src_cur][dst_cur]; + assert(!entry.valid); + entry.best_match_length = best_match_length; + entry.valid = true; + } + } + + // Go over the matched strip and update the table as well. + assert(src_cur - src_start == dst_cur - dst_start); + size_t contiguous_match_len = src_cur - src_start; + + for (size_t i = 0; i < contiguous_match_len; ++i) { + --src_cur; + --dst_cur; + assert(IsInBound(src_cur, dst_cur)); + + DiffMatchEntry& entry = table_[src_cur][dst_cur]; + assert(!entry.valid); + entry.best_match_length = ++best_match_length; + entry.matched = true; + entry.valid = true; + } + + return best_match_length; +} + +template +void LongestCommonSubsequence::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); + + size_t src_cur = 0; + size_t dst_cur = 0; + while (IsInBound(src_cur, dst_cur)) { + if (IsMatched(src_cur, dst_cur)) { + (*src_match_result)[src_cur++] = true; + (*dst_match_result)[dst_cur++] = true; + continue; + } + + if (GetMemoizedLength(src_cur + 1, dst_cur) >= + GetMemoizedLength(src_cur, dst_cur + 1)) { + ++src_cur; + } else { + ++dst_cur; + } + } +} + +} // namespace diff +} // namespace spvtools + +#endif // SOURCE_DIFF_LCS_H_ diff --git a/source/opt/instruction.h b/source/opt/instruction.h index f87f563a..066e9870 100644 --- a/source/opt/instruction.h +++ b/source/opt/instruction.h @@ -87,6 +87,12 @@ struct Operand { spv_operand_type_t type; // Type of this logical operand. OperandData words; // Binary segments of this logical operand. + 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 { assert(type == SPV_OPERAND_TYPE_LITERAL_STRING); @@ -95,7 +101,10 @@ struct Operand { // 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; @@ -294,6 +303,7 @@ class Instruction : public utils::IntrusiveNodeBase { 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/source/parsed_operand.cpp b/source/parsed_operand.cpp index 7ad369cd..5f8e94db 100644 --- a/source/parsed_operand.cpp +++ b/source/parsed_operand.cpp @@ -24,7 +24,9 @@ namespace spvtools { 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/test/CMakeLists.txt b/test/CMakeLists.txt index e88df04d..4ca8ef8f 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -185,6 +185,7 @@ add_spvtools_unittest( endif() +add_subdirectory(diff) add_subdirectory(link) add_subdirectory(lint) add_subdirectory(opt) diff --git a/test/diff/CMakeLists.txt b/test/diff/CMakeLists.txt new file mode 100644 index 00000000..811805bd --- /dev/null +++ b/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/test/diff/diff_files/.gitignore b/test/diff/diff_files/.gitignore new file mode 100644 index 00000000..727526ef --- /dev/null +++ b/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/test/diff/diff_files/OpExtInst_in_dst_only_autogen.cpp b/test/diff/diff_files/OpExtInst_in_dst_only_autogen.cpp new file mode 100644 index 00000000..ce899edd --- /dev/null +++ b/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/test/diff/diff_files/OpExtInst_in_dst_only_dst.spvasm b/test/diff/diff_files/OpExtInst_in_dst_only_dst.spvasm new file mode 100644 index 00000000..e599d1e9 --- /dev/null +++ b/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/test/diff/diff_files/OpExtInst_in_dst_only_src.spvasm b/test/diff/diff_files/OpExtInst_in_dst_only_src.spvasm new file mode 100644 index 00000000..9f6fc18c --- /dev/null +++ b/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/test/diff/diff_files/OpExtInst_in_src_only_autogen.cpp b/test/diff/diff_files/OpExtInst_in_src_only_autogen.cpp new file mode 100644 index 00000000..9944c2cf --- /dev/null +++ b/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/test/diff/diff_files/OpExtInst_in_src_only_dst.spvasm b/test/diff/diff_files/OpExtInst_in_src_only_dst.spvasm new file mode 100644 index 00000000..47233051 --- /dev/null +++ b/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/test/diff/diff_files/OpExtInst_in_src_only_src.spvasm b/test/diff/diff_files/OpExtInst_in_src_only_src.spvasm new file mode 100644 index 00000000..efb663a9 --- /dev/null +++ b/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/test/diff/diff_files/README.md b/test/diff/diff_files/README.md new file mode 100644 index 00000000..5dcee25a --- /dev/null +++ b/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/test/diff/diff_files/basic_autogen.cpp b/test/diff/diff_files/basic_autogen.cpp new file mode 100644 index 00000000..f3afc701 --- /dev/null +++ b/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/test/diff/diff_files/basic_dst.spvasm b/test/diff/diff_files/basic_dst.spvasm new file mode 100644 index 00000000..79cb8887 --- /dev/null +++ b/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/test/diff/diff_files/basic_src.spvasm b/test/diff/diff_files/basic_src.spvasm new file mode 100644 index 00000000..c55ec7af --- /dev/null +++ b/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/test/diff/diff_files/diff_test_files_autogen.cmake b/test/diff/diff_files/diff_test_files_autogen.cmake new file mode 100644 index 00000000..9c72448a --- /dev/null +++ b/test/diff/diff_files/diff_test_files_autogen.cmake @@ -0,0 +1,35 @@ +# 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/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/unrelated_shaders_autogen.cpp" +) diff --git a/test/diff/diff_files/different_decorations_fragment_autogen.cpp b/test/diff/diff_files/different_decorations_fragment_autogen.cpp new file mode 100644 index 00000000..d97a4d52 --- /dev/null +++ b/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 + %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 + %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 + %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 +)"; + 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 + %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 + %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 + %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 +)"; + 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 + %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 + %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 + %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 +)"; + 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 + %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 + %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 + %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 +)"; + Options options; + options.ignore_set_binding = true; + options.ignore_location = true; + DoStringDiffTest(kSrc, kDst, kDiff, options); +} + +} // namespace +} // namespace diff +} // namespace spvtools diff --git a/test/diff/diff_files/different_decorations_fragment_dst.spvasm b/test/diff/diff_files/different_decorations_fragment_dst.spvasm new file mode 100644 index 00000000..b5d1c9f7 --- /dev/null +++ b/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/test/diff/diff_files/different_decorations_fragment_src.spvasm b/test/diff/diff_files/different_decorations_fragment_src.spvasm new file mode 100644 index 00000000..2c8cd644 --- /dev/null +++ b/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/test/diff/diff_files/different_decorations_vertex_autogen.cpp b/test/diff/diff_files/different_decorations_vertex_autogen.cpp new file mode 100644 index 00000000..f73b917d --- /dev/null +++ b/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 + %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 + %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 + %28 = OpFunction %2 None %27 + %29 = OpFunctionParameter %26 + %30 = OpLabel + %31 = OpLoad %2 %29 + OpReturnValue %31 + 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 + %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 + %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 + %28 = OpFunction %2 None %27 +-%29 = OpFunctionParameter %26 ++%59 = OpFunctionParameter %26 + %30 = OpLabel +-%31 = OpLoad %2 %29 ++%31 = OpLoad %2 %59 + OpReturnValue %31 + 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 + %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 + %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 + %28 = OpFunction %2 None %27 + %29 = OpFunctionParameter %26 + %30 = OpLabel + %31 = OpLoad %2 %29 + OpReturnValue %31 + 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 + %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 + %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 + %28 = OpFunction %2 None %27 + %29 = OpFunctionParameter %26 + %30 = OpLabel + %31 = OpLoad %2 %29 + OpReturnValue %31 + 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/test/diff/diff_files/different_decorations_vertex_dst.spvasm b/test/diff/diff_files/different_decorations_vertex_dst.spvasm new file mode 100644 index 00000000..33c6a9c1 --- /dev/null +++ b/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/test/diff/diff_files/different_decorations_vertex_src.spvasm b/test/diff/diff_files/different_decorations_vertex_src.spvasm new file mode 100644 index 00000000..ce1680cb --- /dev/null +++ b/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/test/diff/diff_files/extra_if_block_autogen.cpp b/test/diff/diff_files/extra_if_block_autogen.cpp new file mode 100644 index 00000000..dd2970e6 --- /dev/null +++ b/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 + %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 + %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 + %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 +)"; + 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 + %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 + %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 + %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 +)"; + Options options; + DoStringDiffTest(kSrcNoDebug, kDstNoDebug, kDiff, options); +} + +} // namespace +} // namespace diff +} // namespace spvtools diff --git a/test/diff/diff_files/extra_if_block_dst.spvasm b/test/diff/diff_files/extra_if_block_dst.spvasm new file mode 100644 index 00000000..79bda830 --- /dev/null +++ b/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/test/diff/diff_files/extra_if_block_src.spvasm b/test/diff/diff_files/extra_if_block_src.spvasm new file mode 100644 index 00000000..1b43ccb1 --- /dev/null +++ b/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/test/diff/diff_files/generate_tests.py b/test/diff/diff_files/generate_tests.py new file mode 100755 index 00000000..1c380c97 --- /dev/null +++ b/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: {} ".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/test/diff/diff_files/index_signedness_autogen.cpp b/test/diff/diff_files/index_signedness_autogen.cpp new file mode 100644 index 00000000..ab650be1 --- /dev/null +++ b/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/test/diff/diff_files/index_signedness_dst.spvasm b/test/diff/diff_files/index_signedness_dst.spvasm new file mode 100644 index 00000000..08c1939b --- /dev/null +++ b/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/test/diff/diff_files/index_signedness_src.spvasm b/test/diff/diff_files/index_signedness_src.spvasm new file mode 100644 index 00000000..06dfd18b --- /dev/null +++ b/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/test/diff/diff_files/int_vs_uint_constants_autogen.cpp b/test/diff/diff_files/int_vs_uint_constants_autogen.cpp new file mode 100644 index 00000000..187722e8 --- /dev/null +++ b/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/test/diff/diff_files/int_vs_uint_constants_dst.spvasm b/test/diff/diff_files/int_vs_uint_constants_dst.spvasm new file mode 100644 index 00000000..da2618b2 --- /dev/null +++ b/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/test/diff/diff_files/int_vs_uint_constants_src.spvasm b/test/diff/diff_files/int_vs_uint_constants_src.spvasm new file mode 100644 index 00000000..214b49bd --- /dev/null +++ b/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/test/diff/diff_files/large_functions_large_diffs_autogen.cpp b/test/diff/diff_files/large_functions_large_diffs_autogen.cpp new file mode 100644 index 00000000..127728d5 --- /dev/null +++ b/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 + %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 + %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 + %4 = OpFunction %2 None %3 + %5 = OpLabel +-%136 = OpFunctionCall %2 %6 + %137 = OpFunctionCall %2 %8 ++%189 = OpFunctionCall %2 %6 + 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 +-%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 +-%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 + %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 ++%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 ++%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 +)"; + Options options; + DoStringDiffTest(kSrcNoDebug, kDstNoDebug, kDiff, options); +} + +} // namespace +} // namespace diff +} // namespace spvtools diff --git a/test/diff/diff_files/large_functions_large_diffs_dst.spvasm b/test/diff/diff_files/large_functions_large_diffs_dst.spvasm new file mode 100644 index 00000000..be7c1d5f --- /dev/null +++ b/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/test/diff/diff_files/large_functions_large_diffs_src.spvasm b/test/diff/diff_files/large_functions_large_diffs_src.spvasm new file mode 100644 index 00000000..8f0aa614 --- /dev/null +++ b/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/test/diff/diff_files/large_functions_small_diffs_autogen.cpp b/test/diff/diff_files/large_functions_small_diffs_autogen.cpp new file mode 100644 index 00000000..05e9fa1f --- /dev/null +++ b/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 + %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 + %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 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %135 = OpFunctionCall %2 %6 + %136 = OpFunctionCall %2 %8 + 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 + %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 + %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 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %135 = OpFunctionCall %2 %6 + %136 = OpFunctionCall %2 %8 + OpReturn + OpFunctionEnd +)"; + Options options; + DoStringDiffTest(kSrcNoDebug, kDstNoDebug, kDiff, options); +} + +} // namespace +} // namespace diff +} // namespace spvtools diff --git a/test/diff/diff_files/large_functions_small_diffs_dst.spvasm b/test/diff/diff_files/large_functions_small_diffs_dst.spvasm new file mode 100644 index 00000000..f788e0b6 --- /dev/null +++ b/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/test/diff/diff_files/large_functions_small_diffs_src.spvasm b/test/diff/diff_files/large_functions_small_diffs_src.spvasm new file mode 100644 index 00000000..78a92785 --- /dev/null +++ b/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/test/diff/diff_files/multiple_different_entry_points_autogen.cpp b/test/diff/diff_files/multiple_different_entry_points_autogen.cpp new file mode 100644 index 00000000..74a5a175 --- /dev/null +++ b/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 + %8 = OpFunction %14 None %3 + %6 = OpLabel + %12 = OpLoad %15 %10 + %13 = OpCompositeConstruct %16 %12 %12 %12 %12 + OpStore %9 %13 + OpReturn + OpFunctionEnd + %2 = OpFunction %14 None %3 + %5 = OpLabel + %11 = OpLoad %15 %7 + OpStore %4 %11 + 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 + %8 = OpFunction %14 None %3 + %6 = OpLabel + %12 = OpLoad %15 %10 + %13 = OpCompositeConstruct %16 %12 %12 %12 %12 + OpStore %9 %13 + OpReturn + OpFunctionEnd + %2 = OpFunction %14 None %3 + %5 = OpLabel + %11 = OpLoad %15 %7 + OpStore %4 %11 + OpReturn + OpFunctionEnd +)"; + Options options; + DoStringDiffTest(kSrcNoDebug, kDstNoDebug, kDiff, options); +} + +} // namespace +} // namespace diff +} // namespace spvtools diff --git a/test/diff/diff_files/multiple_different_entry_points_dst.spvasm b/test/diff/diff_files/multiple_different_entry_points_dst.spvasm new file mode 100644 index 00000000..72cfe283 --- /dev/null +++ b/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/test/diff/diff_files/multiple_different_entry_points_src.spvasm b/test/diff/diff_files/multiple_different_entry_points_src.spvasm new file mode 100644 index 00000000..2119aa73 --- /dev/null +++ b/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/test/diff/diff_files/multiple_same_entry_points_autogen.cpp b/test/diff/diff_files/multiple_same_entry_points_autogen.cpp new file mode 100644 index 00000000..71f5ab7e --- /dev/null +++ b/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 + %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 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %11 = OpLoad %6 %10 + OpStore %8 %11 + 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 + %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 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %11 = OpLoad %6 %10 + OpStore %8 %11 + 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 + %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 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %11 = OpLoad %6 %10 + OpStore %8 %11 + 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/test/diff/diff_files/multiple_same_entry_points_dst.spvasm b/test/diff/diff_files/multiple_same_entry_points_dst.spvasm new file mode 100644 index 00000000..e2007220 --- /dev/null +++ b/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/test/diff/diff_files/multiple_same_entry_points_src.spvasm b/test/diff/diff_files/multiple_same_entry_points_src.spvasm new file mode 100644 index 00000000..17001b57 --- /dev/null +++ b/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/test/diff/diff_files/reordered_if_blocks_autogen.cpp b/test/diff/diff_files/reordered_if_blocks_autogen.cpp new file mode 100644 index 00000000..0788199f --- /dev/null +++ b/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/test/diff/diff_files/reordered_if_blocks_dst.spvasm b/test/diff/diff_files/reordered_if_blocks_dst.spvasm new file mode 100644 index 00000000..cd1d6d52 --- /dev/null +++ b/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/test/diff/diff_files/reordered_if_blocks_src.spvasm b/test/diff/diff_files/reordered_if_blocks_src.spvasm new file mode 100644 index 00000000..209cb45b --- /dev/null +++ b/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/test/diff/diff_files/reordered_switch_blocks_autogen.cpp b/test/diff/diff_files/reordered_switch_blocks_autogen.cpp new file mode 100644 index 00000000..c0ba48d1 --- /dev/null +++ b/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/test/diff/diff_files/reordered_switch_blocks_dst.spvasm b/test/diff/diff_files/reordered_switch_blocks_dst.spvasm new file mode 100644 index 00000000..8eabb4ef --- /dev/null +++ b/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/test/diff/diff_files/reordered_switch_blocks_src.spvasm b/test/diff/diff_files/reordered_switch_blocks_src.spvasm new file mode 100644 index 00000000..e3772282 --- /dev/null +++ b/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/test/diff/diff_files/small_functions_small_diffs_autogen.cpp b/test/diff/diff_files/small_functions_small_diffs_autogen.cpp new file mode 100644 index 00000000..623dee2e --- /dev/null +++ b/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 + %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 + %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 + %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 + %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 + %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 + %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 +)"; + 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 + %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 + %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 + %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 + %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 + %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 + %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 +)"; + 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 + %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 + %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 + %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 + %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 + %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 + %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 + 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/test/diff/diff_files/small_functions_small_diffs_dst.spvasm b/test/diff/diff_files/small_functions_small_diffs_dst.spvasm new file mode 100644 index 00000000..fabf5692 --- /dev/null +++ b/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/test/diff/diff_files/small_functions_small_diffs_src.spvasm b/test/diff/diff_files/small_functions_small_diffs_src.spvasm new file mode 100644 index 00000000..895285b1 --- /dev/null +++ b/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/test/diff/diff_files/unrelated_shaders_autogen.cpp b/test/diff/diff_files/unrelated_shaders_autogen.cpp new file mode 100644 index 00000000..e1a58ccc --- /dev/null +++ b/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/test/diff/diff_files/unrelated_shaders_dst.spvasm b/test/diff/diff_files/unrelated_shaders_dst.spvasm new file mode 100644 index 00000000..719715ba --- /dev/null +++ b/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/test/diff/diff_files/unrelated_shaders_src.spvasm b/test/diff/diff_files/unrelated_shaders_src.spvasm new file mode 100644 index 00000000..e77b2d20 --- /dev/null +++ b/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/test/diff/diff_test.cpp b/test/diff/diff_test.cpp new file mode 100644 index 00000000..5b11d0eb --- /dev/null +++ b/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 +#include + +#include "gtest/gtest.h" + +namespace spvtools { +namespace diff { +namespace { + +constexpr auto kDefaultEnvironment = SPV_ENV_UNIVERSAL_1_6; + +std::unique_ptr Assemble(const std::string& spirv) { + spvtools::SpirvTools t(kDefaultEnvironment); + t.SetMessageConsumer(spvtools::utils::CLIMessageConsumer); + std::vector 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 src = Assemble(src_spirv); + ASSERT_TRUE(src); + + std::unique_ptr 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/test/diff/diff_test_utils.cpp b/test/diff/diff_test_utils.cpp new file mode 100644 index 00000000..14bb8215 --- /dev/null +++ b/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 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 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/test/diff/diff_test_utils.h b/test/diff/diff_test_utils.h new file mode 100644 index 00000000..938236e6 --- /dev/null +++ b/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/test/diff/lcs_test.cpp b/test/diff/lcs_test.cpp new file mode 100644 index 00000000..db7072d8 --- /dev/null +++ b/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 + +#include "gtest/gtest.h" + +namespace spvtools { +namespace diff { +namespace { + +using Sequence = std::vector; +using LCS = LongestCommonSubsequence; + +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 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 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 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 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 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 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 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 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 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 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 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); +} + +const std::string large_lcs_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 large_lcs_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"; + +TEST(LCSTest, Large) { + Sequence src; + Sequence dst; + + src.reserve(large_lcs_src_str.length()); + dst.reserve(large_lcs_dst_str.length()); + + for (char c : large_lcs_src_str) { + src.push_back(c); + } + for (char c : large_lcs_dst_str) { + dst.push_back(c); + } + + VerifyMatch(src, dst, 723); +} + +} // namespace +} // namespace diff +} // namespace spvtools diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 0a7e8651..86d0bc46 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -41,6 +41,7 @@ endfunction() 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}) diff --git a/tools/diff/diff.cpp b/tools/diff/diff.cpp new file mode 100644 index 00000000..d3cad04b --- /dev/null +++ b/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 +#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 + +The SPIR-V binary is read from and . 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 load_module(const char* path) { + if (is_assembly(path)) { + std::vector contents; + if (!ReadTextFile(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 contents; + if (!ReadBinaryFile(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 src = load_module(src_file); + std::unique_ptr 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; +}