tree-optimization/118817 - missed folding of PRE inserted code

When PRE inserts code it is not fully folded with following SSA
edges which can cause missed optimizations since the next fully
folding pass is way ahead, after strlen which in the PRs case leads
to diagnostics emitted on dead code.

The following mitigates the missed expression canonicalization that
happens during PHI translation where to be inserted expressions are
calculated.  It is largely refactoring and eliminating the single
use of fully_constant_expression and otherwise leverages the
work already done by vn_nary_simplify by updating the NARY with
the simplified expression.

	PR tree-optimization/118817
	* tree-ssa-pre.cc (fully_constant_expression): Fold into
	the single caller.
	(phi_translate_1): Refactor folded in fully_constant_expression.
	* tree-ssa-sccvn.cc (vn_nary_simplify): Update the NARY with
	the simplified expression.

	* g++.dg/lto/pr118817_0.C: New testcase.
This commit is contained in:
Richard Biener 2025-02-11 10:29:18 +01:00 committed by Richard Biener
parent 1bfab1dc79
commit 0a1d2ea577
3 changed files with 65 additions and 76 deletions

View file

@ -0,0 +1,17 @@
// { dg-lto-do link }
// { dg-lto-options { { -O3 -fPIC -flto -shared -std=c++20 -Wall } } }
// { dg-require-effective-target fpic }
// { dg-require-effective-target shared }
#include <memory>
#include <vector>
#include <string>
int func()
{
auto strVec = std::make_unique<std::vector<std::string>>();
strVec->emplace_back("One");
strVec->emplace_back("Two");
strVec->emplace_back("Three");
return 0;
}

View file

@ -1185,41 +1185,6 @@ get_or_alloc_expr_for_constant (tree constant)
return newexpr;
}
/* Return the folded version of T if T, when folded, is a gimple
min_invariant or an SSA name. Otherwise, return T. */
static pre_expr
fully_constant_expression (pre_expr e)
{
switch (e->kind)
{
case CONSTANT:
return e;
case NARY:
{
vn_nary_op_t nary = PRE_EXPR_NARY (e);
tree res = vn_nary_simplify (nary);
if (!res)
return e;
if (is_gimple_min_invariant (res))
return get_or_alloc_expr_for_constant (res);
if (TREE_CODE (res) == SSA_NAME)
return get_or_alloc_expr_for_name (res);
return e;
}
case REFERENCE:
{
vn_reference_t ref = PRE_EXPR_REFERENCE (e);
tree folded;
if ((folded = fully_constant_vn_reference_p (ref)))
return get_or_alloc_expr_for_constant (folded);
return e;
}
default:
return e;
}
}
/* Translate the VUSE backwards through phi nodes in E->dest, so that
it has the value it would have in E->src. Set *SAME_VALID to true
in case the new vuse doesn't change the value id of the OPERANDS. */
@ -1443,57 +1408,55 @@ phi_translate_1 (bitmap_set_t dest,
}
if (changed)
{
pre_expr constant;
unsigned int new_val_id;
PRE_EXPR_NARY (expr) = newnary;
constant = fully_constant_expression (expr);
PRE_EXPR_NARY (expr) = nary;
if (constant != expr)
/* Try to simplify the new NARY. */
tree res = vn_nary_simplify (newnary);
if (res)
{
if (is_gimple_min_invariant (res))
return get_or_alloc_expr_for_constant (res);
/* For non-CONSTANTs we have to make sure we can eventually
insert the expression. Which means we need to have a
leader for it. */
if (constant->kind != CONSTANT)
gcc_assert (TREE_CODE (res) == SSA_NAME);
/* Do not allow simplifications to non-constants over
backedges as this will likely result in a loop PHI node
to be inserted and increased register pressure.
See PR77498 - this avoids doing predcoms work in
a less efficient way. */
if (e->flags & EDGE_DFS_BACK)
;
else
{
/* Do not allow simplifications to non-constants over
backedges as this will likely result in a loop PHI node
to be inserted and increased register pressure.
See PR77498 - this avoids doing predcoms work in
a less efficient way. */
if (e->flags & EDGE_DFS_BACK)
;
else
unsigned value_id = VN_INFO (res)->value_id;
/* We want a leader in ANTIC_OUT or AVAIL_OUT here.
dest has what we computed into ANTIC_OUT sofar
so pick from that - since topological sorting
by sorted_array_from_bitmap_set isn't perfect
we may lose some cases here. */
pre_expr constant = find_leader_in_sets (value_id, dest,
AVAIL_OUT (pred));
if (constant)
{
unsigned value_id = get_expr_value_id (constant);
/* We want a leader in ANTIC_OUT or AVAIL_OUT here.
dest has what we computed into ANTIC_OUT sofar
so pick from that - since topological sorting
by sorted_array_from_bitmap_set isn't perfect
we may lose some cases here. */
constant = find_leader_in_sets (value_id, dest,
AVAIL_OUT (pred));
if (constant)
if (dump_file && (dump_flags & TDF_DETAILS))
{
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "simplifying ");
print_pre_expr (dump_file, expr);
fprintf (dump_file, " translated %d -> %d to ",
phiblock->index, pred->index);
PRE_EXPR_NARY (expr) = newnary;
print_pre_expr (dump_file, expr);
PRE_EXPR_NARY (expr) = nary;
fprintf (dump_file, " to ");
print_pre_expr (dump_file, constant);
fprintf (dump_file, "\n");
}
return constant;
fprintf (dump_file, "simplifying ");
print_pre_expr (dump_file, expr);
fprintf (dump_file, " translated %d -> %d to ",
phiblock->index, pred->index);
PRE_EXPR_NARY (expr) = newnary;
print_pre_expr (dump_file, expr);
PRE_EXPR_NARY (expr) = nary;
fprintf (dump_file, " to ");
print_pre_expr (dump_file, constant);
fprintf (dump_file, "\n");
}
return constant;
}
}
else
return constant;
}
tree result = vn_nary_op_lookup_pieces (newnary->length,

View file

@ -2598,7 +2598,8 @@ vn_nary_build_or_lookup (gimple_match_op *res_op)
}
/* Try to simplify the expression RCODE OPS... of type TYPE and return
its value if present. */
its value if present. Update NARY with a simplified expression if
it fits. */
tree
vn_nary_simplify (vn_nary_op_t nary)
@ -2608,7 +2609,15 @@ vn_nary_simplify (vn_nary_op_t nary)
gimple_match_op op (gimple_match_cond::UNCOND, nary->opcode,
nary->type, nary->length);
memcpy (op.ops, nary->op, sizeof (tree) * nary->length);
return vn_nary_build_or_lookup_1 (&op, false, true);
tree res = vn_nary_build_or_lookup_1 (&op, false, true);
if (op.code.is_tree_code () && op.num_ops <= nary->length)
{
nary->opcode = (tree_code) op.code;
nary->length = op.num_ops;
for (unsigned i = 0; i < op.num_ops; ++i)
nary->op[i] = op.ops[i];
}
return res;
}
/* Elimination engine. */