https://gcc.gnu.org/g:0a1d2ea57722c248777e1130de076e28c443ff8b

commit r15-7472-g0a1d2ea57722c248777e1130de076e28c443ff8b
Author: Richard Biener <rguent...@suse.de>
Date:   Tue Feb 11 10:29:18 2025 +0100

    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.

Diff:
---
 gcc/testsuite/g++.dg/lto/pr118817_0.C |  17 ++++++
 gcc/tree-ssa-pre.cc                   | 111 ++++++++++++----------------------
 gcc/tree-ssa-sccvn.cc                 |  13 +++-
 3 files changed, 65 insertions(+), 76 deletions(-)

diff --git a/gcc/testsuite/g++.dg/lto/pr118817_0.C 
b/gcc/testsuite/g++.dg/lto/pr118817_0.C
new file mode 100644
index 000000000000..ae65f34504e8
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lto/pr118817_0.C
@@ -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;
+}
diff --git a/gcc/tree-ssa-pre.cc b/gcc/tree-ssa-pre.cc
index 735893bb191e..ecf45d29e769 100644
--- a/gcc/tree-ssa-pre.cc
+++ b/gcc/tree-ssa-pre.cc
@@ -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,
diff --git a/gcc/tree-ssa-sccvn.cc b/gcc/tree-ssa-sccvn.cc
index 6d0202ad4369..06f6b0ccd724 100644
--- a/gcc/tree-ssa-sccvn.cc
+++ b/gcc/tree-ssa-sccvn.cc
@@ -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.  */

Reply via email to