From a564da506f52be66ade298b562417641e87b549f Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Wed, 5 May 2021 16:15:12 +0200 Subject: [PATCH] tree-optimization/100434 - DSE aggregate call LHS This makes DSE consider aggregate LHS of calls as dead, for pure or const calls the whole stmt and for others by removing the LHS. 2021-05-05 Richard Biener PR tree-optimization/100434 * tree-ssa-dse.c (initialize_ao_ref_for_dse): Handle call LHS. (dse_optimize_stmt): Handle call LHS by dropping the LHS or the whole call if it doesn't have other side-effects. (pass_dse::execute): Adjust. * gcc.dg/tree-ssa/ssa-dse-43.c: New testcase. --- gcc/testsuite/gcc.dg/tree-ssa/ssa-dse-43.c | 22 ++++++ gcc/tree-ssa-dse.c | 107 ++++++++++++++++++----------- 2 files changed, 87 insertions(+), 42 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/ssa-dse-43.c diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-dse-43.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dse-43.c new file mode 100644 index 0000000..f8785e9 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dse-43.c @@ -0,0 +1,22 @@ +/* { dg-do compile } */ +/* { dg-options "-O -fdump-tree-dse1-details" } */ + +struct X { int x; }; +struct X x; + +extern struct X foo (void); +void bar() +{ + x = foo(); + x = (struct X){}; +} + +extern struct X __attribute__((const)) foo2 (int); +void bar2() +{ + x = foo2 (1); + x = foo2 (2); +} + +/* { dg-final { scan-tree-dump-times "Deleted dead store in call LHS: x = foo " 1 "dse1" } } */ +/* { dg-final { scan-tree-dump-times "Deleted dead store: x = foo2 " 1 "dse1" } } */ diff --git a/gcc/tree-ssa-dse.c b/gcc/tree-ssa-dse.c index 63c876a..c3939a6 100644 --- a/gcc/tree-ssa-dse.c +++ b/gcc/tree-ssa-dse.c @@ -140,10 +140,13 @@ initialize_ao_ref_for_dse (gimple *stmt, ao_ref *write) break; } } - else if (is_gimple_assign (stmt)) + else if (tree lhs = gimple_get_lhs (stmt)) { - ao_ref_init (write, gimple_assign_lhs (stmt)); - return true; + if (TREE_CODE (lhs) != SSA_NAME) + { + ao_ref_init (write, lhs); + return true; + } } return false; } @@ -1035,7 +1038,7 @@ delete_dead_or_redundant_assignment (gimple_stmt_iterator *gsi, const char *type post dominates the first store, then the first store is dead. */ static void -dse_optimize_stmt (gimple_stmt_iterator *gsi, sbitmap live_bytes) +dse_optimize_stmt (function *fun, gimple_stmt_iterator *gsi, sbitmap live_bytes) { gimple *stmt = gsi_stmt (*gsi); @@ -1113,49 +1116,69 @@ dse_optimize_stmt (gimple_stmt_iterator *gsi, sbitmap live_bytes) } } - if (is_gimple_assign (stmt)) + bool by_clobber_p = false; + + /* Check if this statement stores zero to a memory location, + and if there is a subsequent store of zero to the same + memory location. If so, remove the subsequent store. */ + if (gimple_assign_single_p (stmt) + && initializer_zerop (gimple_assign_rhs1 (stmt))) + dse_optimize_redundant_stores (stmt); + + /* Self-assignments are zombies. */ + if (is_gimple_assign (stmt) + && operand_equal_p (gimple_assign_rhs1 (stmt), + gimple_assign_lhs (stmt), 0)) + ; + else { - bool by_clobber_p = false; - - /* Check if this statement stores zero to a memory location, - and if there is a subsequent store of zero to the same - memory location. If so, remove the subsequent store. */ - if (gimple_assign_single_p (stmt) - && initializer_zerop (gimple_assign_rhs1 (stmt))) - dse_optimize_redundant_stores (stmt); - - /* Self-assignments are zombies. */ - if (operand_equal_p (gimple_assign_rhs1 (stmt), - gimple_assign_lhs (stmt), 0)) - ; - else - { - bool byte_tracking_enabled - = setup_live_bytes_from_ref (&ref, live_bytes); - enum dse_store_status store_status; - store_status = dse_classify_store (&ref, stmt, - byte_tracking_enabled, - live_bytes, &by_clobber_p); - if (store_status == DSE_STORE_LIVE) - return; + bool byte_tracking_enabled + = setup_live_bytes_from_ref (&ref, live_bytes); + enum dse_store_status store_status; + store_status = dse_classify_store (&ref, stmt, + byte_tracking_enabled, + live_bytes, &by_clobber_p); + if (store_status == DSE_STORE_LIVE) + return; - if (store_status == DSE_STORE_MAYBE_PARTIAL_DEAD) - { - maybe_trim_partially_dead_store (&ref, live_bytes, stmt); - return; - } + if (store_status == DSE_STORE_MAYBE_PARTIAL_DEAD) + { + maybe_trim_partially_dead_store (&ref, live_bytes, stmt); + return; } + } - /* Now we know that use_stmt kills the LHS of stmt. */ + /* Now we know that use_stmt kills the LHS of stmt. */ - /* But only remove *this_2(D) ={v} {CLOBBER} if killed by - another clobber stmt. */ - if (gimple_clobber_p (stmt) - && !by_clobber_p) - return; + /* But only remove *this_2(D) ={v} {CLOBBER} if killed by + another clobber stmt. */ + if (gimple_clobber_p (stmt) + && !by_clobber_p) + return; - delete_dead_or_redundant_assignment (gsi, "dead", need_eh_cleanup); + if (is_gimple_call (stmt) + && (gimple_has_side_effects (stmt) + || (stmt_could_throw_p (fun, stmt) + && !fun->can_delete_dead_exceptions))) + { + /* Make sure we do not remove a return slot we cannot reconstruct + later. */ + if (gimple_call_return_slot_opt_p (as_a (stmt)) + && (TREE_ADDRESSABLE (TREE_TYPE (gimple_call_fntype (stmt))) + || !poly_int_tree_p + (TYPE_SIZE (TREE_TYPE (gimple_call_fntype (stmt)))))) + return; + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, " Deleted dead store in call LHS: "); + print_gimple_stmt (dump_file, stmt, 0, dump_flags); + fprintf (dump_file, "\n"); + } + gimple_call_set_lhs (stmt, NULL_TREE); + update_stmt (stmt); } + else + delete_dead_or_redundant_assignment (gsi, "dead", need_eh_cleanup); } namespace { @@ -1194,7 +1217,7 @@ pass_dse::execute (function *fun) need_eh_cleanup = BITMAP_ALLOC (NULL); auto_sbitmap live_bytes (param_dse_max_object_size); - renumber_gimple_stmt_uids (cfun); + renumber_gimple_stmt_uids (fun); calculate_dominance_info (CDI_DOMINATORS); @@ -1211,7 +1234,7 @@ pass_dse::execute (function *fun) gimple *stmt = gsi_stmt (gsi); if (gimple_vdef (stmt)) - dse_optimize_stmt (&gsi, live_bytes); + dse_optimize_stmt (fun, &gsi, live_bytes); else if (def_operand_p def_p = single_ssa_def_operand (stmt, SSA_OP_DEF)) { -- 2.7.4