diff options
Diffstat (limited to 'gcc/analyzer/constraint-manager.h')
-rw-r--r-- | gcc/analyzer/constraint-manager.h | 246 |
1 files changed, 246 insertions, 0 deletions
diff --git a/gcc/analyzer/constraint-manager.h b/gcc/analyzer/constraint-manager.h new file mode 100644 index 0000000..c6a40f9 --- /dev/null +++ b/gcc/analyzer/constraint-manager.h @@ -0,0 +1,246 @@ +/* Tracking equivalence classes and constraints at a point on an execution path. + Copyright (C) 2019-2020 Free Software Foundation, Inc. + Contributed by David Malcolm <dmalcolm@redhat.com>. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +<http://www.gnu.org/licenses/>. */ + +#ifndef GCC_ANALYZER_CONSTRAINT_MANAGER_H +#define GCC_ANALYZER_CONSTRAINT_MANAGER_H + +class constraint_manager; + +/* Abstract base class for specifying how state should be purged. */ + +class purge_criteria +{ +public: + virtual ~purge_criteria () {} + virtual bool should_purge_p (svalue_id sid) const = 0; +}; + +/* An equivalence class within a constraint manager: a set of + svalue_ids that are known to all be equal to each other, + together with an optional tree constant that they are equal to. */ + +class equiv_class +{ +public: + equiv_class (); + equiv_class (const equiv_class &other); + + hashval_t hash () const; + bool operator== (const equiv_class &other); + + void add (svalue_id sid, const constraint_manager &cm); + bool del (svalue_id sid); + + tree get_any_constant () const { return m_constant; } + + svalue_id get_representative () const; + + void remap_svalue_ids (const svalue_id_map &map); + + void canonicalize (); + + void print (pretty_printer *pp) const; + + /* An equivalence class can contain multiple constants (e.g. multiple + different zeroes, for different types); these are just for the last + constant added. */ + tree m_constant; + svalue_id m_cst_sid; + + // TODO: should this be a set rather than a vec? + auto_vec<svalue_id> m_vars; +}; + +/* The various kinds of constraint. */ + +enum constraint_op +{ + CONSTRAINT_NE, + CONSTRAINT_LT, + CONSTRAINT_LE +}; + +const char *constraint_op_code (enum constraint_op c_op); + +/* An ID for an equiv_class within a constraint_manager. Internally, this + is an index into a vector of equiv_class * within the constraint_manager. */ + +class equiv_class_id +{ +public: + static equiv_class_id null () { return equiv_class_id (-1); } + + equiv_class_id (unsigned idx) : m_idx (idx) {} + const equiv_class &get_obj (const constraint_manager &cm) const; + equiv_class &get_obj (constraint_manager &cm) const; + + bool operator== (const equiv_class_id &other) const + { + return m_idx == other.m_idx; + } + bool operator!= (const equiv_class_id &other) const + { + return m_idx != other.m_idx; + } + + bool null_p () const { return m_idx == -1; } + + static equiv_class_id from_int (int idx) { return equiv_class_id (idx); } + int as_int () const { return m_idx; } + + void print (pretty_printer *pp) const; + + void update_for_removal (equiv_class_id other) + { + if (m_idx > other.m_idx) + m_idx--; + } + + int m_idx; +}; + +/* A relationship between two equivalence classes in a constraint_manager. */ + +class constraint +{ + public: + constraint (equiv_class_id lhs, enum constraint_op c_op, equiv_class_id rhs) + : m_lhs (lhs), m_op (c_op), m_rhs (rhs) + { + gcc_assert (!lhs.null_p ()); + gcc_assert (!rhs.null_p ()); + } + + void print (pretty_printer *pp, const constraint_manager &cm) const; + + hashval_t hash () const; + bool operator== (const constraint &other) const; + + /* Is this an ordering, rather than a "!=". */ + bool is_ordering_p () const + { + return m_op != CONSTRAINT_NE; + } + + equiv_class_id m_lhs; + enum constraint_op m_op; + equiv_class_id m_rhs; +}; + +/* An abstract base class for use with constraint_manager::for_each_fact. */ + +class fact_visitor +{ + public: + virtual ~fact_visitor () {} + virtual void on_fact (svalue_id lhs, enum tree_code, svalue_id rhs) = 0; +}; + +/* A collection of equivalence classes and constraints on them. + + Given N svalues, this can be thought of as representing a subset of + N-dimensional space. When we call add_constraint, + we are effectively taking an intersection with that constraint. */ + +class constraint_manager +{ +public: + constraint_manager () {} + constraint_manager (const constraint_manager &other); + virtual ~constraint_manager () {} + + virtual constraint_manager *clone (region_model *) const = 0; + virtual tree maybe_get_constant (svalue_id sid) const = 0; + virtual svalue_id get_sid_for_constant (tree cst) const = 0; + virtual int get_num_svalues () const = 0; + + constraint_manager& operator= (const constraint_manager &other); + + hashval_t hash () const; + bool operator== (const constraint_manager &other) const; + bool operator!= (const constraint_manager &other) const + { + return !(*this == other); + } + + void print (pretty_printer *pp) const; + void dump_to_pp (pretty_printer *pp) const; + void dump (FILE *fp) const; + void dump () const; + + const equiv_class &get_equiv_class_by_index (unsigned idx) const + { + return *m_equiv_classes[idx]; + } + equiv_class &get_equiv_class_by_index (unsigned idx) + { + return *m_equiv_classes[idx]; + } + + equiv_class &get_equiv_class (svalue_id sid) + { + equiv_class_id ec_id = get_or_add_equiv_class (sid); + return ec_id.get_obj (*this); + } + + bool add_constraint (svalue_id lhs, enum tree_code op, svalue_id rhs); + + bool add_constraint (equiv_class_id lhs_ec_id, + enum tree_code op, + equiv_class_id rhs_ec_id); + + bool get_equiv_class_by_sid (svalue_id sid, equiv_class_id *out) const; + equiv_class_id get_or_add_equiv_class (svalue_id sid); + tristate eval_condition (equiv_class_id lhs, + enum tree_code op, + equiv_class_id rhs); + tristate eval_condition (svalue_id lhs, + enum tree_code op, + svalue_id rhs); + + void purge (const purge_criteria &p, purge_stats *stats); + + void remap_svalue_ids (const svalue_id_map &map); + + void canonicalize (unsigned num_svalue_ids); + + static void merge (const constraint_manager &cm_a, + const constraint_manager &cm_b, + constraint_manager *out, + const model_merger &merger); + + void for_each_fact (fact_visitor *) const; + + void validate () const; + + auto_delete_vec<equiv_class> m_equiv_classes; + auto_vec<constraint> m_constraints; + + private: + static void clean_merger_input (const constraint_manager &cm_in, + const one_way_svalue_id_map &map_sid_to_m, + constraint_manager *out); + + void add_constraint_internal (equiv_class_id lhs_id, + enum constraint_op c_op, + equiv_class_id rhs_id); +}; + +#endif /* GCC_ANALYZER_CONSTRAINT_MANAGER_H */ |