You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING. If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA. */
+the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA. */
#include "config.h"
#include "system.h"
#include "ggc.h"
#include "basic-block.h"
#include "output.h"
-#include "errors.h"
#include "expr.h"
#include "function.h"
#include "diagnostic.h"
propagating NEW into ORIG, consolidate aliasing information so that
they both share the same memory tags. */
-static void
+void
merge_alias_info (tree orig, tree new)
{
tree new_sym = SSA_NAME_VAR (new);
#endif
/* Synchronize the type tags. If both pointers had a tag and they
- are different, then something has gone wrong. */
+ are different, then something has gone wrong. Type tags can
+ always be merged because they are flow insensitive, all the SSA
+ names of the same base DECL share the same type tag. */
if (new_ann->type_mem_tag == NULL_TREE)
new_ann->type_mem_tag = orig_ann->type_mem_tag;
else if (orig_ann->type_mem_tag == NULL_TREE)
else
gcc_assert (new_ann->type_mem_tag == orig_ann->type_mem_tag);
- /* Synchronize the name tags. If NEW did not have a name tag, get
- it from ORIG. This happens when NEW is a compiler generated
- temporary which still hasn't had its points-to information filled
- in. */
- if (SSA_NAME_PTR_INFO (orig))
+ /* 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. */
+ if (SSA_NAME_PTR_INFO (orig) && SSA_NAME_PTR_INFO (new))
{
struct ptr_info_def *orig_ptr_info = SSA_NAME_PTR_INFO (orig);
struct ptr_info_def *new_ptr_info = SSA_NAME_PTR_INFO (new);
- if (new_ptr_info == NULL)
- duplicate_ssa_name_ptr_info (new, orig_ptr_info);
- else if (orig_ptr_info->name_mem_tag
- && new_ptr_info->name_mem_tag
- && orig_ptr_info->pt_vars
- && new_ptr_info->pt_vars)
- {
- /* Note that pointer NEW may actually have a different set
- of pointed-to variables. 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. */
- gcc_assert (bitmap_intersect_p (new_ptr_info->pt_vars,
- orig_ptr_info->pt_vars));
- }
+ /* 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));
}
}
/* Propagate the value VAL (assumed to be a constant or another SSA_NAME)
- into the operand pointed by OP_P.
+ into the operand pointed to by OP_P.
Use this version for const/copy propagation as it will perform additional
checks to ensure validity of the const/copy propagation. */
/* Propagate the value VAL (assumed to be a constant or another SSA_NAME)
- into the tree pointed by OP_P.
+ into the tree pointed to by OP_P.
Use this version for const/copy propagation when SSA operands are not
available. It will perform the additional checks to ensure validity of
/* If we are not doing store copy-prop, statements with loads and/or
stores will never generate a useful copy. */
if (!do_store_copy_prop
- && (NUM_VUSES (VUSE_OPS (ann)) > 0
- || NUM_V_MAY_DEFS (V_MAY_DEF_OPS (ann)) > 0
- || NUM_V_MUST_DEFS (V_MUST_DEF_OPS (ann)) > 0))
+ && !ZERO_SSA_OPERANDS (stmt, SSA_OP_ALL_VIRTUALS))
return false;
/* Otherwise, the only statements that generate useful copies are
dump_copy_of (FILE *dump_file, tree var)
{
tree val;
+ sbitmap visited;
print_generic_expr (dump_file, var, dump_flags);
if (TREE_CODE (var) != SSA_NAME)
return;
-
+
+ visited = sbitmap_alloc (num_ssa_names);
+ sbitmap_zero (visited);
+ SET_BIT (visited, SSA_NAME_VERSION (var));
+
fprintf (dump_file, " copy-of chain: ");
val = var;
print_generic_expr (dump_file, val, 0);
fprintf (dump_file, " ");
- while (copy_of[SSA_NAME_VERSION (val)].value
- && copy_of[SSA_NAME_VERSION (val)].value != val)
+ while (copy_of[SSA_NAME_VERSION (val)].value)
{
fprintf (dump_file, "-> ");
val = copy_of[SSA_NAME_VERSION (val)].value;
print_generic_expr (dump_file, val, 0);
fprintf (dump_file, " ");
+ if (TEST_BIT (visited, SSA_NAME_VERSION (val)))
+ break;
+ SET_BIT (visited, SSA_NAME_VERSION (val));
}
val = get_copy_of_val (var)->value;
fprintf (dump_file, "[COPY]");
else
fprintf (dump_file, "[NOT A COPY]");
+
+ sbitmap_free (visited);
}
{
enum ssa_prop_result retval;
tree cond;
- use_optype uses;
cond = COND_EXPR_COND (stmt);
- uses = STMT_USE_OPS (stmt);
retval = SSA_PROP_VARYING;
/* The only conditionals that we may be able to compute statically
- are predicates involving at least one SSA_NAME. */
- if (TREE_CODE_CLASS (TREE_CODE (cond)) == tcc_comparison
- && NUM_USES (uses) >= 1)
+ are predicates involving two SSA_NAMEs. */
+ if (COMPARISON_CLASS_P (cond)
+ && TREE_CODE (TREE_OPERAND (cond, 0)) == SSA_NAME
+ && TREE_CODE (TREE_OPERAND (cond, 1)) == SSA_NAME)
{
- unsigned i;
- tree *orig;
-
- /* Save the original operands. */
- orig = xmalloc (sizeof (tree) * NUM_USES (uses));
- for (i = 0; i < NUM_USES (uses); i++)
- {
- orig[i] = USE_OP (uses, i);
- SET_USE_OP (uses, i, get_last_copy_of (USE_OP (uses, i)));
- }
+ tree op0 = get_last_copy_of (TREE_OPERAND (cond, 0));
+ tree op1 = get_last_copy_of (TREE_OPERAND (cond, 1));
/* See if we can determine the predicate's value. */
if (dump_file && (dump_flags & TDF_DETAILS))
print_generic_stmt (dump_file, cond, 0);
}
- *taken_edge_p = find_taken_edge (bb_for_stmt (stmt), cond);
- if (*taken_edge_p)
- retval = SSA_PROP_INTERESTING;
-
- /* Restore the original operands. */
- for (i = 0; i < NUM_USES (uses); i++)
- SET_USE_OP (uses, i, orig[i]);
- free (orig);
+ /* We can fold COND and get a useful result only when we have
+ the same SSA_NAME on both sides of a comparison operator. */
+ if (op0 == op1)
+ {
+ tree folded_cond = fold_binary (TREE_CODE (cond), boolean_type_node,
+ op0, op1);
+ if (folded_cond)
+ {
+ basic_block bb = bb_for_stmt (stmt);
+ *taken_edge_p = find_taken_edge (bb, folded_cond);
+ if (*taken_edge_p)
+ retval = SSA_PROP_INTERESTING;
+ }
+ }
}
if (dump_file && (dump_flags & TDF_DETAILS) && *taken_edge_p)
}
-/* Initialize structures used for copy propagation. */
+/* Initialize structures used for copy propagation. PHIS_ONLY is true
+ if we should only consider PHI nodes as generating copy propagation
+ opportunities. */
static void
-init_copy_prop (void)
+init_copy_prop (bool phis_only)
{
basic_block bb;
- copy_of = xmalloc (num_ssa_names * sizeof (*copy_of));
+ copy_of = XNEWVEC (prop_value_t, num_ssa_names);
memset (copy_of, 0, num_ssa_names * sizeof (*copy_of));
- cached_last_copy_of = xmalloc (num_ssa_names * sizeof (*cached_last_copy_of));
+ cached_last_copy_of = XNEWVEC (tree, num_ssa_names);
memset (cached_last_copy_of, 0, num_ssa_names * sizeof (*cached_last_copy_of));
FOR_EACH_BB (bb)
lists of the propagator. */
if (stmt_ends_bb_p (stmt))
DONT_SIMULATE_AGAIN (stmt) = false;
- else if (stmt_may_generate_copy (stmt))
+ else if (!phis_only && stmt_may_generate_copy (stmt))
DONT_SIMULATE_AGAIN (stmt) = false;
else
{
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 = XNEWVEC (prop_value_t, num_ssa_names);
+ memset (tmp, 0, num_ssa_names * sizeof (*tmp));
for (i = 1; i < num_ssa_names; i++)
{
tree var = ssa_name (i);
if (var && copy_of[i].value && copy_of[i].value != var)
- copy_of[i].value = get_last_copy_of (var);
+ tmp[i].value = get_last_copy_of (var);
}
- substitute_and_fold (copy_of);
+ substitute_and_fold (tmp, false);
+ free (cached_last_copy_of);
free (copy_of);
+ free (tmp);
}
-/* Main entry point to the copy propagator. 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 from. The
- following example shows how the algorithm proceeds at a high level:
+/* Main entry point to the copy propagator.
+
+ PHIS_ONLY is true if we should only consider PHI nodes as generating
+ 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
+ from. The following example shows how the algorithm proceeds at a
+ high level:
1 a_24 = x_1
2 a_2 = PHI <a_24, x_1>
x_53 and x_54 are both copies of x_898. */
static void
-execute_copy_prop (bool store_copy_prop)
+execute_copy_prop (bool store_copy_prop, bool phis_only)
{
do_store_copy_prop = store_copy_prop;
- init_copy_prop ();
+ init_copy_prop (phis_only);
ssa_propagate (copy_prop_visit_stmt, copy_prop_visit_phi_node);
fini_copy_prop ();
}
static void
do_copy_prop (void)
{
- execute_copy_prop (false);
+ execute_copy_prop (false, false);
}
struct tree_opt_pass pass_copy_prop =
};
+static void
+do_phi_only_copy_prop (void)
+{
+ execute_copy_prop (false, true);
+}
+
+struct tree_opt_pass pass_phi_only_copy_prop =
+{
+ "phionlycopyprop", /* name */
+ gate_copy_prop, /* gate */
+ do_phi_only_copy_prop, /* execute */
+ NULL, /* sub */
+ NULL, /* next */
+ 0, /* static_pass_number */
+ TV_TREE_COPY_PROP, /* tv_id */
+ PROP_ssa | PROP_alias | PROP_cfg, /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ TODO_cleanup_cfg
+ | TODO_dump_func
+ | TODO_ggc_collect
+ | TODO_verify_ssa
+ | TODO_update_ssa, /* todo_flags_finish */
+ 0 /* letter */
+};
+
+
static bool
gate_store_copy_prop (void)
{
store_copy_prop (void)
{
/* If STORE-COPY-PROP is not enabled, we just run regular COPY-PROP. */
- execute_copy_prop (flag_tree_store_copy_prop != 0);
+ execute_copy_prop (flag_tree_store_copy_prop != 0, false);
}
struct tree_opt_pass pass_store_copy_prop =