https://gcc.gnu.org/g:90b9872311ccb24685ba33b6ba6f374d50f03874

commit r14-9490-g90b9872311ccb24685ba33b6ba6f374d50f03874
Author: Jakub Jelinek <ja...@redhat.com>
Date:   Fri Mar 15 09:16:43 2024 +0100

    bitint: Fix up adjustment of large/huge _BitInt arguments of returns_twice 
calls [PR113466]
    
    This patch (on top of the just posted gsi_safe_insert* fixes patch)
    fixes the instrumentation of large/huge _BitInt SSA_NAME arguments of
    returns_twice calls.
    
    In this case it isn't just a matter of using gsi_safe_insert_before instead
    of gsi_insert_before, we need to do more.
    
    One thing is that unlike the asan/ubsan instrumentation which does just some
    checking, here we want the statement before the call to load into a SSA_NAME
    which is passed to the call.  With another edge we need to add a PHI,
    with one PHI argument the loaded SSA_NAME, another argument an uninitialized
    warning free SSA_NAME and a result and arrange for all 3 SSA_NAMEs to be
    preserved (i.e. stay as is, be no longer lowered afterwards).
    
    Unfortunately, edge_before_returns_twice_call can create new SSA_NAMEs using
    copy_ssa_name and while we can have a reasonable partition for them (same
    partition as PHI result correspoding to the PHI argument newly added), 
adding
    SSA_NAMEs into a partition after the partitions are finalized is too ugly.
    So, this patch takes a different approach suggested by Richi, just emit
    the argument loads before the returns_twice call normally (i.e. temporarily
    create invalid IL) and just remember that we did that, and when the bitint
    lowering is otherwise done fix this up, gsi_remove those statements,
    gsi_safe_insert_before and and create the needed new PHIs.
    
    2024-03-15  Jakub Jelinek  <ja...@redhat.com>
    
            PR tree-optimization/113466
            * gimple-lower-bitint.cc (bitint_large_huge): Add 
m_returns_twice_calls
            member.
            (bitint_large_huge::bitint_large_huge): Initialize it.
            (bitint_large_huge::~bitint_large_huge): Release it.
            (bitint_large_huge::lower_call): Remember ECF_RETURNS_TWICE call 
stmts
            before which at least one statement has been inserted.
            (gimple_lower_bitint): Move argument loads before ECF_RETURNS_TWICE
            calls to a different block and add corresponding PHIs.
    
            * gcc.dg/bitint-100.c: New test.

Diff:
---
 gcc/gimple-lower-bitint.cc        |  71 ++++++++++++++++++++++++-
 gcc/testsuite/gcc.dg/bitint-100.c | 108 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 178 insertions(+), 1 deletion(-)

diff --git a/gcc/gimple-lower-bitint.cc b/gcc/gimple-lower-bitint.cc
index b58220f564c..42c39d8a47a 100644
--- a/gcc/gimple-lower-bitint.cc
+++ b/gcc/gimple-lower-bitint.cc
@@ -419,7 +419,8 @@ struct bitint_large_huge
   bitint_large_huge ()
     : m_names (NULL), m_loads (NULL), m_preserved (NULL),
       m_single_use_names (NULL), m_map (NULL), m_vars (NULL),
-      m_limb_type (NULL_TREE), m_data (vNULL) {}
+      m_limb_type (NULL_TREE), m_data (vNULL),
+      m_returns_twice_calls (vNULL) {}
 
   ~bitint_large_huge ();
 
@@ -553,6 +554,7 @@ struct bitint_large_huge
   unsigned m_bitfld_load;
   vec<tree> m_data;
   unsigned int m_data_cnt;
+  vec<gimple *> m_returns_twice_calls;
 };
 
 bitint_large_huge::~bitint_large_huge ()
@@ -565,6 +567,7 @@ bitint_large_huge::~bitint_large_huge ()
     delete_var_map (m_map);
   XDELETEVEC (m_vars);
   m_data.release ();
