summaryrefslogtreecommitdiff
path: root/src/analysis
Commit message (Collapse)AuthorAgeFilesLines
* [NFC] Refactor LocalGraph's core getSets API (#6877)Alon Zakai2024-08-281-5/+5
| | | | | | | | | | | | | | Before we just had a map that people would access with localGraph.getSetses[get], while now it is a call localGraph.getSets(get), which more nicely hides the internal implementation details. Also rename getSetses => getSetsMap. This will allow a later PR to optimize the internals of this API. This is performance-neutral as far as I can measure. (We do replace a direct read from a data structure with a call, but the call is in a header and should always get inlined.)
* [threads] Shared basic heap types (#6667)Thomas Lively2024-06-191-9/+9
| | | | | | | | | | | Implement binary and text parsing and printing of shared basic heap types and incorporate them into the type hierarchy. To avoid the massive amount of code duplication that would be necessary if we were to add separate enum variants for each of the shared basic heap types, use bit 0 to indicate whether the type is shared and replace `getBasic()` with `getBasic(Unshared)`, which clears that bit. Update all the use sites to record whether the original type was shared and produce shared or unshared output without code duplication.
* [NFC] Add explicit deduction guides for CTAD (#6094)Thomas Lively2023-11-096-0/+19
| | | | | | | | | | | Class template argument deduction (CTAD) is a C++17 feature that allows variables to be declared with class template types without specifying the template parameters. Deduction guides are a mechanism by which template authors can control how the template parameters are inferred when CTAD is used. The Google style guide prohibits the use of CTAD except where template authors opt in to supporting it by providing explicit deduction guides. For compatibility with users adhering to Google style, set the compiler flag to check this condition and add the necessary deduction guides to make the compiler happy again.
* Update CFGWalker to generate consolidated exit blocks (#6079)Thomas Lively2023-11-062-0/+19
| | | | | | | | | | | | | | | | Previously CFGWalker designated a particular block as the "exit" block, but it was just the block that happened to appear at the end of the function that returned values by implicitly flowing them out. That exit block was not tied in any way to other blocks that might end in returns, so analyses that needed to perform some action at the end of the function would have had to perform that action at the end of the designated exit block but also separately at any return instruction. Update CFGWalker to make the exit block a synthetic empty block that is a successor of all other blocks tthat implicitly or explicitly return from the function in case there are multiple such blocks, or to make the exit block the single returning block if there is only one. This means that analyses will only perform their end-of-function actions at the end of the exit block rather than additionally at every return instruction.
* [analysis] Make it easier to implement a transfer function (#6077)Thomas Lively2023-11-026-190/+28
| | | | | | | | | Combine the `transfer` and `getDependents` methods of a transfer function so that a transfer function only has to implement `transfer`, which now returns a range of basic blocks that may need to be re-analyzed. To make it easier to implement the returned basic block range, change the requirement so that it provides iterators to `const BasicBlock*` rather than `BasicBlock`. This allows us to entirely remove cfg-impl.h.
* [analysis] Allow joining a single vector element efficiently (#6071)Thomas Lively2023-11-023-40/+68
| | | | | | | | | Previously, modifying a single vector element of a `Shared<Vector>` element required materializing a full vector to do the join. When there is just a single element to update, materializing all the other elements with bottom value is useless work. Add a `Vector<L>::SingletonElement` utility that represents but does not materialize a vector with a single non-bottom element and allow it to be passed to `Vector<L>::join`. Also update `Shared` and `Inverted` so that `SingletonElement` joins still work on vectors wrapped in those other lattices.
* [analysis] Simplify the stack lattice (#6069)Thomas Lively2023-11-021-166/+88
| | | | | | | Remove the ability to represent the top element of the stack lattice since it isn't necessary. Also simplify the element type to be a simple vector, update the lattice method implementations to be more consistent with implementations in other lattices, and make the tests more consistent with the tests for other lattices.
* [analysis] Add a "Shared" lattice to represent shared state (#6067)Thomas Lively2023-11-021-0/+126
| | | | | | | | | | | | | | | | | | | | | | The analysis framework stores a separate lattice element for each basic block being analyzed to represent the program state at the beginning of the block. However, in many analyses a significant portion of program state is not flow-sensitive, so does not benefit from having a separate copy per block. For example, an analysis might track constraints on the types of locals that do not vary across blocks, so it really only needs a single copy of the constrains for each local. It would be correct to simply duplicate the state across blocks anyway, but it would not be efficient. To make it possible to share a single copy of a lattice element across basic blocks, introduce a `Shared<L>` lattice. Mathematically, this lattice represents a single ascending chain in the underlying lattice and its elements are ordered according to sequence numbers corresponding to positions in that chain. Concretely, though, the `Shared<L>` lattice only ever materializes a single, monotonically increasing element of `L` and all of its elements provide access to that shared underlying element. `Shared<L>` will let us get the benefits of having mutable shared state in the concrete implementation of analyses without losing the benefits of keeping those analyses expressible purely in terms of the monotone framework.
* [analysis][NFC] Refactor lattice unit tests (#6065)Thomas Lively2023-11-011-0/+7
| | | | | | Many of the lattice tests were essentially copy-pasted from one lattice to the next because they all tested isomorphic subsets of the various lattices, specifically in the shape of a diamond. Refactor the code so that all lattices that have tests of this shape use the same utility test functions.
* [analysis] Add a lattice for value types (#6064)Thomas Lively2023-11-011-0/+82
| | | | | | Add a lattice that is a thin wrapper around `wasm::Type` giving it the interface of a lattice. As usual, `Type::unreachable` is the bottom element, but unlike in the underlying API, we uniformly treat `Type::none` as the top type so that we have a proper lattice.
* [analysis] Add a tuple lattice (#6062)Thomas Lively2023-10-311-0/+147
| | | | | | | This lattice combines any number of other lattices into a single lattice whose elements are tuples of elements of the other lattices. This will be one of the most important lattices in the analysis framework because it will be used to combine information about different parts of the program, e.g. locals and the value stack, into a single lattice.
* [analysis] Implement a vector lattice (#6058)Thomas Lively2023-10-312-0/+139
| | | | | | | | | | The vector lattice is nearly identical to the array lattice, except that the size of the elements is specified at runtime when the lattice object is created rather than at compile time. The code and tests are largely copy-pasted and fixed up from the array implementation, but there are a couple differences. First, initializing vector elements does not need the template magic used to initialize array elements. Second, the obvious implementations of join and meet do not work for vectors of bools because they might be specialized to be bit vectors, so we need workarounds for that particular case.
* [analysis] Implement an array lattice (#6057)Thomas Lively2023-10-311-0/+122
| | | | | The elements of `Array<L, N>` lattice are arrays of length `N` of elements of `L`, compared pairwise with each other. This lattice is a concrete implementation of what would be written L^N with pen and paper.
* [analysis][NFC] Rename parameters to join and meet methods (#6056)Thomas Lively2023-10-308-64/+64
| | | | | | Since these methods, which operate on lattice elements, moved to the lattice types, it no longer makes much sense for their parameters to be called `self` and `other`. Rename them to `joinee` and `joiner` for joins and `meetee` and `meeter` for meets.
* [analysis] Improve lattice fuzzer (#6050)Thomas Lively2023-10-272-1/+2
| | | | | | | | | | Implement new `RandomLattice` and `RandomFullLattice` utilities that are lattices randomly created from other lattices. By recursively using themselves as the parameter lattices for lattices like `Inverted` and `Lift`, these random lattices can become arbitrarily nested. Decouple the checking of lattice properties from the checking of transfer function properties by creating a new, standalone `checkLatticeProperties` function.
* [analysis] Implement a Lift lattice (#6040)Thomas Lively2023-10-253-0/+88
| | | | This lattice "lifts" another lattice by inserting a new bottom element underneath it.
* [analysis] Implement Flat lattice (#6039)Thomas Lively2023-10-251-0/+93
| | | | | Given a type `T`, `Flat<T>` is the lattice where none of the values of `T` are comparable except with themselves, but they are all greater than a common bottom element not in `T` and less than a common top element also not in `T`.
* [analysis] Add a FullLattice concept and Inverted lattice (#6038)Thomas Lively2023-10-254-4/+89
| | | | | | The FullLattice concept extends the base Lattice with `getTop` and `meet` operations. The `Inverted` lattice uses these operations to reverse the order of an arbitrary full lattice, for example to create a lattice of integers ordered by `>` rather than by `<`.
* [analysis] Implement an Int lattice (#6037)Thomas Lively2023-10-251-0/+63
| | | Implement a generic lattice template for integral types ordered by `<`.
* [analysis] Implement a Bool lattice (#6036)Thomas Lively2023-10-251-0/+47
| | | | | This is a lattice with two elements: `false` is bottom and `true` is top. Add a new gtest file for testing lattices.
* [analysis][NFC] Rename `makeLeastUpperBound` to `join` and move it to ↵Thomas Lively2023-10-255-64/+70
| | | | | | | | | | | | | | | | lattice (#6035) In general, the operation of taking the least upper bound of two lattice elements may depend on some state stored in the lattice object rather than in the elements themselves. To avoid forcing the elements to be larger and more complicated in that case (by storing a parent pointer back to the lattice), move the least upper bound operation to make it a method of the lattice rather than the lattice element. This is also more consistent with where we put e.g. the `compare` method. While we are at it, rename `makeLeastUpperBound` to `join`, which is much shorter and nicer. Usually we avoid using esoteric mathematical jargon like this, but "join" as a normal verb actually describes the operation nicely, so I think it is ok in this case.
* [analysis] Simplify core analysis code (#6034)Thomas Lively2023-10-257-138/+75
| | | | | | | | | | | | | | Simplify the monotone analyzer by replacing all the state it used to store in `BlockState` with a simple vector of lattice elements. Use simple indices to refer to both blocks and their associated states in the vector. Remove the ability for transfer functions to control the initial enqueued order of basic blocks since that was a leaky abstraction. Replace the worklist with a UniqueDeferredQueue since that has generally proven to be more efficient in smiilarly contexts, and more importantly, it has a nicer API. Make miscellaneous simplifications to other code as well. Delete a few unit tests that exposed the order in which blocks were analyzed because they printed intermediate results. These tests should be replaced with tests of analyses' public APIs in the future.
* Add missing includes (#6049)Thomas Lively2023-10-252-0/+3
| | | | These missing includes were not a problem in our standard build configuration, but were breaking other build configurations.
* [analysis][NFC] Create a TransferFunction concept (#6033)Thomas Lively2023-10-206-88/+115
| | | | | | | | | Factor the static assertions for transfer functions out into a new transfer-function.h header. The concept requires the `getDependents` method to return an input range of basic blocks, and to satisfy that requirement, fix up _indirect_ptr_iterator in cfg-impl.h so that it is a proper iterator. Remove part of the lattice fuzzer that was using a placeholder transfer function in a way that does not satisfy the new type constraints; most of that code will be overhauled in the future anyway.
* [analysis][NFC] Move the stack lattice to analysis/lattices (#6030)Thomas Lively2023-10-201-60/+72
| | | Also shorten various names in the implementation to improve readability.
* [analysis][NFC] Remove unused sign-lattice.cpp (#6029)Thomas Lively2023-10-202-46/+0
| | | | There is no header for this source file and its contents are not used anywhere. It will be easy to reintroduce the sign lattice in the future if we need it.
* [analysis][NFC] Move powerset lattices to their own header (#6028)Thomas Lively2023-10-205-139/+199
| | | | Move the powerset lattices out of lattice.h, which now only contains the Lattice concept, to their own dedicated header in a new analysis/lattices directory.
* [analysis][NFC] Use C++20 concepts for Lattice (#6027)Thomas Lively2023-10-186-90/+80
| | | | | | | | | | | | | Replace the static assertions ensuring that Lattice types have the necessary operations with a C++20 concept called `Lattice`. To avoid name conflicts with the new concept, rename existing type parameters named `Lattice` to `L`. When not building with C++20, `Lattice` is a macro that resolves to `typename` so the code continues compiling and has the same behavior, but without any eager checks of the requirements on lattices. Add a new C++20 builder to CI to ensure that future changes compile with both C++17 and C++20. Once we switch to C++20 by default, the new builder can be removed. Update the lint builder to use a recent clang-format that understands concepts.
* Lattice to model Stack (#5849)Bruce He2023-08-033-7/+261
| | | | | | | | | | | | | | | | | This change introduces StackLattice, a lattice to model stack-related behavior. It is templated on a separate lattice whose elements model some property of individual values on the stack. The StackLattice allows users to access the top of the stack, push abstract values, and pop them. Comparisons and least upper bound operations are done on a value by value basis starting from the top of the stack and moving toward the bottom. This is because it allows stacks from different scopes to be joined easily. An application of StackLattice is to model the wasm value stack. The goal is to organize lattice elements representing individual stack values in a natural way which mirrors the wasm value stack. Transfer functions operate on each stack value individually. The stack lattice is an intermediate structure which is not intended to be directly operated on. Rather, it simulates the push and pop behavior of instructions.
* Convert lattice compare function to non-static (#5848)Bruce He2023-07-281-4/+5
| | | | | Changes the static asserts checking a lattice type to require a non-static compare function instead of a static one. Also changes the compare functions of existing lattices to be non-static.
* Add a Fuzzer for Lattice and Transfer Function Properties (#5831)Bruce He2023-07-261-0/+12
| | | | | | | | | | | | | | This change adds a fuzzer which checks the following properties in abstract interpretation static analyses. - Transfer Function Monotonicity - Lattice Element Reflexivity - Lattice Element Transitivity - Lattice Element Anti-Symmetry This is done by randomly generating a module and using its functions as transfer function inputs, along with randomly generated lattice elements (states). Lattice element properties are fuzzed from the randomly generated states also.
* Remove incorrect usages of the term "setses" (#5841)Bruce He2023-07-261-20/+20
| | | This change applies to the Reaching Definitions Analysis.
* Static Analysis: Add an API to get the block index of an expression (#5822)Alon Zakai2023-07-202-0/+32
|
* Reaching Definitions Analysis for LocalGraph (#5817)Bruce He2023-07-198-67/+362
| | | | | | | | | | | This change implements a reaching definitions analysis which is intended to be equivalent to the information provided by LocalGraph, specifically the Flower class of LocalGraph. It also introduces a CRTP utility in visitor-transfer-function.h which implements most commonly found visitor-type transfer function functionalities. The MonotoneCFGAnalyzer is also modified to add a phase to collect results after the analysis is solved from the final CFG states.
* Small fixes to lattice and analyzer (#5815)Bruce He2023-07-132-9/+9
| | | Updates comments. Moves wasm-traversal.h to transfer function classes.
* Generalize Finite Powerset Lattice to Any Given Type (#5800)Bruce He2023-07-063-21/+72
| | | | | | | | | | This change creates a lattice, FinitePowersetLattice, to represent finite powerset lattices constructed from sets containing members of arbitrary type The bitvector finite powerset lattice class is renamed FiniteIntPowersetLattice. The templated FinitePowersetLattice class contains a FiniteIntPowersetLattice object, and over that provides functionality to map lattice element members to bitvector indices. Methods are also provided by the lattice to add or remove members of the given type from lattice members as an abstraction over flipping bits in the bitvector.
* Make the Transfer Function a Generic, Interchangeable Type for the Monotone ↵Bruce He2023-07-064-136/+218
| | | | | | | Analyzer (#5794) This change makes the transfer function an object separate from the monotone analyzer. The transfer function class type is a generic template of the monotone analyzer, and an instance of the transfer function is instantiated and then passed into the monotone analyzer via its constructor. The API of the transfer function is enforced by a static assertion. This change also introduces LivenessTransferFunction as a transfer function for liveness analysis as an example.
* Dynamic Sized Bitvector Powerset Lattice for Static Analysis (#5784)Bruce He2023-06-295-171/+234
| | | This change introduces a finite-height powerset lattice FinitePowersetLattice where each element's height is determined when constructed in runtime. This is implemented using a vector of `bools. This change also modifies BlockState and MonotoneCFGAnalyzer to be templated on a generic lattice type instead of using a hardcoded lattice. It additionally fixes an iterator bug in MonotoneCFGAnalyzer::fromCFG which assigned a temporary iterator object as predecessor and successor pointers to BlockStates instead of pointers to actual BlockState objects.
* Liveness Analysis Proof of Concept (#5771)Bruce He2023-06-237-0/+410
| | | This introduces a limited monotone flow-sensitive liveness analysis on local indices as an initial proof of concept for the creation of a monotone flow-sensitive static analysis framework. Tests are included in test/gtest/cfg.cpp.
* avoid incomplete type in a vector (#5730)walkingeyerobot2023-05-171-17/+17
| | | | | Swap the order of struct declarations to avoid using an incomplete type in a vector. In C++20, using std::vector with an incomplete type often becomes a build failure due to increased usage of constexpr for vector members.
* [analysis] Add a new iterable CFG utility (#5712)Thomas Lively2023-05-124-0/+331
Add a new "analysis" source directory that will contain the source for a new static program analysis framework. To start the framework, add a CFG utility that provides convenient iterators for iterating through the basic blocks of the CFG as well as the predecessors, successors, and contents of each block. The new CFGs are constructed using the existing CFGWalker, but they are different in that the new utility is meant to provide a usable representation of a CFG whereas CFGWalker is meant to allow collecting arbitrary information about each basic block in a CFG. For testing and debugging purposes, add `print` methods to CFGs and basic blocks. This requires exposing the ability to print expression contents excluding children, which was something we previously did only for StackIR. Also add a new gtest file with a test for constructing and printing a CFG. The test reveals some strange properties of the current CFG construction, including empty blocks and strange placement of `loop` instructions, but fixing these problems is left as future work.