diff options
author | Thomas Lively <tlively@google.com> | 2023-10-20 21:14:20 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-10-20 21:14:20 +0200 |
commit | b83d8679a7641312f09380e1cef0e56ceb341d18 (patch) | |
tree | ab7bbfc9b98a50e4cbf5517d5a4dbec9bcea00d0 /src/analysis/lattices | |
parent | be6a3393c36ccc1a0cb0d79b116cbe48e169f93b (diff) | |
download | binaryen-b83d8679a7641312f09380e1cef0e56ceb341d18.tar.gz binaryen-b83d8679a7641312f09380e1cef0e56ceb341d18.tar.bz2 binaryen-b83d8679a7641312f09380e1cef0e56ceb341d18.zip |
[analysis][NFC] Move powerset lattices to their own header (#6028)
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.
Diffstat (limited to 'src/analysis/lattices')
-rw-r--r-- | src/analysis/lattices/powerset-impl.h | 106 | ||||
-rw-r--r-- | src/analysis/lattices/powerset.h | 158 |
2 files changed, 264 insertions, 0 deletions
diff --git a/src/analysis/lattices/powerset-impl.h b/src/analysis/lattices/powerset-impl.h new file mode 100644 index 000000000..3390934d3 --- /dev/null +++ b/src/analysis/lattices/powerset-impl.h @@ -0,0 +1,106 @@ +/* + * 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_lattices_powerset_impl_h +#define wasm_analysis_lattices_powerset_impl_h + +#include <iostream> + +#include "powerset.h" + +namespace wasm::analysis { + +inline LatticeComparison FiniteIntPowersetLattice::compare( + const FiniteIntPowersetLattice::Element& left, + const FiniteIntPowersetLattice::Element& right) const noexcept { + // Both must be from the powerset lattice of the same set. + assert(left.bitvector.size() == right.bitvector.size()); + + // True in left, false in right. + bool leftNotRight = false; + + // True in right, false in left. + bool rightNotLeft = false; + + size_t size = left.bitvector.size(); + + for (size_t i = 0; i < size; ++i) { + leftNotRight |= (left.bitvector[i] && !right.bitvector[i]); + rightNotLeft |= (right.bitvector[i] && !left.bitvector[i]); + + // We can end early if we know neither is a subset of the other. + if (leftNotRight && rightNotLeft) { + return NO_RELATION; + } + } + + if (!leftNotRight) { + if (!rightNotLeft) { + return EQUAL; + } + return LESS; + } else if (!rightNotLeft) { + return GREATER; + } + + return NO_RELATION; +} + +inline FiniteIntPowersetLattice::Element +FiniteIntPowersetLattice::getBottom() const noexcept { + FiniteIntPowersetLattice::Element result(setSize); + return result; +} + +// We count the number of element members present in the element by counting the +// trues in the bitvector. +inline size_t FiniteIntPowersetLattice::Element::count() const { + size_t count = 0; + for (auto it : bitvector) { + count += it; + } + return count; +} + +// Least upper bound is implemented as a logical OR between the bitvectors on +// both sides. We return true if a bit is flipped in-place on the left so the +// worklist algorithm will know if when to enqueue more work. +inline bool FiniteIntPowersetLattice::Element::makeLeastUpperBound( + const FiniteIntPowersetLattice::Element& other) noexcept { + // Both must be from powerset lattice of the same set. + assert(other.bitvector.size() == bitvector.size()); + + bool modified = false; + for (size_t i = 0; i < bitvector.size(); ++i) { + // Bit is flipped on self only if self is false and other is true when self + // and other are OR'ed together. + modified |= (!bitvector[i] && other.bitvector[i]); + bitvector[i] = bitvector[i] || other.bitvector[i]; + } + + return modified; +} + +inline void FiniteIntPowersetLattice::Element::print(std::ostream& os) { + // Element member 0 is on the left, element member N is on the right. + for (auto it : bitvector) { + os << it; + } +} + +}; // namespace wasm::analysis + +#endif // wasm_analysis_lattices_powerset_impl_h diff --git a/src/analysis/lattices/powerset.h b/src/analysis/lattices/powerset.h new file mode 100644 index 000000000..92159da12 --- /dev/null +++ b/src/analysis/lattices/powerset.h @@ -0,0 +1,158 @@ +/* + * 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. + */ + +#include <unordered_map> +#include <vector> + +#include "wasm.h" + +#include "../lattice.h" + +#ifndef wasm_analysis_lattices_powerset_h +#define wasm_analysis_lattices_powerset_h + +namespace wasm::analysis { + +// Represents a powerset lattice constructed from a finite set of consecutive +// integers from 0 to n which can be represented by a bitvector. Set elements +// are represented by FiniteIntPowersetLattice::Element, which represents +// members present in each element by bits in the bitvector. +class FiniteIntPowersetLattice { + // The size of the set that the powerset lattice was created from. This is + // equivalent to the size of the Top lattice element. + size_t setSize; + +public: + FiniteIntPowersetLattice(size_t setSize) : setSize(setSize) {} + + // Returns the size of the set that the powerset lattices was created from. + size_t getSetSize() { return setSize; } + + // This represents an element of a powerset lattice. The element is itself a + // set which has set members. The bitvector tracks which possible members of + // the element are actually present. + class Element { + // If bitvector[i] is true, then member i is present in the lattice element, + // otherwise it isn't. + std::vector<bool> bitvector; + + // This constructs a bottom element, given the lattice set size. Used by the + // lattice's getBottom function. + Element(size_t latticeSetSize) : bitvector(latticeSetSize) {} + + public: + Element(Element&& source) = default; + Element(const Element& source) = default; + + Element& operator=(Element&& source) = default; + Element& operator=(const Element& source) = default; + + // Counts the number of members present the element itself. For instance, if + // we had {true, false, true}, the count would be 2. O(N) operation which + // iterates through the bitvector. + size_t count() const; + + bool get(size_t index) { return bitvector[index]; } + void set(size_t index, bool value) { bitvector[index] = value; } + + bool isTop() const { return count() == bitvector.size(); } + bool isBottom() const { return count() == 0; } + + // Calculates the LUB of this element with some other element and sets + // this element to the LUB in place. Returns true if this element before + // this method call was different than the LUB. + bool makeLeastUpperBound(const Element& other) noexcept; + + // Prints out the bits in the bitvector for a lattice element. + void print(std::ostream& os); + + friend FiniteIntPowersetLattice; + }; + + // Compares two lattice elements and returns a result indicating the + // left element's relation to the right element. + LatticeComparison compare(const Element& left, + const Element& right) const noexcept; + + // Returns an instance of the bottom lattice element. + Element getBottom() const noexcept; +}; + +// A layer of abstraction over FiniteIntPowersetLattice which maps +// set members of some type T to indices in the bitvector. Allows +// the finite powerset lattice to be generalized to arbitrary types. +template<typename T> class FinitePowersetLattice { + FiniteIntPowersetLattice intLattice; + + // Maps a bitvector index to some element member of type T. + // Used to produce initial ordering of element members. + std::vector<T> members; + + // Maps an element member of type T to a bitvector index. + std::unordered_map<T, size_t> memberIndices; + +public: + using Element = FiniteIntPowersetLattice::Element; + + // Takes in an ordered list of all elements of the set to create + // the powerset lattice from (i.e. the powerset lattice top element). This + // is used for mapping the elements to bitvector indices. + FinitePowersetLattice(std::vector<T>&& setMembers) + : intLattice(setMembers.size()), members(std::move(setMembers)) { + for (size_t i = 0; i < members.size(); ++i) { + memberIndices[members[i]] = i; + } + } + + // Iterator to access the list of element members. + using membersIterator = typename std::vector<T>::const_iterator; + membersIterator membersBegin() { return members.cbegin(); } + membersIterator membersEnd() { return members.cend(); } + size_t getSetSize() { return intLattice.getSetSize(); } + + T indexToMember(size_t index) { return members[index]; } + + size_t memberToIndex(T member) { return memberIndices[member]; } + + // Adds member to a powerset lattice element. + void add(Element* element, T member) { + element->set(memberIndices[member], true); + } + + // Removes member from a powerset lattice element. + void remove(Element* element, T member) { + element->set(memberIndices[member], false); + } + + // Checks if member is included in the element set. + bool exists(Element* element, T member) { + return element->get(memberIndices[member]); + } + + // We use implementations from FiniteIntPowersetLattice here. + LatticeComparison compare(const Element& left, + const Element& right) const noexcept { + return intLattice.compare(left, right); + } + + Element getBottom() const noexcept { return intLattice.getBottom(); } +}; + +} // namespace wasm::analysis + +#include "powerset-impl.h" + +#endif // wasm_analysis_lattices_powerset_h |