Replaces OpIAdd with OpIAddCarry, OpISub with OpISubBorrow, OpIMul with
OpUMulExtended or OpSMulExtended and stores the result into a fresh_id
representing a structure. Extracts the first element of the result into
the original result_id. This value is the same as the result of the
original instruction.
Fixes#3577
This PR introduces TransformationAddLoopPreheader, which, given
a loop header and enough fresh ids, adds a loop preheader, updating
all the references so that this new block is the only out-of-loop
predecessor of the header, which branches unconditionally to the
header.
See the discussion in #3095.
Adds a transformation that takes a pair of instruction descriptors to
OpLoad and OpStore that have the same intermediate value and replaces
the OpStore with an equivalent OpCopyMemory.
Fixes#3353.
This PR generalises TransformationAddAccessChain so that dynamic
indices for non-struct composites (with clamping to ensure that
accesses are in-bound) are allowed.
The transformation will add instructions to clamp any index to
a non-struct composite, regardless of whether it is a constant
or not.
Fixes#3179.
Adds a transformation that replaces instruction OpCopyMemory with
loading the source variable to an intermediate value and storing this
value into the target variable of the original OpCopyMemory instruction.
Fixes#3352
Adds a transformation that replaces instruction OpCopyObject with
storing into a new variable and immediately loading this variable to
|result_id| of the original OpCopyObject instruction.
Fixes#3351.
Add TransformationAddRelaxedDecoration, which adds the RelaxedPrecision decoration to ids of numeric instructions (those yielding 32-bit ints or floats) in dead blocks.
Fixes#3502
In this PR, the classes that represent the adjust branch weights
transformation and fuzzer pass were implemented. This transformation
adjusts the branch weights of a OpBranchConditional instruction.
The fact manager maintains an equivalence relation on data descriptors
that tracks when one data descriptor could be used in place of
another. An algorithm to compute the closure of such facts allows
deducing new synonym facts from existing facts. E.g., for two 2D
vectors u and v it is known that u.x is synonymous with v.x and u.y is
synonymous with v.y, it can be deduced that u and v are synonymous.
The closure computation algorithm is very expensive if we get large
equivalence relations.
This change addresses this in three ways:
- The size of equivalence relations is reduced by limiting the extent
to which the components of a composite are recursively noted as
being equivalent, so that when we have large synonymous arrays we do
not record all array elements as being pairwise equivalent.
- When computing the closure of facts, equivalence classes above a
certain size are simply skipped (which can lead to missed facts)
- The closure computation is performed less frequently - it is invoked
explicitly before fuzzer passes that will benefit from data synonym
facts. A new transformation is used to control its invocation, so
that fuzzing and replaying do not get out of sync.
The change also tidies up the order in which some getters are declared
in FuzzerContext.
(1) Runtime arrays are turned into fixed-size arrays, by turning
OpTypeRuntimeArray into OpTypeArray and uses of OpArrayLength into
uses of the constant used for the length of the fixed-size array.
(2) Atomic instructions are not donated, and uses of their results are
replaced with uses of constants of the result type.
In this PR, the classes that represent the toggle access chain
instruction transformation and fuzzer pass were implemented. This
transformation toggles the instructions OpAccessChain and
OpInBoundsAccessChain between them.
Fixes#3193.
This introduces a new fuzzer pass to add instructions to the module
that define equations, and support in the fact manager for recording
equation facts and deducing synonym facts from equation facts.
Initially the only equations that are supported involve OpIAdd,
OpISub, OpSNegate and OpLogicalNot, but there is scope for adding
support for equations over various other operators.
This change adds a fuzzer pass that sprinkles access chain
instructions into a module at random. This allows other passes to
have a richer set of pointers available to them, in particular the
passes that add loads and stores.
Adds a fuzzer pass that inserts function calls into the module at
random. Calls from dead blocks can be arbitrary (so long as they do
not introduce recursion), while calls from other blocks can only be to
livesafe functions.
The change fixes some oversights in transformations to replace
constants with uniforms and to obfuscate constants which testing of
this fuzzer pass identified.
This change ensures that global and local variables donated from other
modules are always initialized at their declaration in the module
being transformed. This is to help limit issues related to undefined
behaviour that might arise due to accessing uninitialized memory.
The change also introduces some helper functions in fuzzer_util to
make it easier to find the pointee types of pointer types.
This change adds fuzzer passes that sprinkle loads and stores into a
module at random, with stores restricted to occur in either dead
blocks, or to use pointers for which it is known that the pointee
value does not influence the module's overall behaviour.
The change also generalises the VariableValueIsArbitrary fact to
PointeeValueIsIrrelevant, to allow stores through access chains or
object copies of variables whose values are known to be irrelevant.
The change includes some other minor refactorings.
Adds two new fuzzer passes to add variables to a module: one that adds
Private storage class global variables, another that adds Function
storage class local variables.
This change adds a new kind of fact to the fact manager, which records
when a variable (or pointer parameter) refers to an arbitrary value,
so that anything can be stored to it, without affecting the observable
behaviour of the module, and nothing can be guaranteed about values
loaded from it. Donated modules are the current source of such
variables, and other transformations, such as outlining, have been
adapted to propagate these facts appropriately.
This change allows the generator to (optionally and at random) make
the functions of a module "livesafe" during donation. This involves
introducing a loop limiter variable to each function and gating the
number of total loop iterations for the function using that variable.
It also involves eliminating OpKill and OpUnreachable instructions
(changing them to OpReturn/OpReturnValue), and clamping access chain
indices so that they are always in-bounds.