Index: gcc/gcc/tree-ssa-copy.c |
diff --git a/gcc/gcc/tree-ssa-copy.c b/gcc/gcc/tree-ssa-copy.c |
index 64c697a51968084608df3665add68ae1930aacb0..9f1f9c41fde11aa48a89abf243cf25a5a5333cde 100644 |
--- a/gcc/gcc/tree-ssa-copy.c |
+++ b/gcc/gcc/tree-ssa-copy.c |
@@ -1,5 +1,6 @@ |
/* Copy propagation and SSA_NAME replacement support routines. |
- Copyright (C) 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. |
+ Copyright (C) 2004, 2005, 2006, 2007, 2008, 2010 |
+ Free Software Foundation, Inc. |
This file is part of GCC. |
@@ -37,6 +38,7 @@ along with GCC; see the file COPYING3. If not see |
#include "tree-pass.h" |
#include "tree-ssa-propagate.h" |
#include "langhooks.h" |
+#include "cfgloop.h" |
/* This file implements the copy propagation pass and provides a |
handful of interfaces for performing const/copy propagation and |
@@ -73,111 +75,17 @@ may_propagate_copy (tree dest, tree orig) |
&& SSA_NAME_OCCURS_IN_ABNORMAL_PHI (dest)) |
return false; |
- /* For memory partitions, copies are OK as long as the memory symbol |
- belongs to the partition. */ |
- if (TREE_CODE (dest) == SSA_NAME |
- && TREE_CODE (SSA_NAME_VAR (dest)) == MEMORY_PARTITION_TAG) |
- return (TREE_CODE (orig) == SSA_NAME |
- && !is_gimple_reg (orig) |
- && (SSA_NAME_VAR (dest) == SSA_NAME_VAR (orig) |
- || bitmap_bit_p (MPT_SYMBOLS (SSA_NAME_VAR (dest)), |
- DECL_UID (SSA_NAME_VAR (orig))))); |
- |
- if (TREE_CODE (orig) == SSA_NAME |
- && TREE_CODE (SSA_NAME_VAR (orig)) == MEMORY_PARTITION_TAG) |
- return (TREE_CODE (dest) == SSA_NAME |
- && !is_gimple_reg (dest) |
- && (SSA_NAME_VAR (dest) == SSA_NAME_VAR (orig) |
- || bitmap_bit_p (MPT_SYMBOLS (SSA_NAME_VAR (orig)), |
- DECL_UID (SSA_NAME_VAR (dest))))); |
- |
/* Do not copy between types for which we *do* need a conversion. */ |
if (!useless_type_conversion_p (type_d, type_o)) |
return false; |
- /* FIXME. GIMPLE is allowing pointer assignments and comparisons of |
- pointers that have different alias sets. This means that these |
- pointers will have different memory tags associated to them. |
- |
- If we allow copy propagation in these cases, statements de-referencing |
- the new pointer will now have a reference to a different memory tag |
- with potentially incorrect SSA information. |
- |
- This was showing up in libjava/java/util/zip/ZipFile.java with code |
- like: |
- |
- struct java.io.BufferedInputStream *T.660; |
- struct java.io.BufferedInputStream *T.647; |
- struct java.io.InputStream *is; |
- struct java.io.InputStream *is.662; |
- [ ... ] |
- T.660 = T.647; |
- is = T.660; <-- This ought to be type-casted |
- is.662 = is; |
- |
- Also, f/name.c exposed a similar problem with a COND_EXPR predicate |
- that was causing DOM to generate and equivalence with two pointers of |
- alias-incompatible types: |
- |
- struct _ffename_space *n; |
- struct _ffename *ns; |
- [ ... ] |
- if (n == ns) |
- goto lab; |
- ... |
- lab: |
- return n; |
- |
- I think that GIMPLE should emit the appropriate type-casts. For the |
- time being, blocking copy-propagation in these cases is the safe thing |
- to do. */ |
- if (TREE_CODE (dest) == SSA_NAME |
- && TREE_CODE (orig) == SSA_NAME |
- && POINTER_TYPE_P (type_d) |
- && POINTER_TYPE_P (type_o)) |
- { |
- tree mt_dest = symbol_mem_tag (SSA_NAME_VAR (dest)); |
- tree mt_orig = symbol_mem_tag (SSA_NAME_VAR (orig)); |
- if (mt_dest && mt_orig && mt_dest != mt_orig) |
- return false; |
- else if (get_alias_set (TREE_TYPE (type_d)) != |
- get_alias_set (TREE_TYPE (type_o))) |
- return false; |
- else if (!MTAG_P (SSA_NAME_VAR (dest)) |
- && !MTAG_P (SSA_NAME_VAR (orig)) |
- && (DECL_NO_TBAA_P (SSA_NAME_VAR (dest)) |
- != DECL_NO_TBAA_P (SSA_NAME_VAR (orig)))) |
- return false; |
- |
- /* Also verify flow-sensitive information is compatible. */ |
- if (SSA_NAME_PTR_INFO (orig) && SSA_NAME_PTR_INFO (dest)) |
- { |
- struct ptr_info_def *orig_ptr_info = SSA_NAME_PTR_INFO (orig); |
- struct ptr_info_def *dest_ptr_info = SSA_NAME_PTR_INFO (dest); |
- |
- if (orig_ptr_info->name_mem_tag |
- && dest_ptr_info->name_mem_tag |
- && orig_ptr_info->pt_vars |
- && dest_ptr_info->pt_vars |
- && !bitmap_intersect_p (dest_ptr_info->pt_vars, |
- orig_ptr_info->pt_vars)) |
- return false; |
- } |
- } |
- |
- /* If the destination is a SSA_NAME for a virtual operand, then we have |
- some special cases to handle. */ |
+ /* Propagating virtual operands is always ok. */ |
if (TREE_CODE (dest) == SSA_NAME && !is_gimple_reg (dest)) |
{ |
- /* If both operands are SSA_NAMEs referring to virtual operands, then |
- we can always propagate. */ |
- if (TREE_CODE (orig) == SSA_NAME |
- && !is_gimple_reg (orig)) |
- return true; |
- |
- /* We have a "copy" from something like a constant into a virtual |
- operand. Reject these. */ |
- return false; |
+ /* But only between virtual operands. */ |
+ gcc_assert (TREE_CODE (orig) == SSA_NAME && !is_gimple_reg (orig)); |
+ |
+ return true; |
} |
/* Anything else is OK. */ |
@@ -211,8 +119,7 @@ may_propagate_copy_into_stmt (gimple dest, tree orig) |
is much simpler. */ |
if (TREE_CODE (orig) == SSA_NAME |
- && (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (orig) |
- || TREE_CODE (SSA_NAME_VAR (orig)) == MEMORY_PARTITION_TAG)) |
+ && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (orig)) |
return false; |
if (is_gimple_assign (dest)) |
@@ -245,106 +152,6 @@ may_propagate_copy_into_asm (tree dest) |
} |
-/* Given two SSA_NAMEs pointers ORIG and NEW such that we are copy |
- propagating NEW into ORIG, consolidate aliasing information so that |
- they both share the same memory tags. */ |
- |
-void |
-merge_alias_info (tree orig_name, tree new_name) |
-{ |
- tree new_sym = SSA_NAME_VAR (new_name); |
- tree orig_sym = SSA_NAME_VAR (orig_name); |
- var_ann_t new_ann = var_ann (new_sym); |
- var_ann_t orig_ann = var_ann (orig_sym); |
- |
- /* No merging necessary when memory partitions are involved. */ |
- if (factoring_name_p (new_name)) |
- { |
- gcc_assert (!is_gimple_reg (orig_sym)); |
- return; |
- } |
- else if (factoring_name_p (orig_name)) |
- { |
- gcc_assert (!is_gimple_reg (new_sym)); |
- return; |
- } |
- |
- gcc_assert (POINTER_TYPE_P (TREE_TYPE (orig_name)) |
- && POINTER_TYPE_P (TREE_TYPE (new_name))); |
- |
-#if defined ENABLE_CHECKING |
- gcc_assert (useless_type_conversion_p (TREE_TYPE (orig_name), |
- TREE_TYPE (new_name))); |
- |
- /* Check that flow-sensitive information is compatible. Notice that |
- we may not merge flow-sensitive information here. This function |
- is called when propagating equivalences dictated by the IL, like |
- a copy operation P_i = Q_j, and from equivalences dictated by |
- control-flow, like if (P_i == Q_j). |
- |
- In the former case, P_i and Q_j are equivalent in every block |
- dominated by the assignment, so their flow-sensitive information |
- is always the same. However, in the latter case, the pointers |
- P_i and Q_j are only equivalent in one of the sub-graphs out of |
- the predicate, so their flow-sensitive information is not the |
- same in every block dominated by the predicate. |
- |
- Since we cannot distinguish one case from another in this |
- function, we can only make sure that if P_i and Q_j have |
- flow-sensitive information, they should be compatible. |
- |
- As callers of merge_alias_info are supposed to call may_propagate_copy |
- first, the following check is redundant. Thus, only do it if checking |
- is enabled. */ |
- if (SSA_NAME_PTR_INFO (orig_name) && SSA_NAME_PTR_INFO (new_name)) |
- { |
- struct ptr_info_def *orig_ptr_info = SSA_NAME_PTR_INFO (orig_name); |
- struct ptr_info_def *new_ptr_info = SSA_NAME_PTR_INFO (new_name); |
- |
- /* Note that pointer NEW and ORIG may actually have different |
- pointed-to variables (e.g., PR 18291 represented in |
- testsuite/gcc.c-torture/compile/pr18291.c). However, since |
- NEW is being copy-propagated into ORIG, it must always be |
- true that the pointed-to set for pointer NEW is the same, or |
- a subset, of the pointed-to set for pointer ORIG. If this |
- isn't the case, we shouldn't have been able to do the |
- propagation of NEW into ORIG. */ |
- if (orig_ptr_info->name_mem_tag |
- && new_ptr_info->name_mem_tag |
- && orig_ptr_info->pt_vars |
- && new_ptr_info->pt_vars) |
- gcc_assert (bitmap_intersect_p (new_ptr_info->pt_vars, |
- orig_ptr_info->pt_vars)); |
- } |
-#endif |
- |
- /* Synchronize the symbol tags. If both pointers had a tag and they |
- are different, then something has gone wrong. Symbol tags can |
- always be merged because they are flow insensitive, all the SSA |
- names of the same base DECL share the same symbol tag. */ |
- if (new_ann->symbol_mem_tag == NULL_TREE) |
- new_ann->symbol_mem_tag = orig_ann->symbol_mem_tag; |
- else if (orig_ann->symbol_mem_tag == NULL_TREE) |
- orig_ann->symbol_mem_tag = new_ann->symbol_mem_tag; |
- else |
- gcc_assert (new_ann->symbol_mem_tag == orig_ann->symbol_mem_tag); |
- |
- /* Copy flow-sensitive alias information in case that NEW_NAME |
- didn't get a NMT but was set to pt_anything for optimization |
- purposes. In case ORIG_NAME has a NMT we can safely use its |
- flow-sensitive alias information as a conservative estimate. */ |
- if (SSA_NAME_PTR_INFO (orig_name) |
- && SSA_NAME_PTR_INFO (orig_name)->name_mem_tag |
- && (!SSA_NAME_PTR_INFO (new_name) |
- || !SSA_NAME_PTR_INFO (new_name)->name_mem_tag)) |
- { |
- struct ptr_info_def *orig_ptr_info = SSA_NAME_PTR_INFO (orig_name); |
- struct ptr_info_def *new_ptr_info = get_ptr_info (new_name); |
- memcpy (new_ptr_info, orig_ptr_info, sizeof (struct ptr_info_def)); |
- } |
-} |
- |
- |
/* Common code for propagate_value and replace_exp. |
Replace use operand OP_P with VAL. FOR_PROPAGATION indicates if the |
@@ -354,9 +161,9 @@ static void |
replace_exp_1 (use_operand_p op_p, tree val, |
bool for_propagation ATTRIBUTE_UNUSED) |
{ |
+#if defined ENABLE_CHECKING |
tree op = USE_FROM_PTR (op_p); |
-#if defined ENABLE_CHECKING |
gcc_assert (!(for_propagation |
&& TREE_CODE (op) == SSA_NAME |
&& TREE_CODE (val) == SSA_NAME |
@@ -364,11 +171,7 @@ replace_exp_1 (use_operand_p op_p, tree val, |
#endif |
if (TREE_CODE (val) == SSA_NAME) |
- { |
- if (TREE_CODE (op) == SSA_NAME && POINTER_TYPE_P (TREE_TYPE (op))) |
- merge_alias_info (op, val); |
- SET_USE (op_p, val); |
- } |
+ SET_USE (op_p, val); |
else |
SET_USE (op_p, unsave_expr_now (val)); |
} |
@@ -418,11 +221,7 @@ propagate_tree_value (tree *op_p, tree val) |
#endif |
if (TREE_CODE (val) == SSA_NAME) |
- { |
- if (*op_p && TREE_CODE (*op_p) == SSA_NAME && POINTER_TYPE_P (TREE_TYPE (*op_p))) |
- merge_alias_info (*op_p, val); |
- *op_p = val; |
- } |
+ *op_p = val; |
else |
*op_p = unsave_expr_now (val); |
} |
@@ -464,8 +263,7 @@ propagate_tree_value_into_stmt (gimple_stmt_iterator *gsi, tree val) |
tree expr = NULL_TREE; |
propagate_tree_value (&expr, val); |
- new_stmt = gimple_build_assign (gimple_call_lhs (stmt), expr); |
- copy_virtual_operands (new_stmt, stmt); |
+ new_stmt = gimple_build_assign (gimple_call_lhs (stmt), expr); |
move_ssa_defining_stmt_for_defs (new_stmt, stmt); |
gsi_replace (gsi, new_stmt, false); |
} |
@@ -513,7 +311,7 @@ stmt_may_generate_copy (gimple stmt) |
return false; |
/* Statements with loads and/or stores will never generate a useful copy. */ |
- if (!ZERO_SSA_OPERANDS (stmt, SSA_OP_ALL_VIRTUALS)) |
+ if (gimple_vuse (stmt)) |
return false; |
/* Otherwise, the only statements that generate useful copies are |
@@ -554,7 +352,7 @@ get_last_copy_of (tree var) |
/* Traverse COPY_OF starting at VAR until we get to the last |
link in the chain. Since it is possible to have cycles in PHI |
nodes, the copy-of chain may also contain cycles. |
- |
+ |
To avoid infinite loops and to avoid traversing lengthy copy-of |
chains, we artificially limit the maximum number of chains we are |
willing to traverse. |
@@ -593,7 +391,7 @@ set_copy_of_val (tree dest, tree first) |
{ |
unsigned int dest_ver = SSA_NAME_VERSION (dest); |
tree old_first, old_last, new_last; |
- |
+ |
/* Set FIRST to be the first link in COPY_OF[DEST]. If that |
changed, return true. */ |
old_first = copy_of[dest_ver].value; |
@@ -633,11 +431,11 @@ dump_copy_of (FILE *file, tree var) |
if (TREE_CODE (var) != SSA_NAME) |
return; |
- |
+ |
visited = sbitmap_alloc (num_ssa_names); |
sbitmap_zero (visited); |
SET_BIT (visited, SSA_NAME_VERSION (var)); |
- |
+ |
fprintf (file, " copy-of chain: "); |
val = var; |
@@ -661,7 +459,7 @@ dump_copy_of (FILE *file, tree var) |
fprintf (file, "[COPY]"); |
else |
fprintf (file, "[NOT A COPY]"); |
- |
+ |
sbitmap_free (visited); |
} |
@@ -680,7 +478,7 @@ copy_prop_visit_assignment (gimple stmt, tree *result_p) |
lhs = gimple_assign_lhs (stmt); |
rhs = gimple_assign_rhs1 (stmt); |
- |
+ |
gcc_assert (gimple_assign_rhs_code (stmt) == SSA_NAME); |
@@ -697,7 +495,7 @@ copy_prop_visit_assignment (gimple stmt, tree *result_p) |
copy of RHS's value, not of RHS itself. This avoids keeping |
unnecessary copy-of chains (assignments cannot be in a cycle |
like PHI nodes), speeding up the propagation process. |
- This is different from what we do in copy_prop_visit_phi_node. |
+ This is different from what we do in copy_prop_visit_phi_node. |
In those cases, we are interested in the copy-of chains. */ |
*result_p = lhs; |
if (set_copy_of_val (*result_p, rhs_val->value)) |
@@ -718,6 +516,7 @@ static enum ssa_prop_result |
copy_prop_visit_cond_stmt (gimple stmt, edge *taken_edge_p) |
{ |
enum ssa_prop_result retval = SSA_PROP_VARYING; |
+ location_t loc = gimple_location (stmt); |
tree op0 = gimple_cond_lhs (stmt); |
tree op1 = gimple_cond_rhs (stmt); |
@@ -741,7 +540,7 @@ copy_prop_visit_cond_stmt (gimple stmt, edge *taken_edge_p) |
the same SSA_NAME on both sides of a comparison operator. */ |
if (op0 == op1) |
{ |
- tree folded_cond = fold_binary (gimple_cond_code (stmt), |
+ tree folded_cond = fold_binary_loc (loc, gimple_cond_code (stmt), |
boolean_type_node, op0, op1); |
if (folded_cond) |
{ |
@@ -864,8 +663,10 @@ copy_prop_visit_phi_node (gimple phi) |
Otherwise, this may move loop variant variables outside of |
their loops and prevent coalescing opportunities. If the |
value was loop invariant, it will be hoisted by LICM and |
- exposed for copy propagation. */ |
- if (loop_depth_of_name (arg) > loop_depth_of_name (lhs)) |
+ exposed for copy propagation. Not a problem for virtual |
+ operands though. */ |
+ if (is_gimple_reg (lhs) |
+ && loop_depth_of_name (arg) > loop_depth_of_name (lhs)) |
{ |
phi_val.value = lhs; |
break; |
@@ -892,7 +693,7 @@ copy_prop_visit_phi_node (gimple phi) |
memory reference of all the other arguments. */ |
if (phi_val.value == NULL_TREE) |
{ |
- phi_val.value = arg; |
+ phi_val.value = arg_val->value ? arg_val->value : arg; |
continue; |
} |
@@ -949,6 +750,7 @@ init_copy_prop (void) |
{ |
gimple_stmt_iterator si; |
int depth = bb->loop_depth; |
+ bool loop_exit_p = false; |
for (si = gsi_start_bb (bb); !gsi_end_p (si); gsi_next (&si)) |
{ |
@@ -986,13 +788,26 @@ init_copy_prop (void) |
cached_last_copy_of[SSA_NAME_VERSION (def)] = def; |
} |
+ /* In loop-closed SSA form do not copy-propagate through |
+ PHI nodes in blocks with a loop exit edge predecessor. */ |
+ if (current_loops |
+ && loops_state_satisfies_p (LOOP_CLOSED_SSA)) |
+ { |
+ edge_iterator ei; |
+ edge e; |
+ FOR_EACH_EDGE (e, ei, bb->preds) |
+ if (loop_exit_edge_p (e->src->loop_father, e)) |
+ loop_exit_p = true; |
+ } |
+ |
for (si = gsi_start_phis (bb); !gsi_end_p (si); gsi_next (&si)) |
{ |
gimple phi = gsi_stmt (si); |
tree def; |
def = gimple_phi_result (phi); |
- if (!is_gimple_reg (def)) |
+ if (!is_gimple_reg (def) |
+ || loop_exit_p) |
prop_set_simulate_again (phi, false); |
else |
prop_set_simulate_again (phi, true); |
@@ -1014,18 +829,34 @@ fini_copy_prop (void) |
{ |
size_t i; |
prop_value_t *tmp; |
- |
+ |
/* Set the final copy-of value for each variable by traversing the |
copy-of chains. */ |
tmp = XCNEWVEC (prop_value_t, num_ssa_names); |
for (i = 1; i < num_ssa_names; i++) |
{ |
tree var = ssa_name (i); |
- if (var && copy_of[i].value && copy_of[i].value != var) |
- tmp[i].value = get_last_copy_of (var); |
+ if (!var |
+ || !copy_of[i].value |
+ || copy_of[i].value == var) |
+ continue; |
+ |
+ tmp[i].value = get_last_copy_of (var); |
+ |
+ /* In theory the points-to solution of all members of the |
+ copy chain is their intersection. For now we do not bother |
+ to compute this but only make sure we do not lose points-to |
+ information completely by setting the points-to solution |
+ of the representative to the first solution we find if |
+ it doesn't have one already. */ |
+ if (tmp[i].value != var |
+ && POINTER_TYPE_P (TREE_TYPE (var)) |
+ && SSA_NAME_PTR_INFO (var) |
+ && !SSA_NAME_PTR_INFO (tmp[i].value)) |
+ duplicate_ssa_name_ptr_info (tmp[i].value, SSA_NAME_PTR_INFO (var)); |
} |
- substitute_and_fold (tmp, false); |
+ substitute_and_fold (tmp, NULL, true); |
free (cached_last_copy_of); |
free (copy_of); |
@@ -1036,7 +867,7 @@ fini_copy_prop (void) |
/* Main entry point to the copy propagator. |
PHIS_ONLY is true if we should only consider PHI nodes as generating |
- copy propagation opportunities. |
+ copy propagation opportunities. |
The algorithm propagates the value COPY-OF using ssa_propagate. For |
every variable X_i, COPY-OF(X_i) indicates which variable is X_i created |
@@ -1059,7 +890,7 @@ fini_copy_prop (void) |
Visit #2: a_2 is copy-of x_298. Value changed. |
Visit #3: a_5 is copy-of x_298. Value changed. |
Visit #4: x_1 is copy-of x_298. Stable state reached. |
- |
+ |
When visiting PHI nodes, we only consider arguments that flow |
through edges marked executable by the propagation engine. So, |
when visiting statement #2 for the first time, we will only look at |
@@ -1096,7 +927,7 @@ fini_copy_prop (void) |
1 x_54 = PHI <x_53, x_52> |
2 x_53 = PHI <x_898, x_54> |
- |
+ |
Visit #1: x_54 is copy-of x_53 (because x_52 is copy-of x_53) |
Visit #2: x_53 is copy-of x_898 (because x_54 is a copy of x_53, |
so it is considered irrelevant |
@@ -1113,7 +944,7 @@ fini_copy_prop (void) |
same variable. So, as long as their copy-of chains overlap, we |
know that they will be a copy of the same variable, regardless of |
which variable that may be). |
- |
+ |
Propagation would then proceed as follows (the notation a -> b |
means that a is a copy-of b): |