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); +}