diff options
author | Thomas Lively <tlively@google.com> | 2023-05-12 11:27:29 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-05-12 09:27:29 -0700 |
commit | 64e5a99ee014af3a138a36f5a87addfacfc95f0c (patch) | |
tree | a322095dfe09f1b361964682f56bc5c6f963e46a /src/analysis/cfg-impl.h | |
parent | 7d5d24f400019ff023b65ccdb3c1d8d07ebb00a5 (diff) | |
download | binaryen-64e5a99ee014af3a138a36f5a87addfacfc95f0c.tar.gz binaryen-64e5a99ee014af3a138a36f5a87addfacfc95f0c.tar.bz2 binaryen-64e5a99ee014af3a138a36f5a87addfacfc95f0c.zip |
[analysis] Add a new iterable CFG utility (#5712)
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.
Diffstat (limited to 'src/analysis/cfg-impl.h')
-rw-r--r-- | src/analysis/cfg-impl.h | 140 |
1 files changed, 140 insertions, 0 deletions
diff --git a/src/analysis/cfg-impl.h b/src/analysis/cfg-impl.h new file mode 100644 index 000000000..cf348fa09 --- /dev/null +++ b/src/analysis/cfg-impl.h @@ -0,0 +1,140 @@ +/* + * Copyright 2023 WebAssembly Community Group participants + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef wasm_analysis_cfg_impl_h +#define wasm_analysis_cfg_impl_h + +#include "cfg.h" + +namespace wasm::analysis { + +// An iterator over a sequence of contiguous pointers (represented as a pointer +// to a pointer in the sequence) that dereferences the pointed-to pointer. +// TODO: Move this to its own public header if there is ever another use for it. +template<typename T> struct _indirect_ptr_iterator { + using iterator_category = std::random_access_iterator_tag; + using value_type = T; + using different_type = off_t; + using reference = const T&; + using pointer = const T*; + + const T* const* ptr; + + const T& operator*() const { return **ptr; } + + const T& operator[](int n) const { return **(ptr + n); } + + _indirect_ptr_iterator& operator+=(int n) { + ptr += n; + return *this; + } + + _indirect_ptr_iterator& operator-=(int n) { + ptr -= n; + return *this; + } + + _indirect_ptr_iterator& operator++() { return *this += 1; } + + _indirect_ptr_iterator operator++(int) { + _indirect_ptr_iterator it = *this; + ++(*this); + return it; + } + + _indirect_ptr_iterator& operator--() { return *this -= 1; } + + _indirect_ptr_iterator operator--(int) { + _indirect_ptr_iterator it = *this; + --(*this); + return it; + } + + _indirect_ptr_iterator operator+(int n) const { + _indirect_ptr_iterator it = *this; + it += n; + return it; + } + + _indirect_ptr_iterator operator-(int n) const { + _indirect_ptr_iterator it = *this; + it -= n; + return it; + } + + bool operator==(const _indirect_ptr_iterator& other) const { + return ptr == other.ptr; + } + + bool operator!=(const _indirect_ptr_iterator& other) const { + return !(*this == other); + } + + bool operator<(const _indirect_ptr_iterator& other) const { + return ptr < other.ptr; + } + + bool operator>(const _indirect_ptr_iterator& other) const { + return ptr > other.ptr; + } + + bool operator<=(const _indirect_ptr_iterator& other) const { + return ptr <= other.ptr; + } + + bool operator>=(const _indirect_ptr_iterator& other) const { + return ptr >= other.ptr; + } +}; + +template<typename T> +_indirect_ptr_iterator<T> operator+(int n, + const _indirect_ptr_iterator<T>& it) { + return it + n; +} + +// Wraps a vector of pointers and provides dereferencing iterators for it. +template<typename T> struct _indirect_ptr_vec { + using iterator = _indirect_ptr_iterator<T>; + + const std::vector<T*>& vec; + + _indirect_ptr_vec(const std::vector<T*>& vec) : vec(vec) {} + + iterator begin() const { return {&vec.data()[0]}; } + iterator end() const { return {&vec.data()[vec.size()]}; } +}; + +struct BasicBlock::Predecessors : _indirect_ptr_vec<BasicBlock> { + Predecessors(const BasicBlock& block) + : _indirect_ptr_vec(block.predecessors) {} +}; + +struct BasicBlock::Successors : _indirect_ptr_vec<BasicBlock> { + Successors(const BasicBlock& block) : _indirect_ptr_vec(block.successors) {} +}; + +inline BasicBlock::Predecessors BasicBlock::preds() const { + return Predecessors(*this); +} + +inline BasicBlock::Successors BasicBlock::succs() const { + return Successors(*this); +} + +} // namespace wasm::analysis + +#endif // wasm_analysis_cfg_impl_h |