Produce better error diagnostics in the CFG validation.
This CL fixes up several issues with the diagnostic error line output
in the CFG validation code. For the cases where we can determine a
better line it has been output. For other cases, we removed the
diagnostic line and the error line number from the results.
Fixes#1657
Add SPV_ENV_WEBGPU_0 for work-in-progress WebGPU.
val: Disallow OpUndef in WebGPU env
Silence unused variable warnings when !defined(SPIRV_EFFCE)
Limit visibility of validate_instruction.cpp's symbols
Only InstructionPass needs to be visible so all other functions are put
in an anonymous namespace inside the libspirv namespace.
[val] Add extra context to error messages.
This CL extends the error messages produced by the validator to output the
disassembly of the errored line.
The validation_id messages have also been updated to print the line number of
the error instead of the word number. Note, the error number is from the start
of the SPIR-V, it does not include any headers printed in the disassembled code.
Fixes#670, #1581
Fixes#491
* Basic blocks now have a link to the terminator
* Check all case sepecific rules
* Missing check for branching into the middle of a case (#1618)
Fixes#1120
Checks that all static uses of the Input and Output variables are listed
as interfaces in each corresponding entry point declaration.
* Changed validation state to track interface lists
* updated many tests
* Modified validation state to store entry point names
* Combined with interface list and called EntryPointDescription
* Updated uses
* Changed interface validation error messages to output entry point name
in addtion to ID
Fixes#1281
* New structured cfg check: all non-construct header blocks'
predecessors must come from within the construct
* New function to calculate blocks in a construct
* Fixed a bug in BasicBlock type bitset
Relaxing check to not consider unreachable predecessors
* Fixing broken common uniform elim test
According to the SPIR-V Spec, section 2.4 Logical Layout of a Module there
should be a single required OpMemoryModel instruction provided. This CL adds
validation that OpMemoryModel is provided to the SPIR-V validator.
Fixes#1207
* Reworked how execution model limitations are checked
* Now OpFunction checks which entry points call it and checks its
registered limitations instead of building a call stack in the entry
point
* New tests
* Moving function to entry point mapping into VState
Refactored validate built-ins to make
GetExecutionModels(entry_point)
and
GetExecutionModes(entry_point)
available in validation state.
Entry points are allowed to have multiple execution modes and execution
models.
Finished the last missing feature in Vulkan built-ins validation:
FragDepth requires DepthReplacing.
Added a framework for validation of BuiltIn variables. The framework
allows implementation of flexible abstract rules which are required for
built-ins as the information (decoration, definition, reference) is not
in one place, but is scattered all over the module.
Validation rules are implemented as a map
id -> list<functor(instrution)>
Ids which are dependent on built-in types or objects receive a task
list, such as "this id cannot be referenced from function which is
called from entry point with execution model X; propagate this rule
to your descendants in the global scope".
Also refactored test/val/val_fixtures.
All built-ins covered by tests
This needs custom code since the rules from the extension
are not encoded in the grammar.
Changes are:
- The new group instructions don't require Group capability
when the extension is declared.
- The Reduce, InclusiveScan, ExclusiveScan normally require the Kernel
capability, but don't when the extension is declared.
Fixes https://github.com/KhronosGroup/SPIRV-Tools/issues/991
Re-formatted the source tree with the command:
$ /usr/bin/clang-format -style=file -i \
$(find include source tools test utils -name '*.cpp' -or -name '*.h')
This required a fix to source/val/decoration.h. It was not including
spirv.h, which broke builds when the #include headers were re-ordered by
clang-format.
NFC. This just makes sure every file is formatted following the
formatting definition in .clang-format.
Re-formatted with:
$ clang-format -i $(find source tools include -name '*.cpp')
$ clang-format -i $(find source tools include -name '*.h')
There are a number of users of spriv-opt that are hitting errors
because of stores with different types. In general, this is wrong, but,
in these cases, the types are the exact same except for decorations.
The options is "--relax-store-struct", and it can be used with the
validator or the optimizer.
We assume that if layout information is missing it is consistent. For
example if one struct has a offset of one of its members, and the other
one does not, we will still consider them as being layout compatible.
The problem will be if both struct has and offset decoration for
corresponding members, and the offset are different.
Function static non-POD data causes problems with DLL lifetime.
This pull request turns all static info tables into strict POD
tables. Specifically, the capabilities/extensions field of
opcode/operand/extended-instruction table are turned into two
fields, one for the count and the other a pointer to an array of
capabilities/extensions. CapabilitySet/EnumSet are not used in
the static table anymore, but they are still used for checking
inclusion by constructing on the fly, which should be cheap for
the majority cases.
Also moves all these tables into the global namespace to avoid
C++11 function static thread-safe initialization overhead.
The pass checks correctness of operands of instruction in opcode range
OpConvertFToU - OpBitset.
Disabled invalid tests
Disabled UConvert validation until Vulkan CTS can catch up.
Add validate_conversion to Android.mk
Also remove duplicate entry in CMakeLists.txt.
Command line application is located at tools/spirv-markv
API at include/spirv-tools/markv.h
At the moment only very basic compression is implemented, mostly varint.
Scope of supported SPIR-V opcodes is also limited.
Using a simple move-to-front implementation instead of encoding mapped
ids.
Work in progress:
- Does not cover all of SPIR-V
- Does not promise compatibility of compression/decompression across
different versions of the code.
Create class to encapsulate control flow analysis and share across
validator and optimizer. A WIP. Start with DepthFirstTraversal. Next
pull in CalculateDominators.
If the variable_pointer extension is used:
* OpLoad's pointer argument may be the result of any of the following:
* OpSelect
* OpPhi
* OpFunctionCall
* OpPtrAccessChain
* OpCopyObject
* OpLoad
* OpConstantNull
* Return value of a function may be a pointer.
* It is valid to use a pointer as the return value of a function.
* OpStore should allow a variable pointer argument.
Known extensions are saved in validation state. Unknown extension
produce a dignostic message, but do not fail the validation.
Moved extension definitions to their own file.
- validation_state.cpp uses functions from opcode.h instead of in-place
switches which need to be updated.
- added new spirv 1.1 type declaration opcodes to a 'is op type
declaration' switch in opcode.cpp.
The limit for the number of struct members is parameterized using
command line options.
Add --max-struct-depth command line option.
Add --max-switch-branches command line option.
Add --max-function-args command line option.
Add --max-control-flow-nesting-depth option.
Add --max-access-chain-indexes option.
If a merge block is reachable, then it must be *strictly* dominated
by its header. Until now we've allowed the header and the merge
block to be the same.
Fixes https://github.com/KhronosGroup/SPIRV-Tools/issues/551
Also: Use dominates and postdominates methods on BasicBlock to
improve readability.
When applied to a structure-type member, all members of that structure
type must also be decorated with BuiltIn. (No allowed mixing of built-in
variables and non-built-in variables within a single structure.)
When applied to a structure-type member, that structure type cannot be
contained as a member of another structure type.
There is at most one object per Storage Class that can contain a
structure type containing members decorated with BuiltIn, consumed per
entry-point.
Added a new file where all the decoration validation can be performed.
In this change the SPIRV Spec Section 2.16.1 is implemented:
"It is illegal to initialize an imported variable. This means
that a module-scope OpVariable with initialization value cannot be
marked with the Import Linkage Type."
Also added unit tests.
* Added the decoration class as well as the code that registers the
decorations for each <id> and also decorations for struct members.
* Added unit tests for decorations in ValidationState as well as
decoration id tests.
According to the SPIRV Spec (2.16.1):
* There is at least one OpEntryPoint instruction, unless the Linkage
capability is being used.
* No function can be targeted by both an OpEntryPoint instruction and an
OpFunctionCall instruction.
Also updated unit tests to includ OpEntryPoint.
entry_block_to_construct_ maps an entry block to its construct. The key
in this map (the entry block) is not unique, and therefore the entry for
the continue construct gets overwritten when the selection construct is
discovered.
Since a given block may be the entry block of different types of
constructs, the (basic_block, construct_type) pair should be able to
uniquely identify the construct.
Adds test:
- In this test, a basic block is the entry block of a continue construct
as well as the entry block of a selection construct.
It can be shown that this unit test would crash without the fix in this
PR and passes with the fix in this PR.
According to Section 2.17 (Universal Limits) of the SPIR-V Spec, the
control flow nesting depth may not be larger than 1023.
This is checked only when we are required to have structured
control flow. Otherwise it's not clear how to compute control
flow nesting depth.
According to sectin 2.17 in SPIR-V Spec, the structure nesting depth may
not be larger than 255. This is interpreted as structures nested in
structures. The code does not look into arrays or follow pointers to see
if it reaches a structure downstream.
Use memoization to avoid exponential runtime.
According to the Universal Limits section of the SPIR-V Spec (2.17), the
number of global variables may not exceed 65,535 and the number of local
variables may not exceed 524,287.
Also added unit tests for each one.
This is described in Section 2.17 of the SPIR-V Spec.
* Updated existing unit test 'SemanticsIdIsAnIdNotALiteral' to pass by
manipulating the ID bound in its binary header.
* Fixed boundary check in the code.
* Added unit test to check the case that the largest ID is equal to the
ID bound.
This change implements the validation for usages of OpSampledImage
instruction as described in the Data Rules section of the Universal
Validation Rules of the SPIR-V Spec.
According to the Data Rules section of 2.16.1. Universal Validation
Rules of the SPIR-V Spec:
Forward reference operands in an OpTypeStruct
* must be later declared with OpTypePointer
* the type pointed to must be an OpTypeStruct
* had an earlier OpTypeForwardPointer forward reference to the same <id>
Example of an error:
spirv-tools/source/validate_cfg.cpp:516:45: error: chosen constructor is
explicit in copy-initialization:
_.current_function().RegisterBlockEnd({}, opcode);
Every time an event happens in the library that the user should be
aware of, the callback will be invoked.
The existing diagnostic mechanism is hijacked internally by a
callback that creates an diagnostic object each time an event
happens.
Use libspirv::CapabilitySet instead of a 64-bit mask.
Remove dead function spvOpcodeRequiresCapability and its tests.
The JSON grammar parser is simplified since it just writes the
list of capabilities as a braced list, and takes advantage of
the CapabilitySet intializer-list constructor.
Previously we use vectors of objects and move semantics to handle
ownership. That approach has the flaw that inserting an object into
the middle of a vector, which may trigger a vector reallocation,
can invalidate some addresses taken from instructions.
Now the in-memory representation internally uses vector of unique
pointers to handle ownership. Since objects are explicitly heap-
allocated now, pointers to them won't be invalidated by vector
resizing anymore.
- Find unreachable continue targets. Look for back edges
with a DFS traversal separate from the dominance traversals,
where we count the OpLoopMerge from the header to the continue
target as an edge in the graph.
- It's ok for a loop to have multiple back edges, provided
they are all from the same block, and we call that the latch block.
This may require a clarification/fix in the SPIR-V spec.
- Compute postdominance correctly for infinite loop:
Bias *predecessor* traversal root finding so that you use
a later block in the original list. This ensures that
for certain simple infinite loops in the CFG where neither
block branches to a node without successors, that we'll
compute the loop header as dominating the latch block, and the
latch block as postdominating the loop header.
Ensure the dominance calculation visits all nodes in the CFG.
The successor list of the pseudo-entry node is augmented with
a single node in each cycle that otherwise would not be visited.
Similarly, the predecssors list of the pseduo-exit node is augmented
with the a single node in each cycle that otherwise would not
be visited.
Pulls DepthFirstSearch out so it's accessible outside of the dominator
calculation.
Fixes https://github.com/KhronosGroup/SPIRV-Tools/issues/279
* Creates an ID class which manages definition and use of IDs
* Moved tracking code from validate.cpp to validate_id.cpp
* Rename and combine SsaPass and ProcessIds into IdPass
* Remove module dependency in Function
For dominance calculations we use an "augmented" CFG
where we always add a pseudo-entry node that is the predecessor
in the augmented CFG to any nodes that have no predecessors in the
regular CFG. Similarly, we add a pseudo-exit node that is the
predecessor in the augmented CFG that is a successor to any
node that has no successors in the regular CFG.
Pseudo entry and exit blocks live in the Function object.
Fixes a subtle problem where we were implicitly creating
the block_details for the pseudo-exit node since it didn't
appear in the idoms map, and yet we referenced it. In such a case the
contents of the block details could be garbage, or zero-initialized.
That sometimes caused incorrect calculation of immediate dominators
and post-dominators. For example, on a debug build where the details
could be zero-initialized, the dominator of an unreachable block would
be given as the pseudo-exit node. Bizarre.
Also, enforce the rule that you must have an OpFunctionEnd to close off
the last function.
Refactor the way the post order vector is created. This new method
will allow for the extraction of backedges and create the post order
vector in one pass.