* Fix infinite loop in validation
Fixes https://crbug.com/38548
* Fixes an issue in structured exit checking where an invalid merge
could result in an infinite traversal
* formatting
It is possible that other optimization will propagate
a value into an OpCompositeExtract or OpVectorShuffle
instruction that is larger than the vector size.
Vector DCE has to be able to handle it.
Fixes https://github.com/KhronosGroup/SPIRV-Tools/issues/4513.
Fixes an issue where an arbitrary word was cast to SpvOp, leading to
undefined behaviour if the value of the word fell outside the range of
SpvOp values.
Fixes#4504.
The validation state contained feature bits for scalar block layout and
workgroup memory scalar block layout which were never used (the
command-line option is used in every case).
- The binary exponent must have some decimal digits
- A + or - after the binary exponent digits should not be interpreted as
part of the binary exponent.
Fixes: #4500
ADCE does not handle exported functions. This was an explicit decision
because we did not believe that the linkage attribute could be used in
shaders, but it can now. This change has been made.
While fixing this error, I noticed that the OpName for labels is
sometimes removed because the label instructions are not marked
explicitly marked as live. This has able been fixed.
This PR is a rebased version of #4479 by James Dong.
---
The primary purpose of this PR is to add the code from my prototype as a PR, for licensing reasons.
The commit history is messy, and the code is not especially clean.
Fixes https://github.com/KhronosGroup/SPIRV-Tools/issues/3196.
Allow LocalSizeId as a way of sizing compute workgroups where the
environment allows it. A command-line switch is also added to force
acceptance even where the environment would not otherwise allow it.
Currently, handles promotion of divergence due to reconvergence rules, but doesn't handle "late merges" caused by a later-than-necessary declared merge block.
Co-authored-by: Jakub Kuderski <kubak@google.com>
convert-to-sampled-image pass converts images and/or samplers with
given pairs of descriptor set and binding to sampled image.
If a pair of an image and a sampler have the same pair of descriptor
set and binding that is one of the given pairs, they will be
converted to a sampled image. In addition, if only an image has the
descriptor set and binding that is one of the given pairs, it will
be converted to a sampled image as well.
For example, when we have
%a = OpLoad %type_2d_image %texture
%b = OpLoad %type_sampler %sampler
%combined = OpSampledImage %type_sampled_image %a %b
%value = OpImageSampleExplicitLod %v4float %combined ...
1. If %texture and %sampler have the same descriptor set and binding
%combine_texture_and_sampler = OpVaraible %ptr_type_sampled_image_Uniform
...
%combined = OpLoad %type_sampled_image %combine_texture_and_sampler
%value = OpImageSampleExplicitLod %v4float %combined ...
2. If %texture and %sampler have different pairs of descriptor set and binding
%a = OpLoad %type_sampled_image %texture
%extracted_image = OpImage %type_2d_image %a
%b = OpLoad %type_sampler %sampler
%combined = OpSampledImage %type_sampled_image %extracted_image %b
%value = OpImageSampleExplicitLod %v4float %combined ...
* Disallow loading a runtime-sized array
Fixes#4472
* Disallow loading a runtime-sized array or a composite containing one
* Refactor type traversal into a separate function used by both runtime
array checks and sized int/float checks
* Update invalid tests
Only the first two operands were tested for constness, missing the third
one. Since the FoldFPBinaryOp() at the end of FoldClamp1() returns null
when not both of its operands are constant, this doesn't change any
behavior, but it avoids some needless work.
Also the comment for FoldClamp2() was fixed.
This PR adds a generic dataflow analysis framework to SPIRV-opt, with the intent of being used in SPIRV-lint. This may also be useful for SPIRV-opt, as existing ad-hoc analyses can be rewritten to use a common framework, but this is not the target of this PR.
This PR adds a new executable spirv-lint with a simple "Hello, world!"
program, along with its associated library and a dummy unit test.
For now, only adds to CMake and Bazel; other build systems will be added
in a future PR.
Issue: #3196
Introducing a new mandatory parameter makes it very difficult to roll
Chromium to a new version of SPIRV-Tools, as this project is used by
several third-party projects, and an atomic update of all projects
is very hard to coordinate.
spirv-fuzz features transformations that should be applicable by
construction. Assertions are used to detect when such transformations
turn out to be inapplicable. Failures of such assertions indicate bugs
in the fuzzer. However, when using the fuzzer at scale (e.g. in
ClusterFuzz) reports of these assertion failures create noise, and
cause the fuzzer to exit early. This change adds an option whereby
inapplicable transformations can be ignored. This reduces noise and
allows fuzzing to continue even when a transformation that should be
applicable but is not has been erroneously created.
The fuzzer pass that adds global variables requires some basic
types. This change makes the fuzzer pass exit gracefully when none are
available.
Fixes#4408.
Control dependence analysis constructs a control dependence graph,
representing the conditions for a block's execution relative to the
results of other blocks with conditional branches, etc.
This is an analysis pass that will be useful for the linter and
potentially also useful in opt. Currently it is unused except for the
added unit tests.
The instruction parameter of CanMakeSynonymOf is an input parameter
that should never be null, so a const reference is a more appropriate
type than a const pointer.
Adds an additional validity check to ensure that every instruction's
context pointer matches the enclosing IR context. Avoids a redundant
copy constructor call in TransformationDuplicateRegionWithSelection
that was leading to a bad IR context for some instructions.
Related: #4387, #4388.
Fixes#4393.
The fuzzer pass was passing the type of a scalar where a vector type
was required, and was not checking whether synonyms could be made for
the operands to the scalar instruction.
Adaps the transformations that add OpConstantUndef and OpConstantNull
to a module so that pointer undefs are not allowed, and null pointers
are only allowed if suitable capabilities are present.
Fixes#4357.
Adds a new transformation that rewrites a scalar operation (like
OpFAdd, opISub) as an equivalent vector operation, adding a synonym
between the scalar result and an appropriate component of the vector
result.
Fixes#4195.
This change is responsible for avoiding the replacement of constant
operands with another one not constant, in the context of atomic
operations. The related rule from the SPIR-V spec is: "All used for
Scope and Memory Semantics in shader capability must be of an
OpConstant."
Fixes#4346.
This is based on a legacy commit which installs a local grammar. A
followup commit will change to the grammar in SPIRV-Headers.
Co-authored-by: baldurk <baldurk@baldurk.org>
This change allows spriv-reduce to get rid of a selection, switch or
loop construct if none of the instructions defined in the construct
are used outside the construct.
The new pass will removed interface variable on the OpEntryPoint instruction when they are not statically referenced in the call tree of the entry point.
It can be enabled on the command line using the options `remove-unused-interface-variables`.
This change allows the reducer to merge together blocks even when they
are unreachable, but keeps the restriction of reachability in place
for the optimizer.
Fixes#4302.
There was a lot of code in the codebase that would get the dominator
analysis for a function and then use it to check whether a block is
reachable. In the fuzzer, a utility method had been introduced to make
this more concise, but it was not being used consistently.
This change moves the utility method to IRContext, so that it can be
used throughout the codebase, and refactors all existing checks for
block reachability to use the utility method.
Cleans up a CMakeLists.txt file and the header guard for a reduction
opportunity, and gets rid of an unnecessary parent function field that
can be derived from an existing block field.
* Initial support for SPV_KHR_integer_dot_product
- Adds new operand types for packed-vector-format
- Moves ray tracing enums to the end
- PackedVectorFormat is a new optional operand type, so it requires
special handling in grammar table generation.
- Add SPV_KHR_integer_dot_product to optimizer whitelists.
- Pass-through validation: valid cases pass validation
Validation errors are not checked.
- Update SPIRV-Headers
Patch by David Neto <dneto@google.com>
Rebase and minor tweaks by Kevin Petit <kevin.petit@arm.com>
Signed-off-by: David Neto <dneto@google.com>
Signed-off-by: Kevin Petit <kevin.petit@arm.com>
Change-Id: Icb41741cb7f0f1063e5541ce25e5ba6c02266d2c
* format fixes
Change-Id: I35c82ec27bded3d1b62373fa6daec3ffd91105a3
Fixes#4170, by checking the signedness of bitwise operands in
TransformationAddBitInstructionSynonym, to avoid an "Expected Base
Type to be equal to Result Type" validation error.
PR #4118 (d71ac38b8e) let spirv-val report a validation error when we
use offset for an OpImage* instruction instead of ConstantOffset. Since
some compilers like DXC rely on spirv-opt for function inlining or loop
unrolling, the spirv-val change broke some working shaders when the
shader developers disable the optimization (spirv-opt).
For example, DXC recently got this issue from a few users e.g.,
https://github.com/microsoft/DirectXShaderCompiler/issues/3807
Since this error is reported only when the spirv-opt is disabled, it
looks like the exact case that we have to skip spirv-val when
`--before-legalize-hlsl` is given. Moreover, avoiding the error using
`--before-legalize-hlsl` on DXC is exactly what FXC and DXC's DXIL
do (they do not report the error if the offset becomes a constant after
function inlining or loop unrolling).
This change prevents TransformationOutlineFunction from outlining a
region of blocks if some block in the region has an unreachable
predecessor. This avoids a bug whereby the region would be outlined,
and the unreachable predecessors would be left behind, referring to
blocks that are no longer in the function.
The def-use manager was being incorrectly updated in
TransformationPermutePhiOperands, and this was causing future
transformations to go wrong during fuzzing. This change updates the
def-use manager in a correct manner, and adds a test exposing the
previous bug.
Fixes#4300.
Sometimes, you need to change these functions during debugging (e.g.,
figure out why the transformation is inapplicable). When that happens,
you need to recompile the whole fuzzer just because these functions
are in the header file. This PR fixes the situation.
Fixes https://crbug.com/tint/793
* When a loop has an empty loop construct, the loop construct and
continue construct share the same header so don't disallow the loop
header for the continue construct
Fix dangling phi bug from loop-unroll
When unrolling the following loop:
```
%const0 = OpConstant ...
%const1 = OpConstant ...
...
%LoopHeader = OpLabel
%phi0 = OpPhi %float %const0 %PreHeader %phi1 %Latch
%phi1 = OpPhi %float %const1 %PreHeader %x %Latch
...
%LoopBody = OpLabel
%x = OpFSub %float %phi1 %phi0
...
```
the loop-unroll pass sets the value of `%phi0` as `%phi1` for the second
copy of the loop body. For example, the second copy of
`%x = OpFSub %float %phi1 %phi0` will be
`%y = OpFSub %float %x %phi1`.
Since all phi instructions for inductions will are removed after the
loop unrolling, `%phi1` will be a dead dangling phi.
It happens only for the phi values of the first loop iteration. Replacing those
dangling phis with their initial values fixes this issue.
For example, the second copy of `%x = OpFSub %float %phi1 %phi0` should be
`%y = OpFSub %float %x %const1` because the value of `%phi1` from the
first loop iteration is `%const1`.
There are some edge cases where adding livesafe functions does not
succeed, due to loop limiter edges breaking SPIR-V dominance rules. As
these edge cases are rare it does not seem worth implementing complex
additional logic to handle all cases. This change accepts that trying
to add a function in a livesafe manner may not succeed.
This pass converts an internal form of GLSLstd450 Interpolate ops
to the externally valid form. The external form takes the lvalue
of the interpolant. The internal form can do a load of the interpolant.
The pass replaces the load with its pointer. The internal form is
generated by glslang and possibly other frontends for HLSL shaders.
The new pass is called as part of HLSL legalization after all
propagation is complete.
Also adds internal interpolate form to pre-legalization validation
FuzzerPassConstructComposites is adapted to use AvailableInstructions
to manage available instructions, and to use zero constants when
trying to construct a composite for which not all fields can otherwise
be constructed. The change uncovered some cases where we create
structs and arrays with struct fields or components that are
block-decorated; these possibilities have been eliminated.
It is easy to avoid the need to invalidate the def-use analysis and
instruction to block mapping when splitting blocks, and profiling has
revealed that invalidation of def-use in particular is expensive when
splitting many blocks. This change avoids these invalidations.
Profiling has shown that adding large numbers of dead block
transformations can be expensive because each on requires dominator
analysis information, and each one invalidates this information. There
is currently no obvious mechanism for incrementally updating the
dominator analysis. This change restricts the number of these
transformations that a single fuzzer pass will apply, to restrict this
performance bottleneck.
Types should only be added to the module by spirv-fuzz via
transformations, so this change removes the AddType methods from
fuzzerutil, which were only called once each from the appropriate
transformation.
The transformations have been adapted so that they avoid redundantly
invalidating all analyses - they now update the def-use manager and
invalidate only the type manager.
Avoids redundantly searching the whome module when locating an
instruction from its descriptor - instead, only the block containing
the instruction needs to be searched.
The performance of spirv-fuzz is sometimes poor due to analyses being
conservatively invalidated. This can lead to quadratic time algorithms
when a fuzzer pass applies O(N) transformations, and where every
transformation e.g. depends on def-use analysis and invalidates
def-use analysis (because building def-use analysis is O(N)).
This change avoids invalidating analyses for certain transformations.
The fuzzer library depended on CLIMessageConsumer, due to its explicit
use in a function. This change removes that dependency so that,
instead, a message consumer parameter is passed.
This allows the GPU-AV layer to differentiate between errors with
uniform buffers versus storage buffers and map these to the relevant
VUIDs.
This is a resubmit of a previously reverted commit. The revert was
done as someone erroneously attempted to build the latest validation
layers with a TOT spirv-tools. The validation layers must be built with
their known-good glslang and its known-good spirv-tools and spirv-headers.
* Mark module as modified if convert-to-half removes decorations.
If the convert-to-half pass does not change the body of the function,
but removes decorations, it returns that nothing changed. This is
incorrect, and will be fixed.
Fixes https://github.com/KhronosGroup/SPIRV-Tools/issues/4117
* Update comment for RemoveDecorationsFrom
The existing spirv-opt `DebugInfoManager::AddDebugValueForDecl()` sets
the scope and line info of the new added DebugValue using the scope and
line of DebugDeclare. This is wrong because only a single DebugDeclare
must exist under a scope while we have to add DebugValue for all the
places where the variable's value is updated. Therefore, we have to set
the scope and line of DebugValue based on the places of the variable
updates.
This bug makes
https://github.com/google/amber/blob/main/tests/cases/debugger_hlsl_shadowed_vars.amber
fail. This commit fixes the bug.
* Validate SPV_KHR_workgroup_memory_explicit_layout
* Check if SPIR-V is at least 1.4 to use the extension.
* Check if either only Workgroup Blocks or only Workgroup non-Blocks
are used.
* Check that if more than one Workgroup Block is used, variables are
decorated with Aliased.
* Check layout decorations for Workgroup Blocks.
* Implicitly use main capability if the ...8BitAccess or
...16BitAccess are used.
* Allow 8-bit and 16-bit types when ...8BitAccess and ...16BitAccess
are used respectively.
* Update SPIRV-Headers dependency
Bump it to include SPV_KHR_workgroup_memory_explicit_layout.
* Add option to validate Workgroup blocks with scalar layout
Validate the equivalent of scalarBlockLayout for Workgroup storage
class Block variables from SPV_KHR_workgroup_memory_explicit_layout.
Add option to the API and command line tool.
This patch supports new Intel extensions added via
https://github.com/KhronosGroup/SPIRV-Headers/pull/176
SPV_INTEL_fooat_controls2 requires extra support to add
two new operand types:
SPV_OPERAND_TYPE_FPDENORM_MODE
SPV_OPERAND_TYPE_FPOPERATION_MODE
* Work around GCC-9 warning treated as error
```
../source/opt/instruction.h:101:23: error: '*((void*)& operand +32)' may be used uninitialized in this function [-Werror=maybe-uninitialized]
101 | uint64_t result = uint64_t(words[0]);
```
* Migrate all Kokoro build scripts over to use the docker VM image
Required updating the NDK SDK and build scripts, as well as the check_copyright for handling 2021.
Propagating the OpLine/OpNoLine to preserve the debug information
through transformations results in integrity check failures because of
the extra line instructions. This commit lets spirv-opt skip the
integrity check when the code contains OpLine or OpNoLine.
* tools/linker: Error out on unrecognized options
Fixes#4083.
* tools/linker: Use early returns when parsing options
This was already the case for some linker options, and other tools were
doing so for all of their options.
* tools/linker: Rework the usage output
* The new formatting for long options taking a value makes it explicit
that there is no equal sign between the option name and the value.
* The options are sorted by lexicographical order.
* Change the option formatting from 90 columns to 80, to match the other
tools.
* tools/linker: Change the default environment to spv1.5
* tools/linker: Change the default output to spv.out
Instead of writing to the standard output when the "-o" option is not
specified, the resulting linked SPIR-V binary will be written to
"spv.out".
One can still have the output sent to the standard output by specifying
"-o -".
* tools/linker: Update the reported target for --version
Running `spirv-link --version` will now report the currently selected
environment.
* tools/linker: Sort header includes
* linker: Improve module-related error messages
* Use 1-based indexing of modules;
* Say which module could not be built;
* Use the correct total number of input modules in the error message
when one fails to build.
When there is an array of strutured buffers, desc sroa will only split
the array, but not a struct type in the structured buffer. However,
the calcualtion of the number of binding a struct requires does not take
this into consideration. This commit will fix that.
Avoid generating OpPhi on void types, and allow the transformation to
take place on regions that produce pointer and sampled image result
ids if such ids are not used after the region.
Fixes#3787.
* validation: tighter validation of multisampled images
- if MS=1, then Sample image operand is required
- Sampling operations are not permitted when MS=1
Fixes#4057, #4058
* Fail early for multisampled image for sampling, dref, gather
* validate StorageImageMultisampled capability
The StorageImageMultisampled capability is required when declaring
an image type with with Multisampled==1 and it's a storage image (Sampled == 2)
Fixes#4061
* Allow SubpassData with Multisampled and Sampled==2
Similar to [1] DCE should be ran when this extension is enabled to
prevent unused bindings from showing up (in particular atomic counters
attached to buffers).
[1]: https://github.com/KhronosGroup/SPIRV-Tools/pull/4047
The eliminate dead member pass is written assuming that the index to an
OpAccessChain will be a 32-bit integer or 64-bit integer. That is
changed to work for any width 64-bits or less.
Fixes https://crbug.com/1151727
* Add validation for ray tracing builtins
- Remove existing InstanceId testing that was combined with VertexId in awkward ways.
- Rather than adding a new set of functions for each ray tracing builtin, add
an error table that maps the builtin ID to the 3 common VUIDs for each builtin
(I could see this being extended for other builtins in the future).
- add F32 matrix validation function
- augment existing PrimitiveId validation to verify Input storage class for the
RT stages this is accepted in, and correct the list of stages that it is actually
accepted in (only Intersection / Any Hit / Closest Hit)
* add testing for ray tracing builtins
- remove exising InstanceId testing as it was tangled in with VertexId in now weird ways
and combine it with the new tests
- add testing for ray tracing builtins
- builtins accepted in the same stages and of the same types are combined into test functions
- add some new matrix types to the code generator so they can be used for testing
This instruments ImageRead, ImageWrite and ImageFetch when applied to
texel buffers.
Also add new (but not yet generated) buffer OOB error codes differentiated
for VUID classification.
* BuildModule: optionally avoid adding new OpLine instructions
Fixes#4029 for my use case
* Fix formatting
* Create last_line_inst_ only if doing extra line tracking
* Update to final ray tracing extensions
Drop Provisional from ray tracing enums
sed -ie 's/RayQueryProvisionalKHR/RayQueryKHR/g' **/*
sed -ie 's/RayTracingProvisionalKHR/RayTracingKHR/g' **/*
Add terminator support for SpvOpIgnoreIntersectionKHR and SpvOpTerminateRayKHR
Update deps for SPIRV-Headers
* Update capability dependencies for MeshShadingNV
Accommodate https://github.com/KhronosGroup/SPIRV-Headers/pull/180
MeshShadingNV: enables PrimitiveId, Layer, and ViewportIndex
Co-authored-by: Daniel Koch <dkoch@nvidia.com>
Fix buffer oob instrumentation for matrix refs.
Matrix stride decoration is not on matrix type but is a member decoration
on the enclosing struct type. Also correctly apply matrix stride depending
on row or column major.
spirv-opt has a bug that `DebugInfoManager::AddDebugValueWithIndex()` does not
preserve `Indexes` operands of
[DebugValue](https://www.khronos.org/registry/spir-v/specs/unified1/OpenCL.DebugInfo.100.html#DebugValue).
It has to preserve all of those `Indexes` operands, but it preserves only the first index
operand.
This PR removes `DebugInfoManager::AddDebugValueWithIndex()` and lets the spirv-opt
use `DebugInfoManager::AddDebugValueForDecl()`.
`DebugInfoManager::AddDebugValueForDecl()` preserves the Indexes operand correctly.
Don't pass a constructed string as an argument to
ValidateNotCalledwithExecutionModel. That method is captured via
std::bind and it ends up using lots of stack space.
Instead, pass in:
- a Vulkan validation unique ID as an integer instead,
(with -1 meaning no VUID), and
- the const char* for the explanator text.
in 3943 the new tests should have failed, but didn't due to the AnyVUID
check not handling case with trailing whitespace. Added trimming to handle
it as easily might happen again in future
The front-end language compiler would simply emit DebugDeclare for
a variable when it is declared, which is effective through the variable's
scope. Since DebugDeclare only maps an OpVariable to a local variable,
the information can be removed when an optimization pass uses the
loaded value of the variable. DebugValue can be used to specify the
value of a variable. For each value update or phi instruction of a variable,
we can add DebugValue to help debugger inspect the variable at any
point of the program execution.
For example,
float a = 3;
... (complicated cfg) ...
foo(a); // <-- variable inspection: debugger can find DebugValue of `float a` in the nearest dominant
For the code with complicated CFG e.g., for-loop, if-statement, we
need help of ssa-rewrite to analyze the effective value of each variable
in each basic block.
If the value update of the variable happens only once and it dominates
all its uses, local-single-store-elim pass conducts the same value update
with ssa-rewrite and we have to let it add DebugValue for the value assignment.
One main issue is that we have to add DebugValue only when the value
update of a variable is visible to DebugDeclare. For example,
```
{ // scope1
%stack = OpVariable %ptr_int %int_3
{ // scope2
DebugDeclare %foo %stack <-- local variable "foo" in high-level language source code is declared as OpVariable "%stack"
// add DebugValue "foo = 3"
...
Store %stack %int_7 <-- foo = 7, add DebugValue "foo = 7"
...
// debugger can inspect the value of "foo"
}
Store %stack %int_11 <-- out of "scope2" i.e., scope of "foo". DO NOT add DebugValue "foo = 11"
}
```
However, the initalization of a variable is an exception.
For example, an argument passing of an inlined function must be done out of
the function's scope, but we must add a DebugValue for it.
```
// in HLSL
bar(float arg) { ... }
...
float foo = 3;
bar(foo);
// in SPIR-V
%arg = OpVariable
OpStore %arg %foo <-- Argument passing. Out of "float arg" scope, but we must add DebugValue for "float arg"
... body of function bar(float arg) ...
```
This PR handles the except case in local-single-store-elim pass. It adds
DebugValue for a store that is considered as an initialization.
The same exception handling code for ssa-rewrite is done by this commit: df4198e50e.
This fixes https://github.com/KhronosGroup/SPIRV-Tools/issues/3873.
In the presence of variable pointers, the reaching definition may be
another pointer. For example, the following fragment:
%2 = OpVariable %_ptr_Input_float Input
%11 = OpVariable %_ptr_Function__ptr_Input_float Function
OpStore %11 %2
%12 = OpLoad %_ptr_Input_float %11
%13 = OpLoad %float %12
corresponds to the pseudo-code:
layout(location = 0) in flat float *%2
float %13;
float *%12;
float **%11;
*%11 = %2;
%12 = *%11;
%13 = *%12;
which ultimately, should correspond to:
%13 = *%2;
During rewriting, the pointer %12 is found to be replaceable by %2.
However, when processing the load %13 = *%12, the type of %12's reaching
definition is another float pointer (%2), instead of a float value.
When this happens, we need to continue looking up the reaching definition
chain until we get to a float value or a non-target var (i.e. a variable
that cannot be SSA replaced, like %2 in this case since it is a function
argument).