Finish moving constraint and logic functionality of out pt.c.
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
This commit is contained in:
parent
4352288a3d
commit
79c05c2bc4
@ -149,6 +149,34 @@
|
||||
* 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
|
||||
|
@ -46,7 +46,7 @@ gtfiles="\
|
||||
\$(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 \
|
||||
|
@ -905,6 +905,9 @@ normalize_constraint_expression (tree expr, bool diag = false)
|
||||
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;
|
||||
|
||||
@ -914,9 +917,44 @@ atomic_constraints_identical_p (tree t1, tree t2)
|
||||
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));
|
||||
|
||||
@ -931,6 +969,41 @@ hash_atomic_constraint (tree 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
|
||||
//
|
||||
@ -1017,6 +1090,61 @@ build_constraints (tree tr, tree dr)
|
||||
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. */
|
||||
|
||||
|
@ -1551,6 +1551,12 @@ check_constraint_info (tree t)
|
||||
#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)
|
||||
@ -7693,7 +7699,6 @@ struct diagnosing_failed_constraint
|
||||
|
||||
/* 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);
|
||||
@ -7761,8 +7766,10 @@ extern bool subsumes_constraints (tree, tree);
|
||||
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 */
|
||||
|
@ -4409,9 +4409,6 @@ cxx_init_decl_processing (void)
|
||||
/* 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"),
|
||||
|
@ -780,6 +780,73 @@ diagnose_constraint_size (tree t)
|
||||
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. */
|
||||
@ -789,6 +856,9 @@ subsumes_constraints_nonnull (tree lhs, tree rhs)
|
||||
{
|
||||
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);
|
||||
|
||||
@ -803,19 +873,20 @@ subsumes_constraints_nonnull (tree lhs, tree 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
|
||||
@ -832,3 +903,5 @@ subsumes (tree lhs, tree rhs)
|
||||
return true;
|
||||
return subsumes_constraints_nonnull (lhs, rhs);
|
||||
}
|
||||
|
||||
#include "gt-cp-logic.h"
|
||||
|
157
gcc/cp/pt.c
157
gcc/cp/pt.c
@ -28483,163 +28483,6 @@ convert_generic_types_to_packs (tree parm, int start_idx, int end_idx)
|
||||
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
|
||||
|
Loading…
Reference in New Issue
Block a user