If an id in one module is not defined by any instruction, don't bother
matching it with an id in the other module, as this disturbs the
reported id bound, resulting in spurious differences.
Fixes#5260.
- Consider prior type pairings when attempting to pair function
parameters by type.
- Pair all parameters that have matching types, not just the first.
- Update diff tests.
Fixes#5218.
These asserts are not valid for string literals, which may
contain several words:
assert(a_operand.words.size() == 1);
assert(b_operand.words.size() == 1);
It looks like they only make sense for the default case, which
assumes that both operands contain a single word.
Running a debug version of spirv-diff on any shader containing
a string literal will hit the original asserts.
The code accidentally expected OpTypeFunction operand count to match.
This is fixed so that OpTypeFunction instructions with different operand
counts are considered not matching.
Currently, the diff tool matches types bottom up, so on every
instruction it expects to know if its operands are already matched or
not. With cyclical references, it cannot know that. Type matching
would need significant rework to be able to support such a use case; for
example, it may need to maintain a set of plausable matches between type
pointers that are forward-referenced, and potentially back track when
later the types turn out to be incompatible.
In this change, OpTypeForwardPointer is supported in the more common and
trivial case. Firstly, forwarded type pointers are only matched if they
have they have the same storage class and point to the same type opcode:
- In the presence of debug info, matching is done only if the names are
unique in both src and dst.
- In the absence of debug info, matching is done only if there is only
one possible matching.
Fixes: #4754
In preparation for supporting OpTypeForwardPointer, which adds more
usages like this. This change refactors common code used to group
instructions and match the groups.
Previously, array sizes were presumed to be OpConstant, which is not
necessarily true. This change ensures OpSpecConstant array sizes as
matched exactly, instead of taken as OpConstant and matched by value.
* Reimplement LCS used by spirv-diff
Two improvements are made to the LCS algorithm:
- The LCS algorithm is reimplemented to use a std::stack instead of
being recursive. This prevents stack overflow in the LCSTest.Large
test.
- The LCS algorithm uses an NxM table. Previously, entries of this
table were {size_t, bool, bool}, which is now packed in 32 bits. The
first entry can assume a maximum value of min(N, M), which
realistically for SPIR-V diff will not be larger than 1 billion
instructions. This reduces memory usage of LCS by 75%.
This partially reverts 845f3efb8a and
enables LCS tests.
* Stabilize the output of spirv-diff
std::map is used instead of std::unordered_map to ensure the output of
spirv-diff is identical everywhere.
This partially reverts 845f3efb8a and
enables spirv-diff tests.
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.