diff options
author | Jakub Jelinek <jakub@redhat.com> | 2024-03-15 09:16:43 +0100 |
---|---|---|
committer | Jakub Jelinek <jakub@redhat.com> | 2024-03-15 09:16:43 +0100 |
commit | 90b9872311ccb24685ba33b6ba6f374d50f03874 (patch) | |
tree | c8bf1b841af18581d280ea49419b3d791dea82c0 /gcc | |
parent | 3fd46d859cda1074125449a4cc680ce59fcebc38 (diff) | |
download | gcc-90b9872311ccb24685ba33b6ba6f374d50f03874.zip gcc-90b9872311ccb24685ba33b6ba6f374d50f03874.tar.gz gcc-90b9872311ccb24685ba33b6ba6f374d50f03874.tar.bz2 |
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 <jakub@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.
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/gimple-lower-bitint.cc | 71 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/bitint-100.c | 108 |
2 files changed, 178 insertions, 1 deletions
diff --git a/gcc/gimple-lower-bitint.cc b/gcc/gimple-lower-bitint.cc index b58220f..42c39d8 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 0000000..e859bfb --- /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); +} |