https://gcc.gnu.org/g:95cc24b98066e7b021ae8562defc384ddeb26b57

commit r16-9874-g95cc24b98066e7b021ae8562defc384ddeb26b57
Author: Jakub Jelinek <[email protected]>
Date:   Tue Oct 20 12:05:03 2026 +0200

    bitintlower: Fix up the single use SSA_NAME optimization [PR127905]
    
    The _BitInt lowering contains an optimization, if a SSA_NAME has a single
    use and if its partition is reused for other SSA_NAMEs, we try to emit
    a CLOBBER on the underlying variable of the partition after the use if
    possible, so that GIMPLE opts know it is dead and can optimize better.
    Already in the past I had to fix this up once, if there are SSA_NAME
    copies, this can misbehave in some cases due to the coalescing algorithm
    special casing those.
    
    The following testcase shows a different problem.  There is an SSA_NAME
    with a single use, but the definition of the SSA_NAME is before a loop
    and the use within a loop.  In this case emitting a CLOBBER inside of
    the loop is wrong, the first loop's iteration will use correct value
    of the underlying var, but second and following iteration will be after
    a CLOBBER, so e.g. if it is unrolled, the uses in those iterations will
    be handled as if they read uninitialized memory.
    
    The following patch is my attempt to detect the case where the use
    stmt can be invoked more often than the definition.
    If def and use are in the same bb, it is IMHO fine, otherwise I compare
    whether the def and use are in the same loop (that is IMHO also ok as
    long as no irreducible loop is involved).
    
    I've also collected statistics, and this patch in the testsuite emits just
    0.137% fewer clobbers than before, so I'm not worried it will pessimize 
stuff
    too much.
    
    2026-10-20  Jakub Jelinek  <[email protected]>
    
            PR tree-optimization/127905
            * gimple-lower-bitint.cc (gimple_lower_bitint): Don't add to
            m_single_use_names versions of SSA_NAMEs where their single use
            is within a different loop from the definition (or if use is
            in irreducible loop, in a different bb than def).
    
            * gcc.dg/torture/bitint-114.c: New test.
    
    Reviewed-by: Richard Biener <[email protected]>
    (cherry picked from commit a4844311b2f48436998f02c8a1c224086426a0cc)

Diff:
---
 gcc/gimple-lower-bitint.cc                | 53 ++++++++++++++++++++++++++++---
 gcc/testsuite/gcc.dg/torture/bitint-114.c | 35 ++++++++++++++++++++
 2 files changed, 83 insertions(+), 5 deletions(-)

diff --git a/gcc/gimple-lower-bitint.cc b/gcc/gimple-lower-bitint.cc
index dc7f044c9ac8..5f16d8f9a7c9 100644
--- a/gcc/gimple-lower-bitint.cc
+++ b/gcc/gimple-lower-bitint.cc
@@ -7038,6 +7038,7 @@ gimple_lower_bitint (void)
   small_max_prec = mid_min_prec = large_min_prec = huge_min_prec = 0;
   limb_prec = abi_limb_prec = 0;
   bitint_big_endian = false;
+  bool loop_init_done = false;
 
   unsigned int i;
   for (i = 0; i < num_ssa_names; ++i)
@@ -7742,7 +7743,7 @@ gimple_lower_bitint (void)
          bitmap_set_bit (large_huge.m_names, SSA_NAME_VERSION (s));
          if (has_single_use (s))
            {
-             tree s2 = s;
+             tree s2 = s, s3 = s;
              /* The coalescing hook special cases SSA_NAME copies.
                 Make sure not to mark in m_single_use_names single
                 use SSA_NAMEs copied from non-single use SSA_NAMEs.  */
@@ -7756,13 +7757,52 @@ gimple_lower_bitint (void)
                      s2 = NULL_TREE;
                      break;
                    }
+                 s3 = s2;
                }
              if (s2)
                {
-                 if (!large_huge.m_single_use_names)
-                   large_huge.m_single_use_names = BITMAP_ALLOC (NULL);
-                 bitmap_set_bit (large_huge.m_single_use_names,
-                                 SSA_NAME_VERSION (s));
+                 /* Only set m_single_use_names for SSA_NAMEs where
+                    the definition and use are within the same loop,
+                    otherwise if the use could be executed more times
+                    than the def stmt, we can't emit clobbers.
+                    Or if irreducible loops are involved, only handle
+                    same bb definitions.  */
+                 gimple *def = SSA_NAME_DEF_STMT (s3), *use;
+                 use_operand_p use_p;
+                 single_imm_use (s, &use_p, &use);
+                 basic_block def_bb, use_bb;
+                 if (SSA_NAME_IS_DEFAULT_DEF (s3))
+                   def_bb = NULL;
+                 else
+                   def_bb = gimple_bb (def);
+                 use_bb = gimple_bb (use);
+                 if (def_bb != use_bb)
+                   {
+                     if (!loop_init_done)
+                       {
+                         unsigned flags
+                           = (AVOID_CFG_MODIFICATIONS
+                              | LOOPS_HAVE_MARKED_IRREDUCIBLE_REGIONS);
+                         loop_optimizer_init (flags);
+                         loop_init_done = true;
+                       }
+                     if ((use_bb->flags & BB_IRREDUCIBLE_LOOP) == 0)
+                       {
+                         class loop *def_loop
+                           = def_bb ? def_bb->loop_father
+                                    : get_loop (cfun, 0);
+                         class loop *use_loop = use_bb->loop_father;
+                         if (def_loop == use_loop)
+                           def_bb = use_bb;
+                       }
+                   }
+                 if (def_bb == use_bb)
+                   {
+                     if (!large_huge.m_single_use_names)
+                       large_huge.m_single_use_names = BITMAP_ALLOC (NULL);
+                     bitmap_set_bit (large_huge.m_single_use_names,
+                                     SSA_NAME_VERSION (s));
+                   }
                }
            }
          if (SSA_NAME_VAR (s)
@@ -8428,6 +8468,9 @@ gimple_lower_bitint (void)
        }
     }
 
+  if (loop_init_done)
+    loop_optimizer_finalize ();
+
   return ret;
 }
 
diff --git a/gcc/testsuite/gcc.dg/torture/bitint-114.c 
b/gcc/testsuite/gcc.dg/torture/bitint-114.c
new file mode 100644
index 000000000000..700185a5d638
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/bitint-114.c
@@ -0,0 +1,35 @@
+/* PR tree-optimization/127905 */
+/* { dg-do run { target bitint } } */
+
+#if __BITINT_MAXWIDTH__ >= 135
+typedef unsigned _BitInt(135) B;
+
+[[gnu::noipa]] B
+foo (B b, int c, unsigned n)
+{
+  B x = c ? b : 7;
+  B y = b;
+  for (unsigned i = 0; i < n; i++)
+    y = x + i;
+  return y;
+}
+
+[[gnu::noipa]] B
+bar (B b, B a, int c, unsigned n)
+{
+  B x = c ? b : 7;
+  B y = b;
+  for (unsigned i = 0; i < n; i++)
+    y = c ? x + 7 : a;
+  return y;
+}
+#endif
+
+int
+main ()
+{
+#if __BITINT_MAXWIDTH__ >= 135
+  if (foo (5, 1, 3) != 7 || bar (5, 9, 1, 3) != 12)
+    __builtin_abort ();
+#endif
+}

Reply via email to