c++: decl_constant_value and unsharing [PR96197]
In the testcase from the PR we're 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, and from there decl_constant_value makes an unshared copy of the VAR_DECL's initializer. But unsharing here is unnecessary because callers of cxx_eval_constant_expression already unshare its result when necessary. To fix this excessive unsharing, this patch adds a new defaulted parameter unshare_p to decl_really_constant_value and decl_constant_value so that callers can control whether to unshare. As a simplification, we can also move the call to unshare_expr in constant_value_1 outside of the loop, since doing unshare_expr on a DECL_P is a no-op. Now that we no longer unshare the result of decl_constant_value and decl_really_constant_value from cxx_eval_constant_expression, memory use during constexpr evaluation for the testcase from the PR falls from ~5GB to 15MB according to -ftime-report. gcc/cp/ChangeLog: PR c++/96197 * constexpr.c (cxx_eval_constant_expression) <case CONST_DECL>: Pass false to decl_constant_value and decl_really_constant_value so that they don't unshare their result. * cp-tree.h (decl_constant_value): New declaration with an added bool parameter. (decl_really_constant_value): Add bool parameter defaulting to true to existing declaration. * init.c (constant_value_1): Add bool parameter which controls whether to unshare the initializer before returning. Call unshare_expr at most once. (scalar_constant_value): Pass true to constant_value_1's new bool parameter. (decl_really_constant_value): Add bool parameter and forward it to constant_value_1. (decl_constant_value): Likewise, but instead define a new overload with an added bool parameter. gcc/testsuite/ChangeLog: PR c++/96197 * g++.dg/cpp1y/constexpr-array8.C: New test.
This commit is contained in:
parent
d48cca8f21
commit
8c00059ce0
4 changed files with 45 additions and 14 deletions
|
@ -5695,9 +5695,9 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
|
|||
TREE_CONSTANT (r) = true;
|
||||
}
|
||||
else if (ctx->strict)
|
||||
r = decl_really_constant_value (t);
|
||||
r = decl_really_constant_value (t, /*unshare_p=*/false);
|
||||
else
|
||||
r = decl_constant_value (t);
|
||||
r = decl_constant_value (t, /*unshare_p=*/false);
|
||||
if (TREE_CODE (r) == TARGET_EXPR
|
||||
&& TREE_CODE (TARGET_EXPR_INITIAL (r)) == CONSTRUCTOR)
|
||||
r = TARGET_EXPR_INITIAL (r);
|
||||
|
|
|
@ -6773,7 +6773,8 @@ extern tree build_vec_delete (location_t, tree, tree,
|
|||
extern tree create_temporary_var (tree);
|
||||
extern void initialize_vtbl_ptrs (tree);
|
||||
extern tree scalar_constant_value (tree);
|
||||
extern tree decl_really_constant_value (tree);
|
||||
extern tree decl_constant_value (tree, bool);
|
||||
extern tree decl_really_constant_value (tree, bool = true);
|
||||
extern int diagnose_uninitialized_cst_or_ref_member (tree, bool, bool);
|
||||
extern tree build_vtbl_address (tree);
|
||||
extern bool maybe_reject_flexarray_init (tree, tree);
|
||||
|
|
|
@ -2272,10 +2272,12 @@ build_offset_ref (tree type, tree member, bool address_p,
|
|||
recursively); otherwise, return DECL. If STRICT_P, the
|
||||
initializer is only returned if DECL is a
|
||||
constant-expression. If RETURN_AGGREGATE_CST_OK_P, it is ok to
|
||||
return an aggregate constant. */
|
||||
return an aggregate constant. If UNSHARE_P, return an unshared
|
||||
copy of the initializer. */
|
||||
|
||||
static tree
|
||||
constant_value_1 (tree decl, bool strict_p, bool return_aggregate_cst_ok_p)
|
||||
constant_value_1 (tree decl, bool strict_p, bool return_aggregate_cst_ok_p,
|
||||
bool unshare_p)
|
||||
{
|
||||
while (TREE_CODE (decl) == CONST_DECL
|
||||
|| decl_constant_var_p (decl)
|
||||
|
@ -2343,9 +2345,9 @@ 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;
|
||||
return unshare_p ? unshare_expr (decl) : decl;
|
||||
}
|
||||
|
||||
/* If DECL is a CONST_DECL, or a constant VAR_DECL initialized by constant
|
||||
|
@ -2357,26 +2359,36 @@ tree
|
|||
scalar_constant_value (tree decl)
|
||||
{
|
||||
return constant_value_1 (decl, /*strict_p=*/true,
|
||||
/*return_aggregate_cst_ok_p=*/false);
|
||||
/*return_aggregate_cst_ok_p=*/false,
|
||||
/*unshare_p=*/true);
|
||||
}
|
||||
|
||||
/* Like scalar_constant_value, but can also return aggregate initializers. */
|
||||
/* Like scalar_constant_value, but can also return aggregate initializers.
|
||||
If UNSHARE_P, return an unshared copy of the initializer. */
|
||||
|
||||
tree
|
||||
decl_really_constant_value (tree decl)
|
||||
decl_really_constant_value (tree decl, bool unshare_p /*= true*/)
|
||||
{
|
||||
return constant_value_1 (decl, /*strict_p=*/true,
|
||||
/*return_aggregate_cst_ok_p=*/true);
|
||||
/*return_aggregate_cst_ok_p=*/true,
|
||||
/*unshare_p=*/unshare_p);
|
||||
}
|
||||
|
||||
/* A more relaxed version of scalar_constant_value, used by the
|
||||
/* A more relaxed version of decl_really_constant_value, used by the
|
||||
common C/C++ code. */
|
||||
|
||||
tree
|
||||
decl_constant_value (tree decl, bool unshare_p)
|
||||
{
|
||||
return constant_value_1 (decl, /*strict_p=*/processing_template_decl,
|
||||
/*return_aggregate_cst_ok_p=*/true,
|
||||
/*unshare_p=*/unshare_p);
|
||||
}
|
||||
|
||||
tree
|
||||
decl_constant_value (tree decl)
|
||||
{
|
||||
return constant_value_1 (decl, /*strict_p=*/processing_template_decl,
|
||||
/*return_aggregate_cst_ok_p=*/true);
|
||||
return decl_constant_value (decl, /*unshare_p=*/true);
|
||||
}
|
||||
|
||||
/* Common subroutines of build_new and build_vec_delete. */
|
||||
|
|
18
gcc/testsuite/g++.dg/cpp1y/constexpr-array8.C
Normal file
18
gcc/testsuite/g++.dg/cpp1y/constexpr-array8.C
Normal file
|
@ -0,0 +1,18 @@
|
|||
// PR c++/96197
|
||||
// { dg-do compile { target c++14 } }
|
||||
|
||||
struct S {
|
||||
S* p = this;
|
||||
};
|
||||
|
||||
constexpr S ary[5000] = {};
|
||||
|
||||
constexpr int foo() {
|
||||
int count = 0;
|
||||
for (int i = 0; i < 5000; i++)
|
||||
if (ary[i].p != nullptr)
|
||||
count++;
|
||||
return count;
|
||||
}
|
||||
|
||||
constexpr int bar = foo();
|
Loading…
Add table
Reference in a new issue