Also, reimplement and re-enable subsumption caching.
gcc/cp/
* config-lang.in (gtfiles): Add logic.cc.
* constraint.cc (atomic_constraints_identical_p): Add assertions.
(hash_atomic_constraint): Likewise.
(constraints_equivalent_p): New.
(inchash::add_constraint): New.
(iterative_hash_constraint): New.
(decl_constraints): Moved from pt.c.
(get_constraints): Likewise.
(set_constraints): Likewise.
(remove_constraints): Likewise.
* cp-tree.h (CONSTR_P): New.
(init_constraint_processing): Remove.
(constraints_equivalent_p, iterative_hash_constraint): Declare.
* decl.c (cxx_init_decl_processing): Don't initialize constraints.
* logic.cc (subsumption_entry): Moved from pt.c.
(subsumption_hasher): Likewise.
(subsumption_cache): Likewise.
(lookup_subsumption): Likewise.
(save_subsumption): Likewise.
(subsumes_constraints_nonnull): Use subsumption cache.
* pt.c: Move aforementioned declarations out of this file.
(init_constraint_processing): Remove.
From-SVN: r277407
* decl.c (cxx_maybe_build_cleanup): When clearing location of cleanup,
if cleanup is a nop, clear location of its operand too.
+2019-10-15 Andrew Sutton <asutton@lock3software.com>
+
+ Finish moving constraint and logic functionality of out pt.c.
+ Reimplement and re-enable subsumption caching.
+
+ * config-lang.in (gtfiles): Add logic.cc.
+ * constraint.cc (atomic_constraints_identical_p): Add assertions.
+ (hash_atomic_constraint): Likewise.
+ (constraints_equivalent_p): New.
+ (inchash::add_constraint): New.
+ (iterative_hash_constraint): New.
+ (decl_constraints): Moved from pt.c.
+ (get_constraints): Likewise.
+ (set_constraints): Likewise.
+ (remove_constraints): Likewise.
+ * cp-tree.h (CONSTR_P): New.
+ (init_constraint_processing): Remove.
+ (constraints_equivalent_p, iterative_hash_constraint): Declare.
+ * decl.c (cxx_init_decl_processing): Don't initialize constraints.
+ * logic.cc (subsumption_entry): Moved from pt.c.
+ (subsumption_hasher): Likewise.
+ (subsumption_cache): Likewise.
+ (lookup_subsumption): Likewise.
+ (save_subsumption): Likewise.
+ (subsumes_constraints_nonnull): Use subsumption cache.
+ * pt.c: Move aforementioned declarations out of this file.
+ (init_constraint_processing): Remove.
+
2019-10-15 Andrew Sutton <asutton@lock3software.com>
* parser.c (cp_parser_constructor_declarator_p): Pass an empty
\$(srcdir)/cp/except.c \
\$(srcdir)/cp/friend.c \
\$(srcdir)/cp/init.c \
-\$(srcdir)/cp/lambda.c \$(srcdir)/cp/lex.c \
+\$(srcdir)/cp/lambda.c \$(srcdir)/cp/lex.c \$(srcdir)/cp/logic.cc \
\$(srcdir)/cp/mangle.c \$(srcdir)/cp/method.c \
\$(srcdir)/cp/name-lookup.c \
\$(srcdir)/cp/parser.c \$(srcdir)/cp/pt.c \
bool
atomic_constraints_identical_p (tree t1, tree t2)
{
+ gcc_assert (TREE_CODE (t1) == ATOMIC_CONSTR);
+ gcc_assert (TREE_CODE (t2) == ATOMIC_CONSTR);
+
if (ATOMIC_CONSTR_EXPR (t1) != ATOMIC_CONSTR_EXPR (t2))
return false;
return true;
}
+/* True if T1 and T2 are equivalent, meaning they have the same syntactic
+ structure and all corresponding constraints are identical. */
+
+bool
+constraints_equivalent_p (tree t1, tree t2)
+{
+ gcc_assert (CONSTR_P (t1));
+ gcc_assert (CONSTR_P (t2));
+
+ if (TREE_CODE (t1) != TREE_CODE (t2))
+ return false;
+
+ switch (TREE_CODE (t1))
+ {
+ case CONJ_CONSTR:
+ case DISJ_CONSTR:
+ if (!constraints_equivalent_p (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0)))
+ return false;
+ if (!constraints_equivalent_p (TREE_OPERAND (t1, 1), TREE_OPERAND (t2, 1)))
+ return false;
+ break;
+ case ATOMIC_CONSTR:
+ if (!atomic_constraints_identical_p(t1, t2))
+ return false;
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ return true;
+}
+
+/* Compute the hash value for T. */
+
hashval_t
hash_atomic_constraint (tree t)
{
+ gcc_assert (TREE_CODE (t) == ATOMIC_CONSTR);
+
/* Hash the identity of the expression. */
hashval_t val = htab_hash_pointer (ATOMIC_CONSTR_EXPR (t));
return val;
}
+namespace inchash
+{
+
+static void
+add_constraint (tree t, hash& h)
+{
+ h.add_int(TREE_CODE (t));
+ switch (TREE_CODE (t))
+ {
+ case CONJ_CONSTR:
+ case DISJ_CONSTR:
+ add_constraint (TREE_OPERAND (t, 0), h);
+ add_constraint (TREE_OPERAND (t, 1), h);
+ break;
+ case ATOMIC_CONSTR:
+ h.merge_hash (hash_atomic_constraint (t));
+ break;
+ default:
+ gcc_unreachable ();
+ }
+}
+
+}
+
+/* Computes a hash code for the constraint T. */
+
+hashval_t
+iterative_hash_constraint (tree t, hashval_t val)
+{
+ gcc_assert (CONSTR_P (t));
+ inchash::hash h (val);
+ inchash::add_constraint (t, h);
+ return h.end ();
+}
+
// -------------------------------------------------------------------------- //
// Constraint Semantic Processing
//
return (tree)ci;
}
+/* A mapping from declarations to constraint information. */
+
+static GTY ((cache)) tree_cache_map *decl_constraints;
+
+/* Returns the template constraints of declaration T. If T is not
+ constrained, return NULL_TREE. Note that T must be non-null. */
+
+tree
+get_constraints (tree t)
+{
+ if (!flag_concepts)
+ return NULL_TREE;
+ if (!decl_constraints)
+ return NULL_TREE;
+
+ gcc_assert (DECL_P (t));
+ if (TREE_CODE (t) == TEMPLATE_DECL)
+ t = DECL_TEMPLATE_RESULT (t);
+ tree* found = decl_constraints->get (t);
+ if (found)
+ return *found;
+ else
+ return NULL_TREE;
+}
+
+/* Associate the given constraint information CI with the declaration
+ T. If T is a template, then the constraints are associated with
+ its underlying declaration. Don't build associations if CI is
+ NULL_TREE. */
+
+void
+set_constraints (tree t, tree ci)
+{
+ if (!ci)
+ return;
+ gcc_assert (t && flag_concepts);
+ if (TREE_CODE (t) == TEMPLATE_DECL)
+ t = DECL_TEMPLATE_RESULT (t);
+ bool found = hash_map_safe_put<hm_ggc> (decl_constraints, t, ci);
+ gcc_assert (!found);
+}
+
+/* Remove the associated constraints of the declaration T. */
+
+void
+remove_constraints (tree t)
+{
+ gcc_assert (DECL_P (t));
+ if (TREE_CODE (t) == TEMPLATE_DECL)
+ t = DECL_TEMPLATE_RESULT (t);
+
+ if (decl_constraints)
+ decl_constraints->remove (t);
+}
+
/* Returns the template-head requires clause for the template
declaration T or NULL_TREE if none. */
#define PLACEHOLDER_TYPE_CONSTRAINTS(NODE) \
DECL_SIZE_UNIT (TYPE_NAME (NODE))
+/* True if NODE is a constraint. */
+#define CONSTR_P(NODE) \
+ (TREE_CODE (NODE) == ATOMIC_CONSTR \
+ || TREE_CODE (NODE) == CONJ_CONSTR \
+ || TREE_CODE (NODE) == DISJ_CONSTR)
+
/* Valid for any normalized constraint. */
#define CONSTR_CHECK(NODE) \
TREE_CHECK3 (NODE, ATOMIC_CONSTR, CONJ_CONSTR, DISJ_CONSTR)
/* in constraint.cc */
-extern void init_constraint_processing ();
extern cp_expr finish_constraint_or_expr (location_t, cp_expr, cp_expr);
extern cp_expr finish_constraint_and_expr (location_t, cp_expr, cp_expr);
extern cp_expr finish_constraint_primary_expr (cp_expr);
extern bool strictly_subsumes (tree, tree, tree);
extern bool weakly_subsumes (tree, tree, tree);
extern int more_constrained (tree, tree);
+extern bool constraints_equivalent_p (tree, tree);
extern bool atomic_constraints_identical_p (tree, tree);
-extern hashval_t hash_atomic_constraint (tree);
+extern hashval_t iterative_hash_constraint (tree, hashval_t);
+extern hashval_t hash_atomic_constraint (tree);
extern void diagnose_constraints (location_t, tree, tree);
/* in logic.cc */
/* Ensure attribs.c is initialized. */
init_attributes ();
- /* Ensure constraint.cc is initialized. */
- init_constraint_processing ();
-
extvisattr = build_tree_list (get_identifier ("externally_visible"),
NULL_TREE);
newattrs = tree_cons (get_identifier ("alloc_size"),
return false;
}
+/* Key/value pair for caching subsumption results. This associates a pair of
+ constraints with a boolean value indicating the result. */
+
+struct GTY((for_user)) subsumption_entry
+{
+ tree lhs;
+ tree rhs;
+ bool result;
+};
+
+/* Hashing function and equality for constraint entries. */
+
+struct subsumption_hasher : ggc_ptr_hash<subsumption_entry>
+{
+ static hashval_t hash (subsumption_entry *e)
+ {
+ hashval_t val = 0;
+ val = iterative_hash_constraint (e->lhs, val);
+ val = iterative_hash_constraint (e->rhs, val);
+ return val;
+ }
+
+ static bool equal (subsumption_entry *e1, subsumption_entry *e2)
+ {
+ if (!constraints_equivalent_p (e1->lhs, e2->lhs))
+ return false;
+ if (!constraints_equivalent_p (e1->rhs, e2->rhs))
+ return false;
+ return true;
+ }
+};
+
+/* Caches the results of subsumes_non_null(t1, t1). */
+
+static GTY ((deletable)) hash_table<subsumption_hasher> *subsumption_cache;
+
+/* Search for a previously cached subsumption result. */
+
+static bool*
+lookup_subsumption (tree t1, tree t2)
+{
+ if (!subsumption_cache)
+ return NULL;
+ subsumption_entry elt = { t1, t2, false };
+ subsumption_entry* found = subsumption_cache->find (&elt);
+ if (found)
+ return &found->result;
+ else
+ return 0;
+}
+
+/* Save a subsumption result. */
+
+static bool
+save_subsumption (tree t1, tree t2, bool result)
+{
+ if (!subsumption_cache)
+ subsumption_cache = hash_table<subsumption_hasher>::create_ggc(31);
+ subsumption_entry elt = {t1, t2, result};
+ subsumption_entry** slot = subsumption_cache->find_slot (&elt, INSERT);
+ subsumption_entry* entry = ggc_alloc<subsumption_entry> ();
+ *entry = elt;
+ *slot = entry;
+ return result;
+}
+
+
/* Returns true if the LEFT constraint subsume the RIGHT constraints.
This is done by deriving a proof of the conclusions on the RIGHT
from the assumptions on the LEFT assumptions. */
{
auto_timevar time (TV_CONSTRAINT_SUB);
+ if (bool *b = lookup_subsumption(lhs, rhs))
+ return *b;
+
int n1 = dnf_size (lhs);
int n2 = cnf_size (rhs);
}
/* Decompose the smaller of the two formulas, and recursively
- check the implication using the larger. Note that for
- constraints that are largely comprised of conjunctions the
- it will usually be the case that n1 <= n2. */
+ check for implication of the larger. */
+ bool result;
if (n1 <= n2)
{
formula dnf = decompose_antecedents (lhs);
- return derive_proofs (dnf, rhs, left);
+ result = derive_proofs (dnf, rhs, left);
}
else
{
formula cnf = decompose_consequents (rhs);
- return derive_proofs (cnf, lhs, right);
+ result = derive_proofs (cnf, lhs, right);
}
+
+ return save_subsumption (lhs, rhs, result);
}
/* Returns true if the LEFT constraints subsume the RIGHT
return true;
return subsumes_constraints_nonnull (lhs, rhs);
}
+
+#include "gt-cp-logic.h"
return tsubst (parm, replacement, tf_none, NULL_TREE);
}
-/* A mapping from declarations to constraint information. Note that
- both templates and their underlying declarations are mapped to the
- same constraint information.
-
- FIXME: This is defined in pt.c because garbage collection
- code is not being generated for constraint.cc. */
-
-static GTY ((cache)) tree_cache_map *decl_constraints;
-
-/* Returns the template constraints of declaration T. If T is not
- constrained, return NULL_TREE. Note that T must be non-null. */
-
-tree
-get_constraints (tree t)
-{
- if (!flag_concepts)
- return NULL_TREE;
- if (!decl_constraints)
- return NULL_TREE;
-
- gcc_assert (DECL_P (t));
- if (TREE_CODE (t) == TEMPLATE_DECL)
- t = DECL_TEMPLATE_RESULT (t);
- tree* found = decl_constraints->get (t);
- if (found)
- return *found;
- else
- return NULL_TREE;
-}
-
-/* Associate the given constraint information CI with the declaration
- T. If T is a template, then the constraints are associated with
- its underlying declaration. Don't build associations if CI is
- NULL_TREE. */
-
-void
-set_constraints (tree t, tree ci)
-{
- if (!ci)
- return;
- gcc_assert (t && flag_concepts);
- if (TREE_CODE (t) == TEMPLATE_DECL)
- t = DECL_TEMPLATE_RESULT (t);
- bool found = hash_map_safe_put<hm_ggc> (decl_constraints, t, ci);
- gcc_assert (!found);
-}
-
-/* Remove the associated constraints of the declaration T. */
-
-void
-remove_constraints (tree t)
-{
- gcc_assert (DECL_P (t));
- if (TREE_CODE (t) == TEMPLATE_DECL)
- t = DECL_TEMPLATE_RESULT (t);
-
- if (decl_constraints)
- decl_constraints->remove (t);
-}
-
-static hashval_t
-hash_subsumption_args (tree t1, tree t2)
-{
- gcc_assert (TREE_CODE (t1) == CHECK_CONSTR);
- gcc_assert (TREE_CODE (t2) == CHECK_CONSTR);
- int val = 0;
- val = iterative_hash_object (CHECK_CONSTR_CONCEPT (t1), val);
- val = iterative_hash_template_arg (CHECK_CONSTR_ARGS (t1), val);
- val = iterative_hash_object (CHECK_CONSTR_CONCEPT (t2), val);
- val = iterative_hash_template_arg (CHECK_CONSTR_ARGS (t2), val);
- return val;
-}
-
-/* Compare the constraints of two subsumption entries. The LEFT1 and
- LEFT2 arguments comprise the first subsumption pair and the RIGHT1
- and RIGHT2 arguments comprise the second. These are all CHECK_CONSTRs. */
-
-static bool
-comp_subsumption_args (tree left1, tree left2, tree right1, tree right2)
-{
- if (CHECK_CONSTR_CONCEPT (left1) == CHECK_CONSTR_CONCEPT (right1))
- if (CHECK_CONSTR_CONCEPT (left2) == CHECK_CONSTR_CONCEPT (right2))
- if (comp_template_args (CHECK_CONSTR_ARGS (left1),
- CHECK_CONSTR_ARGS (right1)))
- return comp_template_args (CHECK_CONSTR_ARGS (left2),
- CHECK_CONSTR_ARGS (right2));
- return false;
-}
-
-/* Key/value pair for learning and memoizing subsumption results. This
- associates a pair of check constraints (including arguments) with
- a boolean value indicating the result. */
-
-struct GTY((for_user)) subsumption_entry
-{
- tree t1;
- tree t2;
- bool result;
-};
-
-/* Hashing function and equality for constraint entries. */
-
-struct subsumption_hasher : ggc_ptr_hash<subsumption_entry>
-{
- static hashval_t hash (subsumption_entry *e)
- {
- return hash_subsumption_args (e->t1, e->t2);
- }
-
- static bool equal (subsumption_entry *e1, subsumption_entry *e2)
- {
- ++comparing_specializations;
- bool eq = comp_subsumption_args(e1->t1, e1->t2, e2->t1, e2->t2);
- --comparing_specializations;
- return eq;
- }
-};
-
-static GTY (()) hash_table<subsumption_hasher> *subsumption_table;
-
-/* Search for a previously cached subsumption result. */
-
-bool*
-lookup_subsumption_result (tree t1, tree t2)
-{
- subsumption_entry elt = { t1, t2, false };
- subsumption_entry* found = subsumption_table->find (&elt);
- if (found)
- return &found->result;
- else
- return 0;
-}
-
-/* Save a subsumption result. */
-
-bool
-save_subsumption_result (tree t1, tree t2, bool result)
-{
- subsumption_entry elt = {t1, t2, result};
- subsumption_entry** slot = subsumption_table->find_slot (&elt, INSERT);
- subsumption_entry* entry = ggc_alloc<subsumption_entry> ();
- *entry = elt;
- *slot = entry;
- return result;
-}
-
-/* Set up the hash table for constraint association. */
-
-void
-init_constraint_processing (void)
-{
- if (!flag_concepts)
- return;
-
- subsumption_table = hash_table<subsumption_hasher>::create_ggc(37);
-}
-
GTY(()) tree current_failed_constraint;
/* __integer_pack(N) in a pack expansion expands to a sequence of numbers from