struct im_mem_ref
{
- unsigned id : 31; /* ID assigned to the memory reference
+ unsigned id : 30; /* ID assigned to the memory reference
(its index in memory_accesses.refs_list) */
unsigned ref_canonical : 1; /* Whether mem.ref was canonicalized. */
+ unsigned ref_decomposed : 1; /* Whether the ref was hashed from mem. */
hashval_t hash; /* Its hash value. */
/* The memory access itself and associated caching of alias-oracle
mem_ref_hasher::equal (const im_mem_ref *mem1, const ao_ref *obj2)
{
if (obj2->max_size_known_p ())
- return (operand_equal_p (mem1->mem.base, obj2->base, 0)
+ return (mem1->ref_decomposed
+ && operand_equal_p (mem1->mem.base, obj2->base, 0)
&& known_eq (mem1->mem.offset, obj2->offset)
&& known_eq (mem1->mem.size, obj2->size)
&& known_eq (mem1->mem.max_size, obj2->max_size)
ao_ref_init (&ref->mem, error_mark_node);
ref->id = id;
ref->ref_canonical = false;
+ ref->ref_decomposed = false;
ref->hash = hash;
ref->stored = NULL;
bitmap_initialize (&ref->indep_loop, &lim_bitmap_obstack);
HOST_WIDE_INT offset, size, max_size;
poly_int64 saved_maxsize = aor.max_size, mem_off;
tree mem_base;
+ bool ref_decomposed;
if (aor.max_size_known_p ()
&& aor.offset.is_constant (&offset)
&& aor.size.is_constant (&size)
aor.size)
&& (mem_base = get_addr_base_and_unit_offset (aor.ref, &mem_off)))
{
+ ref_decomposed = true;
hash = iterative_hash_expr (ao_ref_base (&aor), 0);
hash = iterative_hash_host_wide_int (offset, hash);
hash = iterative_hash_host_wide_int (size, hash);
}
else
{
+ ref_decomposed = false;
hash = iterative_hash_expr (aor.ref, 0);
aor.max_size = -1;
}
{
id = memory_accesses.refs_list.length ();
ref = mem_ref_alloc (&aor, hash, id);
+ ref->ref_decomposed = ref_decomposed;
memory_accesses.refs_list.safe_push (ref);
*slot = ref;
static unsigned
process_bb (rpo_elim &avail, basic_block bb,
bool bb_visited, bool iterate_phis, bool iterate, bool eliminate,
- bool do_region, bitmap exit_bbs)
+ bool do_region, bitmap exit_bbs, bool skip_phis)
{
unsigned todo = 0;
edge_iterator ei;
/* If we are in loop-closed SSA preserve this state. This is
relevant when called on regions from outside of FRE/PRE. */
bool lc_phi_nodes = false;
- if (loops_state_satisfies_p (LOOP_CLOSED_SSA))
+ if (!skip_phis
+ && loops_state_satisfies_p (LOOP_CLOSED_SSA))
FOR_EACH_EDGE (e, ei, bb->preds)
if (e->src->loop_father != e->dest->loop_father
&& flow_loop_nested_p (e->dest->loop_father,
}
/* Value-number all defs in the basic-block. */
- for (gphi_iterator gsi = gsi_start_phis (bb); !gsi_end_p (gsi);
- gsi_next (&gsi))
- {
- gphi *phi = gsi.phi ();
- tree res = PHI_RESULT (phi);
- vn_ssa_aux_t res_info = VN_INFO (res);
- if (!bb_visited)
- {
- gcc_assert (!res_info->visited);
- res_info->valnum = VN_TOP;
- res_info->visited = true;
- }
+ if (!skip_phis)
+ for (gphi_iterator gsi = gsi_start_phis (bb); !gsi_end_p (gsi);
+ gsi_next (&gsi))
+ {
+ gphi *phi = gsi.phi ();
+ tree res = PHI_RESULT (phi);
+ vn_ssa_aux_t res_info = VN_INFO (res);
+ if (!bb_visited)
+ {
+ gcc_assert (!res_info->visited);
+ res_info->valnum = VN_TOP;
+ res_info->visited = true;
+ }
- /* When not iterating force backedge values to varying. */
- visit_stmt (phi, !iterate_phis);
- if (virtual_operand_p (res))
- continue;
+ /* When not iterating force backedge values to varying. */
+ visit_stmt (phi, !iterate_phis);
+ if (virtual_operand_p (res))
+ continue;
- /* Eliminate */
- /* The interesting case is gcc.dg/tree-ssa/pr22230.c for correctness
- how we handle backedges and availability.
- And gcc.dg/tree-ssa/ssa-sccvn-2.c for optimization. */
- tree val = res_info->valnum;
- if (res != val && !iterate && eliminate)
- {
- if (tree leader = avail.eliminate_avail (bb, res))
- {
- if (leader != res
- /* Preserve loop-closed SSA form. */
- && (! lc_phi_nodes
- || is_gimple_min_invariant (leader)))
- {
- if (dump_file && (dump_flags & TDF_DETAILS))
- {
- fprintf (dump_file, "Replaced redundant PHI node "
- "defining ");
- print_generic_expr (dump_file, res);
- fprintf (dump_file, " with ");
- print_generic_expr (dump_file, leader);
- fprintf (dump_file, "\n");
- }
- avail.eliminations++;
+ /* Eliminate */
+ /* The interesting case is gcc.dg/tree-ssa/pr22230.c for correctness
+ how we handle backedges and availability.
+ And gcc.dg/tree-ssa/ssa-sccvn-2.c for optimization. */
+ tree val = res_info->valnum;
+ if (res != val && !iterate && eliminate)
+ {
+ if (tree leader = avail.eliminate_avail (bb, res))
+ {
+ if (leader != res
+ /* Preserve loop-closed SSA form. */
+ && (! lc_phi_nodes
+ || is_gimple_min_invariant (leader)))
+ {
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "Replaced redundant PHI node "
+ "defining ");
+ print_generic_expr (dump_file, res);
+ fprintf (dump_file, " with ");
+ print_generic_expr (dump_file, leader);
+ fprintf (dump_file, "\n");
+ }
+ avail.eliminations++;
- if (may_propagate_copy (res, leader))
- {
- /* Schedule for removal. */
- avail.to_remove.safe_push (phi);
- continue;
- }
- /* ??? Else generate a copy stmt. */
- }
- }
- }
- /* Only make defs available that not already are. But make
- sure loop-closed SSA PHI node defs are picked up for
- downstream uses. */
- if (lc_phi_nodes
- || res == val
- || ! avail.eliminate_avail (bb, res))
- avail.eliminate_push_avail (bb, res);
- }
+ if (may_propagate_copy (res, leader))
+ {
+ /* Schedule for removal. */
+ avail.to_remove.safe_push (phi);
+ continue;
+ }
+ /* ??? Else generate a copy stmt. */
+ }
+ }
+ }
+ /* Only make defs available that not already are. But make
+ sure loop-closed SSA PHI node defs are picked up for
+ downstream uses. */
+ if (lc_phi_nodes
+ || res == val
+ || ! avail.eliminate_avail (bb, res))
+ avail.eliminate_push_avail (bb, res);
+ }
/* For empty BBs mark outgoing edges executable. For non-empty BBs
we do this when processing the last stmt as we have to do this
bitmap_set_bit (exit_bbs, EXIT_BLOCK);
}
+ /* Clear EDGE_DFS_BACK on "all" entry edges, RPO order compute will
+ re-mark those that are contained in the region. */
+ edge_iterator ei;
+ edge e;
+ FOR_EACH_EDGE (e, ei, entry->dest->preds)
+ e->flags &= ~EDGE_DFS_BACK;
+
int *rpo = XNEWVEC (int, n_basic_blocks_for_fn (fn) - NUM_FIXED_BLOCKS);
int n = rev_post_order_and_mark_dfs_back_seme
(fn, entry, exit_bbs, !loops_state_satisfies_p (LOOPS_NEED_FIXUP), rpo);
if (!do_region)
BITMAP_FREE (exit_bbs);
+ /* If there are any non-DFS_BACK edges into entry->dest skip
+ processing PHI nodes for that block. This supports
+ value-numbering loop bodies w/o the actual loop. */
+ FOR_EACH_EDGE (e, ei, entry->dest->preds)
+ if (e != entry
+ && !(e->flags & EDGE_DFS_BACK))
+ break;
+ bool skip_entry_phis = e != NULL;
+ if (skip_entry_phis && dump_file && (dump_flags & TDF_DETAILS))
+ fprintf (dump_file, "Region does not contain all edges into "
+ "the entry block, skipping its PHIs.\n");
+
int *bb_to_rpo = XNEWVEC (int, last_basic_block_for_fn (fn));
for (int i = 0; i < n; ++i)
bb_to_rpo[rpo[i]] = i;
edge e;
edge_iterator ei;
FOR_EACH_EDGE (e, ei, bb->preds)
- gcc_assert (e == entry || (e->src->flags & bb_in_region));
+ gcc_assert (e == entry
+ || (skip_entry_phis && bb == entry->dest)
+ || (e->src->flags & bb_in_region));
}
for (int i = 0; i < n; ++i)
{
if (e->flags & EDGE_DFS_BACK)
has_backedges = true;
e->flags &= ~EDGE_EXECUTABLE;
- if (iterate || e == entry)
+ if (iterate || e == entry || (skip_entry_phis && bb == entry->dest))
continue;
if (bb_to_rpo[e->src->index] > i)
{
edge_iterator ei;
FOR_EACH_EDGE (e, ei, bb->preds)
{
- if (e == entry)
+ if (e == entry || (skip_entry_phis && bb == entry->dest))
continue;
int max_rpo = MAX (rpo_state[i].max_rpo,
rpo_state[bb_to_rpo[e->src->index]].max_rpo);
todo |= process_bb (avail, bb,
rpo_state[idx].visited != 0,
rpo_state[idx].iterate,
- iterate, eliminate, do_region, exit_bbs);
+ iterate, eliminate, do_region, exit_bbs, false);
rpo_state[idx].visited++;
/* Verify if changed values flow over executable outgoing backedges
edge e;
FOR_EACH_EDGE (e, ei, bb->preds)
if (!(e->flags & EDGE_EXECUTABLE)
- && !rpo_state[bb_to_rpo[e->src->index]].visited
- && rpo_state[bb_to_rpo[e->src->index]].max_rpo >= (int)idx)
+ && (bb == entry->dest
+ || (!rpo_state[bb_to_rpo[e->src->index]].visited
+ && (rpo_state[bb_to_rpo[e->src->index]].max_rpo
+ >= (int)idx))))
{
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "Cannot trust state of predecessor "
nblk++;
todo |= process_bb (avail, bb, false, false, false, eliminate,
- do_region, exit_bbs);
+ do_region, exit_bbs,
+ skip_entry_phis && bb == entry->dest);
rpo_state[idx].visited++;
FOR_EACH_EDGE (e, ei, bb->succs)
}
/* Region-based entry for RPO VN. Performs value-numbering and elimination
- on the SEME region specified by ENTRY and EXIT_BBS. */
+ on the SEME region specified by ENTRY and EXIT_BBS. If ENTRY is not
+ the only edge into the region at ENTRY->dest PHI nodes in ENTRY->dest
+ are not considered. */
unsigned
do_rpo_vn (function *fn, edge entry, bitmap exit_bbs)