blob: a2fce740c1a80fbd092047f200e1f52688a1bfd5 [file] [log] [blame] [edit]
/*
* 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; }
// 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;
// Modifies `joinee` to be the join (aka least upper bound) of `joinee` and
// `joiner`. Returns true if `joinee` was modified, i.e. if it was not already
// an upper bound of `joiner`.
bool join(Element& joinee, const Element& joiner) 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(); }
bool join(Element& joinee, const Element& joiner) const noexcept {
return intLattice.join(joinee, joiner);
}
};
} // namespace wasm::analysis
#include "powerset-impl.h"
#endif // wasm_analysis_lattices_powerset_h