include/PatriciaTreeOverUnderSetAbstractDomain.h (170 lines of code) (raw):

/* * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ #pragma once #include <initializer_list> #include "AbstractDomain.h" #include "Exceptions.h" #include "PatriciaTreeSet.h" namespace sparta { namespace ptousad_impl { template <typename Element> class OverUnderSetValue final : public AbstractValue<OverUnderSetValue<Element>> { public: OverUnderSetValue() = default; OverUnderSetValue(PatriciaTreeSet<Element> over, PatriciaTreeSet<Element> under) : m_over(std::move(over)), m_under(std::move(under)) { m_over.union_with(m_under); } void clear() override { m_over.clear(); m_under.clear(); } AbstractValueKind kind() const override { return AbstractValueKind::Value; } bool empty() const { return m_over.empty(); } const PatriciaTreeSet<Element>& over() const { return m_over; } const PatriciaTreeSet<Element>& under() const { return m_under; } void add_over(const PatriciaTreeSet<Element>& set) { m_over.union_with(set); } void add_under(const PatriciaTreeSet<Element>& set) { m_over.union_with(set); m_under.union_with(set); } void add(const OverUnderSetValue& other) { m_over.union_with(other.m_over); m_under.union_with(other.m_under); } bool leq(const OverUnderSetValue& other) const override { return m_over.is_subset_of(other.m_over) && other.m_under.is_subset_of(m_under); } bool equals(const OverUnderSetValue& other) const override { return m_over.equals(other.m_over) && m_under.equals(other.m_under); } AbstractValueKind join_with(const OverUnderSetValue& other) override { m_over.union_with(other.m_over); m_under.intersection_with(other.m_under); return AbstractValueKind::Value; } AbstractValueKind widen_with(const OverUnderSetValue& other) override { return join_with(other); } AbstractValueKind meet_with(const OverUnderSetValue& other) override { m_over.intersection_with(other.m_over); m_under.union_with(other.m_under); return m_under.is_subset_of(m_over) ? AbstractValueKind::Value : AbstractValueKind::Bottom; } AbstractValueKind narrow_with(const OverUnderSetValue& other) override { return meet_with(other); } friend std::ostream& operator<<(std::ostream& out, const OverUnderSetValue& value) { if (value.empty()) { out << "{}"; } else { out << "{over=" << value.m_over << ", under=" << value.m_under << "}"; } return out; } private: // Invariant: m_under.is_subset_of(m_over) PatriciaTreeSet<Element> m_over; PatriciaTreeSet<Element> m_under; }; } // namespace ptousad_impl /** * An implementation of powerset abstract domains that computes both an over- * and under-approximation using Patricia trees. * * This domain can only handle elements that are either unsigned integers or * pointers to objects. */ template <typename Element> class PatriciaTreeOverUnderSetAbstractDomain final : public AbstractDomainScaffolding< ptousad_impl::OverUnderSetValue<Element>, PatriciaTreeOverUnderSetAbstractDomain<Element>> { public: using Value = ptousad_impl::OverUnderSetValue<Element>; /* Return the empty over-under set. */ PatriciaTreeOverUnderSetAbstractDomain() { this->set_to_value(Value()); } explicit PatriciaTreeOverUnderSetAbstractDomain(AbstractValueKind kind) : AbstractDomainScaffolding< ptousad_impl::OverUnderSetValue<Element>, PatriciaTreeOverUnderSetAbstractDomain<Element>>(kind) {} explicit PatriciaTreeOverUnderSetAbstractDomain(const Element& e) { auto set = PatriciaTreeSet<Element>{e}; this->set_to_value(Value(/* over */ set, /* under */ set)); } explicit PatriciaTreeOverUnderSetAbstractDomain( std::initializer_list<Element> l) { auto set = PatriciaTreeSet<Element>(l); this->set_to_value(Value(/* over */ set, /* under */ set)); } explicit PatriciaTreeOverUnderSetAbstractDomain( const PatriciaTreeSet<Element>& set) { this->set_to_value(Value(/* over */ set, /* under */ set)); } explicit PatriciaTreeOverUnderSetAbstractDomain( PatriciaTreeSet<Element> over, PatriciaTreeSet<Element> under) { this->set_to_value(Value(std::move(over), std::move(under))); } static PatriciaTreeOverUnderSetAbstractDomain bottom() { return PatriciaTreeOverUnderSetAbstractDomain(AbstractValueKind::Bottom); } static PatriciaTreeOverUnderSetAbstractDomain top() { return PatriciaTreeOverUnderSetAbstractDomain(AbstractValueKind::Top); } bool empty() const { return this->is_value() && this->get_value()->empty(); } const PatriciaTreeSet<Element>& over() const { RUNTIME_CHECK(this->kind() == AbstractValueKind::Value, invalid_abstract_value() << expected_kind(AbstractValueKind::Value) << actual_kind(this->kind())); return this->get_value()->over(); } const PatriciaTreeSet<Element>& under() const { RUNTIME_CHECK(this->kind() == AbstractValueKind::Value, invalid_abstract_value() << expected_kind(AbstractValueKind::Value) << actual_kind(this->kind())); return this->get_value()->under(); } void add_over(const Element& e) { add_over(PatriciaTreeSet<Element>{e}); } void add_over(const PatriciaTreeSet<Element>& set) { if (this->is_value()) { this->get_value()->add_over(set); } else if (this->is_bottom()) { this->set_to_value(Value(/* over */ set, /* under */ {})); } } void add_under(const Element& e) { add_under(PatriciaTreeSet<Element>{e}); } void add_under(const PatriciaTreeSet<Element>& set) { if (this->is_value()) { this->get_value()->add_under(set); } else if (this->is_bottom()) { this->set_to_value(Value(/* over */ set, /* under */ set)); } } void add(const PatriciaTreeOverUnderSetAbstractDomain& other) { if (this->is_top() || other.is_bottom()) { return; } else if (other.is_top()) { this->set_to_top(); } else if (this->is_bottom()) { this->set_to_value(*other.get_value()); } else { this->get_value()->add(*other.get_value()); } } friend std::ostream& operator<<( std::ostream& out, const PatriciaTreeOverUnderSetAbstractDomain& x) { using namespace sparta; switch (x.kind()) { case AbstractValueKind::Bottom: { out << "_|_"; break; } case AbstractValueKind::Top: { out << "T"; break; } case AbstractValueKind::Value: { out << *x.get_value(); break; } } return out; } }; } // namespace sparta