https://gcc.gnu.org/g:056a01f9fa85c584ed97533e75b50160d5993613

commit r14-11658-g056a01f9fa85c584ed97533e75b50160d5993613
Author: Jakub Jelinek <ja...@redhat.com>
Date:   Sat Apr 12 13:13:53 2025 +0200

    bitintlower: Fix up handling of SSA_NAME copies in coalescing [PR119722]
    
    The following patch is miscompiled, because during the limited
    SSA name coalescing the bitintlower pass does we incorrectly don't
    register a conflict.
    This is on
      <bb 4> [local count: 1073741824]:
      # b_17 = PHI <b_19(3), 8(2)>
      g.4_13 = g;
      _14 = g.4_13 >> 50;
      _15 = (unsigned int) _14;
      _21 = b_17;
      _16 = (unsigned int) _21;
      s_22 = _15 + _16;
      return s_22;
    basic block where in the map->bitint bitmap we track 14, 17 and 19.
    The build_bitint_stmt_ssa_conflicts "hook" has special code where
    it tracks uses at the final statements of mergeable operations, so
    e.g. the
      _16 = (unsigned int) _21;
    statement is considered to be use of b_17 because _21 is not in
    map->bitmap (or large_huge.m_names), i.e. is mergeable.
    The problem is that build_ssa_conflict_graph has special code to handle
    SSA_NAME copies and _21 = b_17; is gimple_assign_copy_p.  In such cases
    it calls live_track_clear_var on the rhs1.  The problem is that
    on the above bb, after we note in the _16 = (unsigned int) _21;
    stmt we need b_17 the generic code makes us forget that because
    of the copy statement, and then build_bitint_stmt_ssa_conflicts
    ignores it completely (because _21 is large/huge bitint and is
    not in map->bitint, so assumed to be handled by a later stmt in the
    bb, for backwards walk like this before this one).
    As the b_17 use is ignored, the coalescing thinks it can put
    all of b_17, b_19 and _14 into the same partition, which is wrong,
    while we can and should coalesce b_17 and b_19, _14 needs to be a different
    temporary because b_17 is set before and used after _14 has been written.
    
    The following patch fixes it by handling gimple_assign_copy_p in two
    separate spots, move the generic coalesce handling of it after
    build_ssa_conflict_graph (where build_ssa_conflict_graph handling
    doesn't fall through to that, it does continue after the call) and
    inside of build_ssa_conflict_graph it performs it too, but only if
    the lhs is not mergeable large/huge bitint.
    
    2025-04-12  Jakub Jelinek  <ja...@redhat.com>
    
            PR tree-optimization/119722
            * gimple-lower-bitint.h (build_bitint_stmt_ssa_conflicts): Add
            CLEAR argument.
            * gimple-lower-bitint.cc (build_bitint_stmt_ssa_conflicts): Add
            CLEAR argument.  Call clear on gimple_assign_copy_p rhs1 if lhs
            is large/huge bitint unless lhs is not in names.
            * tree-ssa-coalesce.cc (build_ssa_conflict_graph): Adjust
            build_bitint_stmt_ssa_conflicts caller.  Move gimple_assign_copy_p
            handling to after the build_bitint_stmt_ssa_conflicts call.
    
    (cherry picked from commit 3f9dfb94eab1ab1bbf9a2b5e20d1f61e36516063)

Diff:
---
 gcc/gimple-lower-bitint.cc | 22 +++++++++++++++++++++-
 gcc/gimple-lower-bitint.h  |  1 +
 gcc/tree-ssa-coalesce.cc   | 22 ++++++++++++----------
 3 files changed, 34 insertions(+), 11 deletions(-)

diff --git a/gcc/gimple-lower-bitint.cc b/gcc/gimple-lower-bitint.cc
index 899a9b5c1eaa..97ba94107b90 100644
--- a/gcc/gimple-lower-bitint.cc
+++ b/gcc/gimple-lower-bitint.cc
@@ -5915,7 +5915,8 @@ build_bitint_stmt_ssa_conflicts (gimple *stmt, live_track 
*live,
                                 ssa_conflicts *graph, bitmap names,
                                 void (*def) (live_track *, tree,
                                              ssa_conflicts *),
-                                void (*use) (live_track *, tree))
+                                void (*use) (live_track *, tree),
+                                void (*clear) (live_track *, tree))
 {
   bool muldiv_p = false;
   tree lhs = NULL_TREE;
@@ -5932,6 +5933,25 @@ build_bitint_stmt_ssa_conflicts (gimple *stmt, 
live_track *live,
            {
              if (!bitmap_bit_p (names, SSA_NAME_VERSION (lhs)))
                return;
+
+             /* A copy between 2 partitions does not introduce an interference
+                by itself.  If they did, you would never be able to coalesce
+                two things which are copied.  If the two variables really do
+                conflict, they will conflict elsewhere in the program.
+
+                This is handled by simply removing the SRC of the copy from
+                the live list, and processing the stmt normally.
+
+                Don't do this if lhs is not in names though, in such cases
+                it is actually used at some point later in the basic
+                block.  */
+             if (gimple_assign_copy_p (stmt))
+               {
+                 tree rhs1 = gimple_assign_rhs1 (stmt);
+                 if (TREE_CODE (rhs1) == SSA_NAME)
+                   clear (live, rhs1);
+               }
+
              switch (gimple_assign_rhs_code (stmt))
                {
                case MULT_EXPR:
diff --git a/gcc/gimple-lower-bitint.h b/gcc/gimple-lower-bitint.h
index eff27b30a5eb..f5117ce25276 100644
--- a/gcc/gimple-lower-bitint.h
+++ b/gcc/gimple-lower-bitint.h
@@ -26,6 +26,7 @@ extern void build_bitint_stmt_ssa_conflicts (gimple *, 
live_track *,
                                             ssa_conflicts *, bitmap,
                                             void (*) (live_track *, tree,
                                                       ssa_conflicts *),
+                                            void (*) (live_track *, tree),
                                             void (*) (live_track *, tree));
 
 #endif /* GCC_GIMPLE_LOWER_BITINT_H */
diff --git a/gcc/tree-ssa-coalesce.cc b/gcc/tree-ssa-coalesce.cc
index 8d8727de32f1..7c652361485f 100644
--- a/gcc/tree-ssa-coalesce.cc
+++ b/gcc/tree-ssa-coalesce.cc
@@ -896,6 +896,18 @@ build_ssa_conflict_graph (tree_live_info_p liveinfo)
          tree var;
          gimple *stmt = gsi_stmt (gsi);
 
+         if (is_gimple_debug (stmt))
+           continue;
+
+         if (map->bitint)
+           {
+             build_bitint_stmt_ssa_conflicts (stmt, live, graph, map->bitint,
+                                              live_track_process_def,
+                                              live_track_process_use,
+                                              live_track_clear_var);
+             continue;
+           }
+
          /* A copy between 2 partitions does not introduce an interference
             by itself.  If they did, you would never be able to coalesce
             two things which are copied.  If the two variables really do
@@ -912,16 +924,6 @@ build_ssa_conflict_graph (tree_live_info_p liveinfo)
                   && TREE_CODE (rhs1) == SSA_NAME)
                live_track_clear_var (live, rhs1);
            }
-         else if (is_gimple_debug (stmt))
-           continue;
-
-         if (map->bitint)
-           {
-             build_bitint_stmt_ssa_conflicts (stmt, live, graph, map->bitint,
-                                              live_track_process_def,
-                                              live_track_process_use);
-             continue;
-           }
 
          /* For stmts with more than one SSA_NAME definition pretend all the
             SSA_NAME outputs but the first one are live at this point, so

Reply via email to