aboutsummaryrefslogtreecommitdiff
path: root/gcc/tree-ssa-sccvn.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/tree-ssa-sccvn.c')
-rw-r--r--gcc/tree-ssa-sccvn.c390
1 files changed, 103 insertions, 287 deletions
diff --git a/gcc/tree-ssa-sccvn.c b/gcc/tree-ssa-sccvn.c
index fb90392..8abc306 100644
--- a/gcc/tree-ssa-sccvn.c
+++ b/gcc/tree-ssa-sccvn.c
@@ -426,13 +426,11 @@ vn_reference_hash (const void *p1)
hashval_t
vn_reference_compute_hash (const vn_reference_t vr1)
{
- hashval_t result = 0;
- tree v;
+ hashval_t result;
int i;
vn_reference_op_t vro;
- for (i = 0; VEC_iterate (tree, vr1->vuses, i, v); i++)
- result += iterative_hash_expr (v, 0);
+ result = iterative_hash_expr (vr1->vuse, 0);
for (i = 0; VEC_iterate (vn_reference_op_s, vr1->operands, i, vro); i++)
result += vn_reference_op_compute_hash (vro);
@@ -445,7 +443,6 @@ vn_reference_compute_hash (const vn_reference_t vr1)
int
vn_reference_eq (const void *p1, const void *p2)
{
- tree v;
int i;
vn_reference_op_t vro;
@@ -454,15 +451,18 @@ vn_reference_eq (const void *p1, const void *p2)
if (vr1->hashcode != vr2->hashcode)
return false;
- if (vr1->vuses == vr2->vuses
- && vr1->operands == vr2->operands)
- return true;
+ /* Early out if this is not a hash collision. */
+ if (vr1->hashcode != vr2->hashcode)
+ return false;
- /* Impossible for them to be equivalent if they have different
- number of vuses. */
- if (VEC_length (tree, vr1->vuses) != VEC_length (tree, vr2->vuses))
+ /* The VOP needs to be the same. */
+ if (vr1->vuse != vr2->vuse)
return false;
+ /* If the operands are the same we are done. */
+ if (vr1->operands == vr2->operands)
+ return true;
+
/* We require that address operands be canonicalized in a way that
two memory references will have the same operands if they are
equivalent. */
@@ -470,99 +470,12 @@ vn_reference_eq (const void *p1, const void *p2)
!= VEC_length (vn_reference_op_s, vr2->operands))
return false;
- /* The memory state is more often different than the address of the
- store/load, so check it first. */
- for (i = 0; VEC_iterate (tree, vr1->vuses, i, v); i++)
- {
- if (VEC_index (tree, vr2->vuses, i) != v)
- return false;
- }
-
for (i = 0; VEC_iterate (vn_reference_op_s, vr1->operands, i, vro); i++)
- {
- if (!vn_reference_op_eq (VEC_index (vn_reference_op_s, vr2->operands, i),
- vro))
- return false;
- }
- return true;
-}
-
-/* Place the vuses from STMT into *result. */
-
-static inline void
-vuses_to_vec (gimple stmt, VEC (tree, gc) **result)
-{
- ssa_op_iter iter;
- tree vuse;
-
- if (!stmt)
- return;
-
- VEC_reserve_exact (tree, gc, *result,
- num_ssa_operands (stmt, SSA_OP_VIRTUAL_USES));
-
- FOR_EACH_SSA_TREE_OPERAND (vuse, stmt, iter, SSA_OP_VIRTUAL_USES)
- VEC_quick_push (tree, *result, vuse);
-}
-
-
-/* Copy the VUSE names in STMT into a vector, and return
- the vector. */
-
-static VEC (tree, gc) *
-copy_vuses_from_stmt (gimple stmt)
-{
- VEC (tree, gc) *vuses = NULL;
-
- vuses_to_vec (stmt, &vuses);
-
- return vuses;
-}
-
-/* Place the vdefs from STMT into *result. */
-
-static inline void
-vdefs_to_vec (gimple stmt, VEC (tree, gc) **result)
-{
- ssa_op_iter iter;
- tree vdef;
-
- if (!stmt)
- return;
-
- *result = VEC_alloc (tree, gc, num_ssa_operands (stmt, SSA_OP_VIRTUAL_DEFS));
-
- FOR_EACH_SSA_TREE_OPERAND (vdef, stmt, iter, SSA_OP_VIRTUAL_DEFS)
- VEC_quick_push (tree, *result, vdef);
-}
-
-/* Copy the names of vdef results in STMT into a vector, and return
- the vector. */
-
-static VEC (tree, gc) *
-copy_vdefs_from_stmt (gimple stmt)
-{
- VEC (tree, gc) *vdefs = NULL;
-
- vdefs_to_vec (stmt, &vdefs);
-
- return vdefs;
-}
-
-/* Place for shared_v{uses/defs}_from_stmt to shove vuses/vdefs. */
-static VEC (tree, gc) *shared_lookup_vops;
-
-/* Copy the virtual uses from STMT into SHARED_LOOKUP_VOPS.
- This function will overwrite the current SHARED_LOOKUP_VOPS
- variable. */
-
-VEC (tree, gc) *
-shared_vuses_from_stmt (gimple stmt)
-{
- VEC_truncate (tree, shared_lookup_vops, 0);
- vuses_to_vec (stmt, &shared_lookup_vops);
+ if (!vn_reference_op_eq (VEC_index (vn_reference_op_s, vr2->operands, i),
+ vro))
+ return false;
- return shared_lookup_vops;
+ return true;
}
/* Copy the operations present in load/store REF into RESULT, a vector of
@@ -696,7 +609,7 @@ copy_reference_ops_from_ref (tree ref, VEC(vn_reference_op_s, heap) **result)
Returns NULL_TREE if the ops were not handled.
This routine needs to be kept in sync with copy_reference_ops_from_ref. */
-static tree
+tree
get_ref_from_reference_ops (VEC(vn_reference_op_s, heap) *ops)
{
vn_reference_op_t op;
@@ -891,78 +804,6 @@ valueize_refs (VEC (vn_reference_op_s, heap) *orig)
return orig;
}
-/* Transform any SSA_NAME's in ORIG, a vector of vuse trees, into
- their value numbers. This is done in-place, and the vector passed
- in is returned. */
-
-static VEC (tree, gc) *
-valueize_vuses (VEC (tree, gc) *orig)
-{
- bool made_replacement = false;
- tree vuse;
- int i;
-
- for (i = 0; VEC_iterate (tree, orig, i, vuse); i++)
- {
- if (vuse != SSA_VAL (vuse))
- {
- made_replacement = true;
- VEC_replace (tree, orig, i, SSA_VAL (vuse));
- }
- }
-
- if (made_replacement && VEC_length (tree, orig) > 1)
- sort_vuses (orig);
-
- return orig;
-}
-
-/* Return the single reference statement defining all virtual uses
- in VUSES or NULL_TREE, if there are multiple defining statements.
- Take into account only definitions that alias REF if following
- back-edges. */
-
-static gimple
-get_def_ref_stmt_vuses (tree ref, VEC (tree, gc) *vuses)
-{
- gimple def_stmt;
- tree vuse;
- unsigned int i;
-
- gcc_assert (VEC_length (tree, vuses) >= 1);
-
- def_stmt = SSA_NAME_DEF_STMT (VEC_index (tree, vuses, 0));
- if (gimple_code (def_stmt) == GIMPLE_PHI)
- {
- /* We can only handle lookups over PHI nodes for a single
- virtual operand. */
- if (VEC_length (tree, vuses) == 1)
- {
- def_stmt = get_single_def_stmt_from_phi (ref, def_stmt);
- goto cont;
- }
- else
- return NULL;
- }
-
- /* Verify each VUSE reaches the same defining stmt. */
- for (i = 1; VEC_iterate (tree, vuses, i, vuse); ++i)
- {
- gimple tmp = SSA_NAME_DEF_STMT (vuse);
- if (tmp != def_stmt)
- return NULL;
- }
-
- /* Now see if the definition aliases ref, and loop until it does. */
-cont:
- while (def_stmt
- && is_gimple_assign (def_stmt)
- && !refs_may_alias_p (ref, gimple_get_lhs (def_stmt)))
- def_stmt = get_single_def_stmt_with_phi (ref, def_stmt);
-
- return def_stmt;
-}
-
/* Lookup a SCCVN reference operation VR in the current hash table.
Returns the resulting value number if it exists in the hash table,
NULL_TREE otherwise. VNRESULT will be filled in with the actual
@@ -990,6 +831,32 @@ vn_reference_lookup_1 (vn_reference_t vr, vn_reference_t *vnresult)
return NULL_TREE;
}
+/* Callback for walk_non_aliased_vuses. Adjusts the vn_reference_t VR_
+ with the current VUSE and performs the expression lookup. */
+
+static void *
+vn_reference_lookup_2 (tree op ATTRIBUTE_UNUSED, tree vuse, void *vr_)
+{
+ vn_reference_t vr = (vn_reference_t)vr_;
+ void **slot;
+ hashval_t hash;
+
+ /* Fixup vuse and hash. */
+ vr->hashcode = vr->hashcode - iterative_hash_expr (vr->vuse, 0);
+ vr->vuse = SSA_VAL (vuse);
+ vr->hashcode = vr->hashcode + iterative_hash_expr (vr->vuse, 0);
+
+ hash = vr->hashcode;
+ slot = htab_find_slot_with_hash (current_info->references, vr,
+ hash, NO_INSERT);
+ if (!slot && current_info == optimistic_info)
+ slot = htab_find_slot_with_hash (valid_info->references, vr,
+ hash, NO_INSERT);
+ if (slot)
+ return *slot;
+
+ return NULL;
+}
/* Lookup a reference operation by it's parts, in the current hash table.
Returns the resulting value number if it exists in the hash table,
@@ -997,43 +864,38 @@ vn_reference_lookup_1 (vn_reference_t vr, vn_reference_t *vnresult)
vn_reference_t stored in the hashtable if something is found. */
tree
-vn_reference_lookup_pieces (VEC (tree, gc) *vuses,
+vn_reference_lookup_pieces (tree vuse,
VEC (vn_reference_op_s, heap) *operands,
vn_reference_t *vnresult, bool maywalk)
{
struct vn_reference_s vr1;
- tree result;
- if (vnresult)
- *vnresult = NULL;
+ vn_reference_t tmp;
+
+ if (!vnresult)
+ vnresult = &tmp;
+ *vnresult = NULL;
- vr1.vuses = valueize_vuses (vuses);
+ vr1.vuse = vuse ? SSA_VAL (vuse) : NULL_TREE;
vr1.operands = valueize_refs (operands);
vr1.hashcode = vn_reference_compute_hash (&vr1);
- result = vn_reference_lookup_1 (&vr1, vnresult);
+ vn_reference_lookup_1 (&vr1, vnresult);
- /* If there is a single defining statement for all virtual uses, we can
- use that, following virtual use-def chains. */
- if (!result
+ if (!*vnresult
&& maywalk
- && vr1.vuses
- && VEC_length (tree, vr1.vuses) >= 1)
+ && vr1.vuse)
{
tree ref = get_ref_from_reference_ops (operands);
- gimple def_stmt;
- if (ref
- && (def_stmt = get_def_ref_stmt_vuses (ref, vr1.vuses))
- && is_gimple_assign (def_stmt))
- {
- /* We are now at an aliasing definition for the vuses we want to
- look up. Re-do the lookup with the vdefs for this stmt. */
- vdefs_to_vec (def_stmt, &vuses);
- vr1.vuses = valueize_vuses (vuses);
- vr1.hashcode = vn_reference_compute_hash (&vr1);
- result = vn_reference_lookup_1 (&vr1, vnresult);
- }
+ if (!ref)
+ return NULL_TREE;
+ *vnresult =
+ (vn_reference_t)walk_non_aliased_vuses (ref, vr1.vuse,
+ vn_reference_lookup_2, &vr1);
}
- return result;
+ if (*vnresult)
+ return (*vnresult)->result;
+
+ return NULL_TREE;
}
/* Lookup OP in the current hash table, and return the resulting value
@@ -1043,38 +905,36 @@ vn_reference_lookup_pieces (VEC (tree, gc) *vuses,
stored in the hashtable if one exists. */
tree
-vn_reference_lookup (tree op, VEC (tree, gc) *vuses, bool maywalk,
+vn_reference_lookup (tree op, tree vuse, bool maywalk,
vn_reference_t *vnresult)
{
struct vn_reference_s vr1;
- tree result;
- gimple def_stmt;
+
if (vnresult)
*vnresult = NULL;
- vr1.vuses = valueize_vuses (vuses);
+ vr1.vuse = vuse ? SSA_VAL (vuse) : NULL_TREE;
vr1.operands = valueize_refs (shared_reference_ops_from_ref (op));
vr1.hashcode = vn_reference_compute_hash (&vr1);
- result = vn_reference_lookup_1 (&vr1, vnresult);
- /* If there is a single defining statement for all virtual uses, we can
- use that, following virtual use-def chains. */
- if (!result
- && maywalk
- && vr1.vuses
- && VEC_length (tree, vr1.vuses) >= 1
- && (def_stmt = get_def_ref_stmt_vuses (op, vr1.vuses))
- && is_gimple_assign (def_stmt))
+ if (maywalk
+ && vr1.vuse)
{
- /* We are now at an aliasing definition for the vuses we want to
- look up. Re-do the lookup with the vdefs for this stmt. */
- vdefs_to_vec (def_stmt, &vuses);
- vr1.vuses = valueize_vuses (vuses);
- vr1.hashcode = vn_reference_compute_hash (&vr1);
- result = vn_reference_lookup_1 (&vr1, vnresult);
+ vn_reference_t wvnresult;
+ wvnresult =
+ (vn_reference_t)walk_non_aliased_vuses (op, vr1.vuse,
+ vn_reference_lookup_2, &vr1);
+ if (wvnresult)
+ {
+ if (vnresult)
+ *vnresult = wvnresult;
+ return wvnresult->result;
+ }
+
+ return NULL_TREE;
}
- return result;
+ return vn_reference_lookup_1 (&vr1, vnresult);
}
@@ -1082,7 +942,7 @@ vn_reference_lookup (tree op, VEC (tree, gc) *vuses, bool maywalk,
RESULT, and return the resulting reference structure we created. */
vn_reference_t
-vn_reference_insert (tree op, tree result, VEC (tree, gc) *vuses)
+vn_reference_insert (tree op, tree result, tree vuse)
{
void **slot;
vn_reference_t vr1;
@@ -1092,7 +952,7 @@ vn_reference_insert (tree op, tree result, VEC (tree, gc) *vuses)
vr1->value_id = VN_INFO (result)->value_id;
else
vr1->value_id = get_or_alloc_constant_value_id (result);
- vr1->vuses = valueize_vuses (vuses);
+ vr1->vuse = vuse ? SSA_VAL (vuse) : NULL_TREE;
vr1->operands = valueize_refs (create_reference_ops_from_ref (op));
vr1->hashcode = vn_reference_compute_hash (vr1);
vr1->result = TREE_CODE (result) == SSA_NAME ? SSA_VAL (result) : result;
@@ -1121,7 +981,7 @@ vn_reference_insert (tree op, tree result, VEC (tree, gc) *vuses)
structure we created. */
vn_reference_t
-vn_reference_insert_pieces (VEC (tree, gc) *vuses,
+vn_reference_insert_pieces (tree vuse,
VEC (vn_reference_op_s, heap) *operands,
tree result, unsigned int value_id)
@@ -1130,8 +990,8 @@ vn_reference_insert_pieces (VEC (tree, gc) *vuses,
vn_reference_t vr1;
vr1 = (vn_reference_t) pool_alloc (current_info->references_pool);
- vr1->value_id = value_id;
- vr1->vuses = valueize_vuses (vuses);
+ vr1->value_id = value_id;
+ vr1->vuse = vuse ? SSA_VAL (vuse) : NULL_TREE;
vr1->operands = valueize_refs (operands);
vr1->hashcode = vn_reference_compute_hash (vr1);
if (result && TREE_CODE (result) == SSA_NAME)
@@ -1142,8 +1002,8 @@ vn_reference_insert_pieces (VEC (tree, gc) *vuses,
INSERT);
/* At this point we should have all the things inserted that we have
- seen before, and we should never try inserting something that
- already exists. */
+ seen before, and we should never try inserting something that
+ already exists. */
gcc_assert (!*slot);
if (*slot)
free_reference (*slot);
@@ -1614,7 +1474,7 @@ set_ssa_val_to (tree from, tree to)
if (currval != to && !operand_equal_p (currval, to, OEP_PURE_SAME))
{
- SSA_VAL (from) = to;
+ VN_INFO (from)->valnum = to;
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, " (changed)\n");
return true;
@@ -1722,8 +1582,9 @@ visit_reference_op_call (tree lhs, gimple stmt)
bool changed = false;
struct vn_reference_s vr1;
tree result;
+ tree vuse = gimple_vuse (stmt);
- vr1.vuses = valueize_vuses (shared_vuses_from_stmt (stmt));
+ vr1.vuse = vuse ? SSA_VAL (vuse) : NULL_TREE;
vr1.operands = valueize_refs (shared_reference_ops_from_call (stmt));
vr1.hashcode = vn_reference_compute_hash (&vr1);
result = vn_reference_lookup_1 (&vr1, NULL);
@@ -1740,7 +1601,7 @@ visit_reference_op_call (tree lhs, gimple stmt)
vn_reference_t vr2;
changed = set_ssa_val_to (lhs, lhs);
vr2 = (vn_reference_t) pool_alloc (current_info->references_pool);
- vr2->vuses = valueize_vuses (copy_vuses_from_stmt (stmt));
+ vr2->vuse = vr1.vuse;
vr2->operands = valueize_refs (create_reference_ops_from_call (stmt));
vr2->hashcode = vr1.hashcode;
vr2->result = lhs;
@@ -1761,8 +1622,7 @@ static bool
visit_reference_op_load (tree lhs, tree op, gimple stmt)
{
bool changed = false;
- tree result = vn_reference_lookup (op, shared_vuses_from_stmt (stmt), true,
- NULL);
+ tree result = vn_reference_lookup (op, gimple_vuse (stmt), true, NULL);
/* We handle type-punning through unions by value-numbering based
on offset and size of the access. Be prepared to handle a
@@ -1840,7 +1700,7 @@ visit_reference_op_load (tree lhs, tree op, gimple stmt)
else
{
changed = set_ssa_val_to (lhs, lhs);
- vn_reference_insert (op, lhs, copy_vuses_from_stmt (stmt));
+ vn_reference_insert (op, lhs, gimple_vuse (stmt));
}
return changed;
@@ -1873,8 +1733,7 @@ visit_reference_op_store (tree lhs, tree op, gimple stmt)
Otherwise, the vdefs for the store are used when inserting into
the table, since the store generates a new memory state. */
- result = vn_reference_lookup (lhs, shared_vuses_from_stmt (stmt), false,
- NULL);
+ result = vn_reference_lookup (lhs, gimple_vuse (stmt), false, NULL);
if (result)
{
@@ -1887,8 +1746,6 @@ visit_reference_op_store (tree lhs, tree op, gimple stmt)
if (!result || !resultsame)
{
- VEC(tree, gc) *vdefs = copy_vdefs_from_stmt (stmt);
- int i;
tree vdef;
if (dump_file && (dump_flags & TDF_DETAILS))
@@ -1902,7 +1759,7 @@ visit_reference_op_store (tree lhs, tree op, gimple stmt)
}
/* Have to set value numbers before insert, since insert is
going to valueize the references in-place. */
- for (i = 0; VEC_iterate (tree, vdefs, i, vdef); i++)
+ if ((vdef = gimple_vdef (stmt)))
{
VN_INFO (vdef)->use_processed = true;
changed |= set_ssa_val_to (vdef, vdef);
@@ -1911,36 +1768,23 @@ visit_reference_op_store (tree lhs, tree op, gimple stmt)
/* Do not insert structure copies into the tables. */
if (is_gimple_min_invariant (op)
|| is_gimple_reg (op))
- vn_reference_insert (lhs, op, vdefs);
+ vn_reference_insert (lhs, op, vdef);
}
else
{
- /* We had a match, so value number the vdefs to have the value
- number of the vuses they came from. */
- ssa_op_iter op_iter;
- def_operand_p var;
- vuse_vec_p vv;
+ /* We had a match, so value number the vdef to have the value
+ number of the vuse it came from. */
+ tree def, use;
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "Store matched earlier value,"
"value numbering store vdefs to matching vuses.\n");
- FOR_EACH_SSA_VDEF_OPERAND (var, vv, stmt, op_iter)
- {
- tree def = DEF_FROM_PTR (var);
- tree use;
-
- /* Uh, if the vuse is a multiuse, we can't really do much
- here, sadly, since we don't know which value number of
- which vuse to use. */
- if (VUSE_VECT_NUM_ELEM (*vv) != 1)
- use = def;
- else
- use = VUSE_ELEMENT_VAR (*vv, 0);
+ def = gimple_vdef (stmt);
+ use = gimple_vuse (stmt);
- VN_INFO (def)->use_processed = true;
- changed |= set_ssa_val_to (def, SSA_VAL (use));
- }
+ VN_INFO (def)->use_processed = true;
+ changed |= set_ssa_val_to (def, SSA_VAL (use));
}
return changed;
@@ -2802,7 +2646,6 @@ init_scc_vn (void)
gcc_obstack_init (&vn_ssa_aux_obstack);
shared_lookup_phiargs = NULL;
- shared_lookup_vops = NULL;
shared_lookup_references = NULL;
rpo_numbers = XCNEWVEC (int, last_basic_block + NUM_FIXED_BLOCKS);
rpo_numbers_temp = XCNEWVEC (int, last_basic_block + NUM_FIXED_BLOCKS);
@@ -2848,7 +2691,6 @@ free_scc_vn (void)
htab_delete (constant_to_value_id);
BITMAP_FREE (constant_value_ids);
VEC_free (tree, heap, shared_lookup_phiargs);
- VEC_free (tree, gc, shared_lookup_vops);
VEC_free (vn_reference_op_s, heap, shared_lookup_references);
XDELETEVEC (rpo_numbers);
@@ -2941,7 +2783,7 @@ run_scc_vn (bool may_insert_arg)
if (gimple_default_def (cfun, param) != NULL)
{
tree def = gimple_default_def (cfun, param);
- SSA_VAL (def) = def;
+ VN_INFO (def)->valnum = def;
}
}
@@ -3074,32 +2916,6 @@ expressions_equal_p (tree e1, tree e2)
return false;
}
-/* Sort the VUSE array so that we can do equality comparisons
- quicker on two vuse vecs. */
-
-void
-sort_vuses (VEC (tree,gc) *vuses)
-{
- if (VEC_length (tree, vuses) > 1)
- qsort (VEC_address (tree, vuses),
- VEC_length (tree, vuses),
- sizeof (tree),
- operand_build_cmp);
-}
-
-/* Sort the VUSE array so that we can do equality comparisons
- quicker on two vuse vecs. */
-
-void
-sort_vuses_heap (VEC (tree,heap) *vuses)
-{
- if (VEC_length (tree, vuses) > 1)
- qsort (VEC_address (tree, vuses),
- VEC_length (tree, vuses),
- sizeof (tree),
- operand_build_cmp);
-}
-
/* Return true if the nary operation NARY may trap. This is a copy
of stmt_could_throw_1_p adjusted to the SCCVN IL. */