Clean up loop-closed PHIs after loop finalize

This patch propagates loop-closed PHIs them out at
loop_optimizer_finalize.  For some cases, to clean up loop-closed PHIs
would save efforts of optimization passes after loopdone.

Thanks,
Jiufu Guo.

gcc/ChangeLog:
2020-10-18  Jiufu Guo   <guojiufu@linux.ibm.com>

	* cfgloop.h (loop_optimizer_finalize): Add flag argument.
	* loop-init.c (loop_optimizer_finalize): Call clean_up_loop_closed_phi.
	* tree-cfgcleanup.h (clean_up_loop_closed_phi): New declare.
	* tree-ssa-loop.c (tree_ssa_loop_done): Call loop_optimizer_finalize
	with flag argument.
	* tree-ssa-propagate.c (clean_up_loop_closed_phi): New function.

gcc/testsuite/ChangeLog:
2020-10-18  Jiufu Guo   <guojiufu@linux.ibm.com>

	* gcc.dg/tree-ssa/loopclosedphi.c: New test.
This commit is contained in:
guojiufu 2020-11-17 19:49:03 +08:00
parent 397654d66a
commit d87ee7f1c9
6 changed files with 104 additions and 3 deletions

View File

@ -824,7 +824,7 @@ extern void init_set_costs (void);
/* Loop optimizer initialization. */
extern void loop_optimizer_init (unsigned);
extern void loop_optimizer_finalize (function *);
extern void loop_optimizer_finalize (function *, bool = false);
inline void
loop_optimizer_finalize ()
{

View File

@ -33,6 +33,7 @@ along with GCC; see the file COPYING3. If not see
#include "tree-ssa-loop-niter.h"
#include "loop-unroll.h"
#include "tree-scalar-evolution.h"
#include "tree-cfgcleanup.h"
/* Apply FLAGS to the loop state. */
@ -133,13 +134,19 @@ loop_optimizer_init (unsigned flags)
/* Finalize loop structures. */
void
loop_optimizer_finalize (struct function *fn)
loop_optimizer_finalize (struct function *fn, bool clean_loop_closed_phi)
{
class loop *loop;
basic_block bb;
timevar_push (TV_LOOP_FINI);
if (clean_loop_closed_phi && loops_state_satisfies_p (fn, LOOP_CLOSED_SSA))
{
clean_up_loop_closed_phi (fn);
loops_state_clear (fn, LOOP_CLOSED_SSA);
}
if (loops_state_satisfies_p (fn, LOOPS_HAVE_RECORDED_EXITS))
release_recorded_exits (fn);

View File

@ -0,0 +1,21 @@
/* { dg-do compile } */
/* { dg-options "-O3 -fno-tree-ch -w -fdump-tree-loopdone-details" } */
void
t6 (int qz, int wh)
{
int jl = wh;
while (1.0 * qz / wh < 1)
{
qz = wh * (wh + 2);
while (wh < 1)
jl = 0;
}
while (qz < 1)
qz = jl * wh;
}
/* { dg-final { scan-tree-dump-times "Replacing" 2 "loopdone"} } */

View File

@ -26,5 +26,6 @@ extern bool cleanup_tree_cfg (unsigned = 0);
extern bool fixup_noreturn_call (gimple *stmt);
extern bool delete_unreachable_blocks_update_callgraph (cgraph_node *dst_node,
bool update_clones);
extern unsigned clean_up_loop_closed_phi (function *);
#endif /* GCC_TREE_CFGCLEANUP_H */

View File

@ -529,7 +529,7 @@ tree_ssa_loop_done (void)
{
free_numbers_of_iterations_estimates (cfun);
scev_finalize ();
loop_optimizer_finalize ();
loop_optimizer_finalize (cfun, true);
return 0;
}

View File

@ -1549,3 +1549,75 @@ propagate_tree_value_into_stmt (gimple_stmt_iterator *gsi, tree val)
else
gcc_unreachable ();
}
/* Check exits of each loop in FUN, walk over loop closed PHIs in
each exit basic block and propagate degenerate PHIs. */
unsigned
clean_up_loop_closed_phi (function *fun)
{
unsigned i;
edge e;
gphi *phi;
tree rhs;
tree lhs;
gphi_iterator gsi;
struct loop *loop;
/* Avoid possibly quadratic work when scanning for loop exits across
all loops of a nest. */
if (!loops_state_satisfies_p (LOOPS_HAVE_RECORDED_EXITS))
return 0;
/* Walk over loop in function. */
FOR_EACH_LOOP_FN (fun, loop, 0)
{
/* Check each exit edege of loop. */
auto_vec<edge> exits = get_loop_exit_edges (loop);
FOR_EACH_VEC_ELT (exits, i, e)
if (single_pred_p (e->dest))
/* Walk over loop-closed PHIs. */
for (gsi = gsi_start_phis (e->dest); !gsi_end_p (gsi);)
{
phi = gsi.phi ();
rhs = gimple_phi_arg_def (phi, 0);
lhs = gimple_phi_result (phi);
if (rhs && may_propagate_copy (lhs, rhs))
{
/* Dump details. */
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, " Replacing '");
print_generic_expr (dump_file, lhs, dump_flags);
fprintf (dump_file, "' with '");
print_generic_expr (dump_file, rhs, dump_flags);
fprintf (dump_file, "'\n");
}
use_operand_p use_p;
imm_use_iterator iter;
gimple *use_stmt;
FOR_EACH_IMM_USE_STMT (use_stmt, iter, lhs)
{
FOR_EACH_IMM_USE_ON_STMT (use_p, iter)
replace_exp (use_p, rhs);
update_stmt (use_stmt);
/* Update the invariant flag for ADDR_EXPR if replacing
a variable index with a constant. */
if (gimple_assign_single_p (use_stmt)
&& TREE_CODE (gimple_assign_rhs1 (use_stmt))
== ADDR_EXPR)
recompute_tree_invariant_for_addr_expr (
gimple_assign_rhs1 (use_stmt));
}
remove_phi_node (&gsi, true);
}
else
gsi_next (&gsi);
}
}
return 0;
}