[PATCH 3/4 v2] c++: Use two levels of caching in satisfy_atom
Jason Merrill
jason@redhat.com
Fri Nov 6 20:29:09 GMT 2020
On 11/5/20 8:40 PM, Patrick Palka wrote:
> This improves the effectiveness of caching in satisfy_atom by querying
> the cache again after we've instantiated the atom's parameter mapping.
>
> Before instantiating its mapping, the identity of an (atom,args) pair
> within the satisfaction cache is determined by idiosyncratic things like
> the level and index of each template parameter used in targets of the
> parameter mapping. For example, the associated constraints of foo in
>
> template <class T> concept range = range_v<T>;
> template <class U, class V> void foo () requires range<U> && range<V>;
>
> are range_v<T> (with mapping T -> U) /\ range_v<T> (with mapping T -> V).
> If during satisfaction the template arguments supplied for U and V are
> the same, then the satisfaction value of these two atoms will be the
> same (despite their uninstantiated parameter mappings being different).
>
> But sat_cache doesn't see this because it compares the uninstantiated
> parameter mapping and the supplied template arguments of sat_entry's
> independently. So satisy_atom on this latter atom will end up fully
> evaluating it instead of reusing the satisfaction value of the former.
>
> But there is a point when the two atoms do look the same to sat_cache,
> and that's after instantiating their parameter mappings. By querying
> the cache again at this point, we avoid substituting the instantiated
> mapping into the second atom's expression. This in general results in
> a higher cache hit rate in satisfy_atom.
>
> With this patch, compile time and memory usage for the cmcstl2 test
> test/algorithm/set_symmetric_diference4.cpp drops from 11s/1.4GB to
> 8.5s/1.2GB with an --enable-checking=release compiler.
OK.
> gcc/cp/ChangeLog:
>
> * cp-tree.h (ATOMIC_CONSTR_MAP_INSTANTIATED_P): Define this flag
> for ATOMIC_CONSTRs.
> * constraint.cc (sat_hasher::hash): Use hash_atomic_constraint
> if the flag is set, otherwise keep using a pointer hash.
> (sat_hasher::equal): Return false if the flag's setting differs
> on two atoms. Call atomic_constraints_identical_p if the flag
> is set, otherwise keep using a pointer equality test.
> (satisfy_atom): After instantiating the parameter mapping, form
> another ATOMIC_CONSTR using the instantiated mapping and query
> the cache again. Cache the satisfaction value of both atoms.
> (diagnose_atomic_constraint): Simplify now that the supplied
> atom has an instantiated mapping.
> ---
> gcc/cp/constraint.cc | 57 +++++++++++++++++++++++++++++++++-----------
> gcc/cp/cp-tree.h | 7 ++++++
> 2 files changed, 50 insertions(+), 14 deletions(-)
>
> diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
> index 613ced26e2b..9dd5d892ce9 100644
> --- a/gcc/cp/constraint.cc
> +++ b/gcc/cp/constraint.cc
> @@ -2310,17 +2310,37 @@ struct sat_hasher : ggc_ptr_hash<sat_entry>
> {
> static hashval_t hash (sat_entry *e)
> {
> - /* Since normalize_atom caches the ATOMIC_CONSTRs it returns,
> - we can assume pointer-based identity for fast hashing and
> - comparison. Even if this assumption is violated, that's
> - okay, we'll just get a cache miss. */
> + if (ATOMIC_CONSTR_MAP_INSTANTIATED_P (e->constr))
> + {
> + /* Atoms with instantiated mappings are built during satisfaction.
> + They live only inside the sat_cache, and we build one to query
> + the cache with each time we instantiate a mapping. */
> + gcc_assert (!e->args);
> + return hash_atomic_constraint (e->constr);
> + }
> +
> + /* Atoms with uninstantiated mappings are built during normalization.
> + Since normalize_atom caches the atoms it returns, we can assume
> + pointer-based identity for fast hashing and comparison. Even if this
> + assumption is violated, that's okay, we'll just get a cache miss. */
> hashval_t value = htab_hash_pointer (e->constr);
> +
> return iterative_hash_template_arg (e->args, value);
> }
>
> static bool equal (sat_entry *e1, sat_entry *e2)
> {
> - /* As in sat_hasher::hash. */
> + if (ATOMIC_CONSTR_MAP_INSTANTIATED_P (e1->constr)
> + != ATOMIC_CONSTR_MAP_INSTANTIATED_P (e2->constr))
> + return false;
> +
> + /* See sat_hasher::hash. */
> + if (ATOMIC_CONSTR_MAP_INSTANTIATED_P (e1->constr))
> + {
> + gcc_assert (!e1->args && !e2->args);
> + return atomic_constraints_identical_p (e1->constr, e2->constr);
> + }
> +
> if (e1->constr != e2->constr)
> return false;
> return template_args_equal (e1->args, e2->args);
> @@ -2614,6 +2634,18 @@ satisfy_atom (tree t, tree args, subst_info info)
> return cache.save (boolean_false_node);
> }
>
> + /* Now build a new atom using the instantiated mapping. We use
> + this atom as a second key to the satisfaction cache, and we
> + also pass it to diagnose_atomic_constraint so that diagnostics
> + which refer to the atom display the instantiated mapping. */
> + t = copy_node (t);
> + ATOMIC_CONSTR_MAP (t) = map;
> + gcc_assert (!ATOMIC_CONSTR_MAP_INSTANTIATED_P (t));
> + ATOMIC_CONSTR_MAP_INSTANTIATED_P (t) = true;
> + satisfaction_cache inst_cache (t, /*args=*/NULL_TREE, info.complain);
> + if (tree r = inst_cache.get ())
> + return cache.save (r);
> +
> /* Rebuild the argument vector from the parameter mapping. */
> args = get_mapped_args (map);
>
> @@ -2626,19 +2658,19 @@ satisfy_atom (tree t, tree args, subst_info info)
> is not satisfied. Replay the substitution. */
> if (info.noisy ())
> tsubst_expr (expr, args, info.complain, info.in_decl, false);
> - return cache.save (boolean_false_node);
> + return cache.save (inst_cache.save (boolean_false_node));
> }
>
> /* [17.4.1.2] ... lvalue-to-rvalue conversion is performed as necessary,
> and EXPR shall be a constant expression of type bool. */
> result = force_rvalue (result, info.complain);
> if (result == error_mark_node)
> - return cache.save (error_mark_node);
> + return cache.save (inst_cache.save (error_mark_node));
> if (!same_type_p (TREE_TYPE (result), boolean_type_node))
> {
> if (info.noisy ())
> diagnose_atomic_constraint (t, map, result, info);
> - return cache.save (error_mark_node);
> + return cache.save (inst_cache.save (error_mark_node));
> }
>
> /* Compute the value of the constraint. */
> @@ -2655,7 +2687,7 @@ satisfy_atom (tree t, tree args, subst_info info)
> if (result == boolean_false_node && info.noisy ())
> diagnose_atomic_constraint (t, map, result, info);
>
> - return cache.save (result);
> + return cache.save (inst_cache.save (result));
> }
>
> /* Determine if the normalized constraint T is satisfied.
> @@ -3495,14 +3527,11 @@ diagnose_atomic_constraint (tree t, tree map, tree result, subst_info info)
> diagnose_requires_expr (expr, map, info.in_decl);
> break;
> default:
> - tree a = copy_node (t);
> - ATOMIC_CONSTR_MAP (a) = map;
> if (!same_type_p (TREE_TYPE (result), boolean_type_node))
> error_at (loc, "constraint %qE has type %qT, not %<bool%>",
> - a, TREE_TYPE (result));
> + t, TREE_TYPE (result));
> else
> - inform (loc, "the expression %qE evaluated to %<false%>", a);
> - ggc_free (a);
> + inform (loc, "the expression %qE evaluated to %<false%>", t);
> }
> }
>
> diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
> index eda4c56b406..c2673fb0cef 100644
> --- a/gcc/cp/cp-tree.h
> +++ b/gcc/cp/cp-tree.h
> @@ -435,6 +435,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
> REINTERPRET_CAST_P (in NOP_EXPR)
> ALIGNOF_EXPR_STD_P (in ALIGNOF_EXPR)
> OVL_DEDUP_P (in OVERLOAD)
> + ATOMIC_CONSTR_MAP_INSTANTIATED_P (in ATOMIC_CONSTR)
> 1: IDENTIFIER_KIND_BIT_1 (in IDENTIFIER_NODE)
> TI_PENDING_TEMPLATE_FLAG.
> TEMPLATE_PARMS_FOR_INLINE.
> @@ -1593,6 +1594,12 @@ check_constraint_info (tree t)
> #define ATOMIC_CONSTR_MAP(NODE) \
> TREE_OPERAND (TREE_CHECK (NODE, ATOMIC_CONSTR), 0)
>
> +/* Whether the parameter mapping of this atomic constraint
> + is already instantiated with concrete template arguments.
> + Used only in satisfy_atom and in the satisfaction cache. */
> +#define ATOMIC_CONSTR_MAP_INSTANTIATED_P(NODE) \
> + TREE_LANG_FLAG_0 (ATOMIC_CONSTR_CHECK (NODE))
> +
> /* The expression of an atomic constraint. */
> #define ATOMIC_CONSTR_EXPR(NODE) \
> CONSTR_EXPR (ATOMIC_CONSTR_CHECK (NODE))
>
More information about the Gcc-patches
mailing list