/* Back-propagation of usage information to definitions.
- Copyright (C) 2015 Free Software Foundation, Inc.
+ Copyright (C) 2015-2021 Free Software Foundation, Inc.
This file is part of GCC.
namespace {
/* Information about a group of uses of an SSA name. */
-struct usage_info
+class usage_info
{
+public:
usage_info () : flag_word (0) {}
usage_info &operator &= (const usage_info &);
usage_info operator & (const usage_info &) const;
dump_usage_prefix (FILE *file, tree var)
{
fprintf (file, " ");
- print_generic_expr (file, var, 0);
+ print_generic_expr (file, var);
fprintf (file, ": ");
}
/* A bitmap of blocks that we have finished processing in the initial
post-order walk. */
- sbitmap m_visited_blocks;
+ auto_sbitmap m_visited_blocks;
+
+ /* A bitmap of phis that we have finished processing in the initial
+ post-order walk, excluding those from blocks mentioned in
+ M_VISITED_BLOCKS. */
+ auto_bitmap m_visited_phis;
/* A worklist of SSA names whose definitions need to be reconsidered. */
auto_vec <tree, 64> m_worklist;
backprop::backprop (function *fn)
: m_fn (fn),
m_info_pool ("usage_info"),
- m_visited_blocks (sbitmap_alloc (last_basic_block_for_fn (m_fn))),
+ m_visited_blocks (last_basic_block_for_fn (m_fn)),
m_worklist_names (BITMAP_ALLOC (NULL))
{
bitmap_clear (m_visited_blocks);
backprop::~backprop ()
{
BITMAP_FREE (m_worklist_names);
- sbitmap_free (m_visited_blocks);
m_info_pool.release ();
}
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "[WORKLIST] Pushing ");
- print_generic_expr (dump_file, var, 0);
+ print_generic_expr (dump_file, var);
fprintf (dump_file, "\n");
}
}
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "[WORKLIST] Popping ");
- print_generic_expr (dump_file, var, 0);
+ print_generic_expr (dump_file, var);
fprintf (dump_file, "\n");
}
return var;
break;
CASE_CFN_COPYSIGN:
+ CASE_CFN_COPYSIGN_FN:
/* The sign of the first input is ignored. */
if (rhs != gimple_call_arg (call, 1))
info->flags.ignore_sign = true;
}
CASE_CFN_FMA:
+ CASE_CFN_FMA_FN:
+ case CFN_FMS:
+ case CFN_FNMA:
+ case CFN_FNMS:
/* In X * X + Y, where Y is distinct from X, the sign of X doesn't
matter. */
if (gimple_call_arg (call, 0) == rhs
switch (gimple_assign_rhs_code (assign))
{
case ABS_EXPR:
+ case ABSU_EXPR:
/* The sign of the input doesn't matter. */
info->flags.ignore_sign = true;
break;
}
break;
- case FMA_EXPR:
- /* In X * X + Y, where Y is distinct from X, the sign of X doesn't
- matter. */
- if (gimple_assign_rhs1 (assign) == rhs
- && gimple_assign_rhs2 (assign) == rhs
- && gimple_assign_rhs3 (assign) != rhs)
- info->flags.ignore_sign = true;
- break;
-
case MULT_EXPR:
/* In X * X, the sign of X doesn't matter. */
if (gimple_assign_rhs1 (assign) == rhs
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "[USE] ");
- print_generic_expr (dump_file, rhs, 0);
+ print_generic_expr (dump_file, rhs);
fprintf (dump_file, " in ");
print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
}
backprop::intersect_uses (tree var, usage_info *info)
{
imm_use_iterator iter;
- gimple *stmt;
+ use_operand_p use_p;
*info = usage_info::intersection_identity ();
- FOR_EACH_IMM_USE_STMT (stmt, iter, var)
+ FOR_EACH_IMM_USE_FAST (use_p, iter, var)
{
+ gimple *stmt = USE_STMT (use_p);
if (is_gimple_debug (stmt))
continue;
- if (is_a <gphi *> (stmt)
- && !bitmap_bit_p (m_visited_blocks, gimple_bb (stmt)->index))
+ gphi *phi = dyn_cast <gphi *> (stmt);
+ if (phi
+ && !bitmap_bit_p (m_visited_blocks, gimple_bb (phi)->index)
+ && !bitmap_bit_p (m_visited_phis,
+ SSA_NAME_VERSION (gimple_phi_result (phi))))
{
/* Skip unprocessed phis. */
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "[BACKEDGE] ");
- print_generic_expr (dump_file, var, 0);
+ print_generic_expr (dump_file, var);
fprintf (dump_file, " in ");
- print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
+ print_gimple_stmt (dump_file, phi, 0, TDF_SLIM);
}
}
else
process_use (stmt, var, &subinfo);
*info &= subinfo;
if (!info->is_useful ())
- {
- BREAK_FROM_IMM_USE_STMT (iter);
- return false;
- }
+ return false;
}
}
return true;
}
for (gphi_iterator gpi = gsi_start_phis (bb); !gsi_end_p (gpi);
gsi_next (&gpi))
- process_var (gimple_phi_result (gpi.phi ()));
+ {
+ tree result = gimple_phi_result (gpi.phi ());
+ process_var (result);
+ bitmap_set_bit (m_visited_phis, SSA_NAME_VERSION (result));
+ }
+ bitmap_clear (m_visited_phis);
}
/* Delete the definition of VAR, which has no uses. */
note_replacement (gimple *stmt, tree old_rhs, tree new_rhs)
{
fprintf (dump_file, "Replacing use of ");
- print_generic_expr (dump_file, old_rhs, 0);
+ print_generic_expr (dump_file, old_rhs);
fprintf (dump_file, " with ");
- print_generic_expr (dump_file, new_rhs, 0);
+ print_generic_expr (dump_file, new_rhs);
fprintf (dump_file, " in ");
print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
}
switch (gimple_assign_rhs_code (assign))
{
case ABS_EXPR:
+ case ABSU_EXPR:
case NEGATE_EXPR:
return gimple_assign_rhs1 (assign);
switch (gimple_call_combined_fn (call))
{
CASE_CFN_COPYSIGN:
+ CASE_CFN_COPYSIGN_FN:
return gimple_call_arg (call, 0);
default:
void
backprop::prepare_change (tree var)
{
- if (MAY_HAVE_DEBUG_STMTS)
+ if (MAY_HAVE_DEBUG_BIND_STMTS)
insert_debug_temp_for_var_def (NULL, var);
+ reset_flow_sensitive_info (var);
}
/* STMT has been changed. Give the fold machinery a chance to simplify
void
backprop::optimize_phi (gphi *phi, tree var, const usage_info *info)
{
- /* If the sign of the result doesn't matter, strip sign operations
- from all arguments. */
+ /* If the sign of the result doesn't matter, try to strip sign operations
+ from arguments. */
if (info->flags.ignore_sign)
{
+ basic_block bb = gimple_bb (phi);
use_operand_p use;
ssa_op_iter oi;
bool replaced = false;
FOR_EACH_PHI_ARG (use, phi, oi, SSA_OP_USE)
{
+ /* Propagating along abnormal edges is delicate, punt for now. */
+ const int index = PHI_ARG_INDEX_FROM_USE (use);
+ if (EDGE_PRED (bb, index)->flags & EDGE_ABNORMAL)
+ continue;
+
tree new_arg = strip_sign_op (USE_FROM_PTR (use));
if (new_arg)
{