+  m_returns_twice_calls.release ();
 }
 
 /* Insert gimple statement G before current location
@@ -5248,6 +5251,7 @@ bitint_large_huge::lower_call (tree obj, gimple *stmt)
       default:
        break;
       }
+  bool returns_twice = (gimple_call_flags (stmt) & ECF_RETURNS_TWICE) != 0;
   for (unsigned int i = 0; i < nargs; ++i)
     {
       tree arg = gimple_call_arg (stmt, i);
@@ -5271,6 +5275,11 @@ bitint_large_huge::lower_call (tree obj, gimple *stmt)
          arg = make_ssa_name (TREE_TYPE (arg));
          gimple *g = gimple_build_assign (arg, v);
          gsi_insert_before (&gsi, g, GSI_SAME_STMT);
+         if (returns_twice)
+           {
+             m_returns_twice_calls.safe_push (stmt);
+             returns_twice = false;
+           }
        }
       gimple_call_set_arg (stmt, i, arg);
       if (m_preserved == NULL)
@@ -7091,6 +7100,66 @@ gimple_lower_bitint (void)
   if (edge_insertions)
     gsi_commit_edge_inserts ();
 
+  /* Fix up arguments of ECF_RETURNS_TWICE calls.  Those were temporarily
+     inserted before the call, but that is invalid IL, so move them to the
+     right place and add corresponding PHIs.  */
+  if (!large_huge.m_returns_twice_calls.is_empty ())
+    {
+      auto_vec<gimple *, 16> arg_stmts;
+      while (!large_huge.m_returns_twice_calls.is_empty ())
+       {
+         gimple *stmt = large_huge.m_returns_twice_calls.pop ();
+         gimple_stmt_iterator gsi = gsi_after_labels (gimple_bb (stmt));
+         while (gsi_stmt (gsi) != stmt)
+           {
+             arg_stmts.safe_push (gsi_stmt (gsi));
+             gsi_remove (&gsi, false);
+           }
+         gimple *g;
+         basic_block bb = NULL;
+         edge e = NULL, ead = NULL;
+         FOR_EACH_VEC_ELT (arg_stmts, i, g)
+           {
+             gsi_safe_insert_before (&gsi, g);
+             if (i == 0)
+               {
+                 bb = gimple_bb (stmt);
+                 gcc_checking_assert (EDGE_COUNT (bb->preds) == 2);
+                 e = EDGE_PRED (bb, 0);
+                 ead = EDGE_PRED (bb, 1);
+                 if ((ead->flags & EDGE_ABNORMAL) == 0)
+                   std::swap (e, ead);
+                 gcc_checking_assert ((e->flags & EDGE_ABNORMAL) == 0
+                                      && (ead->flags & EDGE_ABNORMAL));
+               }
+             tree lhs = gimple_assign_lhs (g);
+             tree arg = lhs;
+             gphi *phi = create_phi_node (copy_ssa_name (arg), bb);
+             add_phi_arg (phi, arg, e, UNKNOWN_LOCATION);
+             tree var = create_tmp_reg (TREE_TYPE (arg));
+             suppress_warning (var, OPT_Wuninitialized);
+             arg = get_or_create_ssa_default_def (cfun, var);
+             SSA_NAME_OCCURS_IN_ABNORMAL_PHI (arg) = 1;
+             add_phi_arg (phi, arg, ead, UNKNOWN_LOCATION);
+             arg = gimple_phi_result (phi);
+             SSA_NAME_OCCURS_IN_ABNORMAL_PHI (arg) = 1;
+             imm_use_iterator iter;
+             gimple *use_stmt;
+             FOR_EACH_IMM_USE_STMT (use_stmt, iter, lhs)
+               {
+                 if (use_stmt == phi)
+                   continue;
+                 gcc_checking_assert (use_stmt == stmt);
+                 use_operand_p use_p;
+                 FOR_EACH_IMM_USE_ON_STMT (use_p, iter)
+                   SET_USE (use_p, arg);
+               }
+           }
+         update_stmt (stmt);
+         arg_stmts.truncate (0);
+       }
+    }
+
   return ret;
 }
 
diff --git a/gcc/testsuite/gcc.dg/bitint-100.c 
b/gcc/testsuite/gcc.dg/bitint-100.c
new file mode 100644
index 00000000000..e859bfba6b8
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/bitint-100.c
@@ -0,0 +1,108 @@
+/* PR tree-optimization/113466 */
+/* { dg-do compile { target bitint575 } } */
+/* { dg-options "-O2" } */
+
+int foo (int);
+
+__attribute__((returns_twice, noipa)) _BitInt(325)
+bar (_BitInt(575) x)
+{
+  (void) x;
+  return 0wb;
+}
+
+__attribute__((returns_twice, noipa)) _BitInt(325)
+garply (_BitInt(575) x, _BitInt(575) y, _BitInt(575) z, int u, int v, 
_BitInt(575) w)
+{
+  (void) x;
+  (void) y;
+  (void) z;
+  (void) u;
+  (void) v;
+  (void) w;
+  return 0wb;
+}
+
+_BitInt(325)
+baz (_BitInt(575) y)
+{
+  foo (1);
+  return bar (y);
+}
+
+_BitInt(325)
+qux (int x, _BitInt(575) y)
+{
+  if (x == 25)
+    x = foo (2);
+  else if (x == 42)
+    x = foo (foo (3));
+  return bar (y);
+}
+
+void
+corge (int x, _BitInt(575) y, _BitInt(325) *z)
+{
+  void *q[] = { &&l1, &&l2, &&l3, &&l3 };
+  if (x == 25)
+    {
+    l1:
+      x = foo (2);
+    }
+  else if (x == 42)
+    {
+    l2:
+      x = foo (foo (3));
+    }
+l3:
+  *z = bar (y);
+  if (x < 4)
+    goto *q[x & 3];
+}
+
+_BitInt(325)
+freddy (int x, _BitInt(575) y)
+{
+  bar (y);
+  ++y;
+  if (x == 25)
+    x = foo (2);
+  else if (x == 42)
+    x = foo (foo (3));
+  return bar (y);
+}
+
+_BitInt(325)
+quux (_BitInt(575) x, _BitInt(575) y, _BitInt(575) z)
+{
+  _BitInt(575) w = x + y;
+  foo (1);
+  return garply (x, y, z, 42, 42, w);
+}
+
+_BitInt(325)
+grault (int x, _BitInt(575) y, _BitInt(575) z)
+{
+  _BitInt(575) v = x + y;
+  _BitInt(575) w = x - y;
+  if (x == 25)
+    x = foo (2);
+  else if (x == 42)
+    x = foo (foo (3));
+  return garply (y, z, v, 0, 0, w);
+}
+
+_BitInt(325)
+plugh (int x, _BitInt(575) y, _BitInt(575) z, _BitInt(575) v, _BitInt(575) w)
+{
+  garply (y, z, v, 1, 2, w);
+  ++y;
+  z += 2wb;
+  v <<= 3;
+  w *= 3wb;
+  if (x == 25)
+    x = foo (2);
+  else if (x == 42)
+    x = foo (foo (3));
+  return garply (y, z, v, 1, 2, w);
+}

Reply via email to