On Tue, Jul 21, 2020 at 9:08 PM Patrick Palka via Gcc-patches
<[email protected]> wrote:
>
> In the testcase from the PR we are seeing excessive memory use (> 5GB)
> during constexpr evaluation, almost all of which is due to the call to
> decl_constant_value in the VAR_DECL/CONST_DECL branch of
> cxx_eval_constant_expression. We reach here every time we evaluate an
> ARRAY_REF of a constexpr VAR_DECL, which in this testcase is quite
> often, and from there decl_constant_value makes an unshared copy of the
> VAR_DECL's initializer, even though the unsharing is not needed at this
> call site (because it is up to callers of cxx_eval_constant_expression
> to unshare).
>
> To fix this, this patch moves the responsibility of unsharing the result
> of decl_constant_value, decl_really_constant_value and
> scalar_constant_value from the callee to the caller.
>
> Fortunately there's only six calls to these functions, two of which are
> from cxx_eval_constant_expression where the unsharing is undesirable.
> And in unify there is one call, to scalar_constant_value, that looks
> like:
>
> case CONST_DECL:
> if (DECL_TEMPLATE_PARM_P (parm))
> return ...;
> > if (arg != scalar_constant_value (parm))
> return ...;
>
> where we are suspiciously testing for pointer equality despite
> scalar_constant_value's unsharing behavior. This line seems to be dead
> code however, so this patch replaces it with an appropriate gcc_assert.
> Finally, this patch adds an explicit call to unshare_expr to the
> remaining three callers.
>
> Now that the the calls to decl_constant_value and
> decl_really_constant_value from cxx_eval_constant_expression no longer
> unshare their result, memory use during constexpr evaluation for the
> testcase in the PR falls from 5GB to 15MB according to -ftime-report.
>
> Bootstrapped and regtested on x86_64-pc-linux-gnu, and also tested on
> cmcstl2 and a number of other libraries. Does this look OK to commit?
Can you add the PRs testcase? Thanks for tracking this down! (but I can't
approve the patch)
Richard.
> gcc/cp/ChangeLog:
>
> PR c++/96197
> * cp-gimplify.c (cp_fold_maybe_rvalue): Call unshare_expr on the
> result of decl_constant_value.
> * cvt.c: Include gimplify.h.
> (ocp_convert): Call unshare_expr on the result of
> scalar_constant_value.
> * init.c (constant_value_1): Don't call unshare_expr here,
> so that callers can choose whether to unshare.
> * pt.c (tsubst_copy): Call unshare_expr on the result of
> scalar_constant_value.
> (unify) <case CONST_DECL>: Assert DECL_TEMPLATE_PARM_P and
> simplify accordingly.
> ---
> gcc/cp/cp-gimplify.c | 2 +-
> gcc/cp/cvt.c | 3 ++-
> gcc/cp/init.c | 2 +-
> gcc/cp/pt.c | 9 +++------
> 4 files changed, 7 insertions(+), 9 deletions(-)
>
> diff --git a/gcc/cp/cp-gimplify.c b/gcc/cp/cp-gimplify.c
> index 0e949e29c5c..5c5c44dbc5d 100644
> --- a/gcc/cp/cp-gimplify.c
> +++ b/gcc/cp/cp-gimplify.c
> @@ -2433,7 +2433,7 @@ cp_fold_maybe_rvalue (tree x, bool rval)
> tree v = decl_constant_value (x);
> if (v != x && v != error_mark_node)
> {
> - x = v;
> + x = unshare_expr (v);
> continue;
> }
> }
> diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c
> index c9e7b1ff044..a7e40a1fa51 100644
> --- a/gcc/cp/cvt.c
> +++ b/gcc/cp/cvt.c
> @@ -36,6 +36,7 @@ along with GCC; see the file COPYING3. If not see
> #include "stringpool.h"
> #include "attribs.h"
> #include "escaped_string.h"
> +#include "gimplify.h"
>
> static tree convert_to_pointer_force (tree, tree, tsubst_flags_t);
> static tree build_type_conversion (tree, tree);
> @@ -725,7 +726,7 @@ ocp_convert (tree type, tree expr, int convtype, int
> flags,
> e = mark_rvalue_use (e);
> tree v = scalar_constant_value (e);
> if (!error_operand_p (v))
> - e = v;
> + e = unshare_expr (v);
> }
> if (error_operand_p (e))
> return error_mark_node;
> diff --git a/gcc/cp/init.c b/gcc/cp/init.c
> index ef4b3c4dc3c..bf229bd2ba5 100644
> --- a/gcc/cp/init.c
> +++ b/gcc/cp/init.c
> @@ -2343,7 +2343,7 @@ constant_value_1 (tree decl, bool strict_p, bool
> return_aggregate_cst_ok_p)
> && !DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl)
> && DECL_NONTRIVIALLY_INITIALIZED_P (decl))
> break;
> - decl = unshare_expr (init);
> + decl = init;
> }
> return decl;
> }
> diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
> index 34876788a9c..4d3ee099cea 100644
> --- a/gcc/cp/pt.c
> +++ b/gcc/cp/pt.c
> @@ -16368,7 +16368,7 @@ tsubst_copy (tree t, tree args, tsubst_flags_t
> complain, tree in_decl)
> return t;
> /* If ARGS is NULL, then T is known to be non-dependent. */
> if (args == NULL_TREE)
> - return scalar_constant_value (t);
> + return unshare_expr (scalar_constant_value (t));
>
> /* Unfortunately, we cannot just call lookup_name here.
> Consider:
> @@ -23644,11 +23644,8 @@ unify (tree tparms, tree targs, tree parm, tree arg,
> int strict,
> strict, explain_p);
>
> case CONST_DECL:
> - if (DECL_TEMPLATE_PARM_P (parm))
> - return unify (tparms, targs, DECL_INITIAL (parm), arg, strict,
> explain_p);
> - if (arg != scalar_constant_value (parm))
> - return unify_template_argument_mismatch (explain_p, parm, arg);
> - return unify_success (explain_p);
> + gcc_assert (DECL_TEMPLATE_PARM_P (parm));
> + return unify (tparms, targs, DECL_INITIAL (parm), arg, strict,
> explain_p);
>
> case FIELD_DECL:
> case TEMPLATE_DECL:
> --
> 2.28.0.rc1
>