GCC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
+the Free Software Foundation; either version 3, or (at your option)
any later version.
GCC is distributed in the hope that it will be useful,
GNU General Public License for more details.
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, 51 Franklin Street, Fifth Floor,
-Boston, MA 02110-1301, USA. */
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
#include "config.h"
#include "system.h"
#include "langhooks.h"
#include "cfgloop.h"
#include "tree-ssa-sccvn.h"
+#include "params.h"
/* TODO:
Fourth, we eliminate fully redundant expressions.
This is a simple statement walk that replaces redundant
- calculations with the now available values. */
+ calculations with the now available values. */
/* Representations of value numbers:
/* Next global expression id number. */
static unsigned int next_expression_id;
+typedef VEC(tree, gc) *vuse_vec;
+DEF_VEC_P (vuse_vec);
+DEF_VEC_ALLOC_P (vuse_vec, heap);
+
+static VEC(vuse_vec, heap) *expression_vuses;
+
/* Mapping from expression to id number we can use in bitmap sets. */
static VEC(tree, heap) *expressions;
ann->aux = XNEW (unsigned int);
* ((unsigned int *)ann->aux) = next_expression_id++;
VEC_safe_push (tree, heap, expressions, expr);
+ VEC_safe_push (vuse_vec, heap, expression_vuses, NULL);
return next_expression_id - 1;
}
return VEC_index (tree, expressions, id);
}
+/* Return the expression vuses for EXPR, if there are any. */
+
+static inline vuse_vec
+get_expression_vuses (tree expr)
+{
+ unsigned int expr_id = get_or_alloc_expression_id (expr);
+ return VEC_index (vuse_vec, expression_vuses, expr_id);
+}
+
+/* Set the expression vuses for EXPR to VUSES. */
+
+static inline void
+set_expression_vuses (tree expr, vuse_vec vuses)
+{
+ unsigned int expr_id = get_or_alloc_expression_id (expr);
+ VEC_replace (vuse_vec, expression_vuses, expr_id, vuses);
+}
+
+
/* Free the expression id field in all of our expressions,
and then destroy the expressions array. */
tree_common_ann (expr)->aux = NULL;
}
VEC_free (tree, heap, expressions);
+ VEC_free (vuse_vec, heap, expression_vuses);
}
static bool in_fre = false;
the current iteration. */
bitmap_set_t new_sets;
- /* These are the loads that will be ANTIC_IN at the top of the
- block, and are actually generated in the block. */
- bitmap_set_t antic_safe_loads;
-
/* True if we have visited this block during ANTIC calculation. */
unsigned int visited:1;
#define ANTIC_IN(BB) ((bb_value_sets_t) ((BB)->aux))->antic_in
#define PA_IN(BB) ((bb_value_sets_t) ((BB)->aux))->pa_in
#define NEW_SETS(BB) ((bb_value_sets_t) ((BB)->aux))->new_sets
-#define ANTIC_SAFE_LOADS(BB) ((bb_value_sets_t) ((BB)->aux))->antic_safe_loads
#define BB_VISITED(BB) ((bb_value_sets_t) ((BB)->aux))->visited
#define BB_DEFERRED(BB) ((bb_value_sets_t) ((BB)->aux))->deferred
static bool bitmap_set_contains_value (bitmap_set_t, tree);
static void bitmap_insert_into_set (bitmap_set_t, tree);
static bitmap_set_t bitmap_set_new (void);
-static bool is_undefined_value (tree);
static tree create_expression_by_pieces (basic_block, tree, tree);
static tree find_or_generate_expression (basic_block, tree, tree);
speed reasons. */
hashval_t hashcode;
} *expr_pred_trans_t;
+typedef const struct expr_pred_trans_d *const_expr_pred_trans_t;
/* Return the hash value for a phi translation table entry. */
static hashval_t
expr_pred_trans_hash (const void *p)
{
- const expr_pred_trans_t ve = (expr_pred_trans_t) p;
+ const_expr_pred_trans_t const ve = (const_expr_pred_trans_t) p;
return ve->hashcode;
}
static int
expr_pred_trans_eq (const void *p1, const void *p2)
{
- const expr_pred_trans_t ve1 = (expr_pred_trans_t) p1;
- const expr_pred_trans_t ve2 = (expr_pred_trans_t) p2;
+ const_expr_pred_trans_t const ve1 = (const_expr_pred_trans_t) p1;
+ const_expr_pred_trans_t const ve2 = (const_expr_pred_trans_t) p2;
basic_block b1 = ve1->pred;
basic_block b2 = ve2->pred;
int i;
static inline bool
constant_expr_p (tree v)
{
- return TREE_CODE (v) != VALUE_HANDLE &&
+ return TREE_CODE (v) != VALUE_HANDLE &&
(TREE_CODE (v) == FIELD_DECL || is_gimple_min_invariant (v));
}
the phis in PRED. SEEN is a bitmap saying which expression we have
translated since we started translation of the toplevel expression.
Return NULL if we can't find a leader for each part of the
- translated expression. */
+ translated expression. */
static tree
phi_translate_1 (tree expr, bitmap_set_t set1, bitmap_set_t set2,
/* Phi translations of a given expression don't change. */
if (EXPR_P (expr) || GIMPLE_STMT_P (expr))
{
- tree vh;
-
- vh = get_value_handle (expr);
- if (vh && TREE_CODE (vh) == VALUE_HANDLE)
- phitrans = phi_trans_lookup (expr, pred, VALUE_HANDLE_VUSES (vh));
- else
- phitrans = phi_trans_lookup (expr, pred, NULL);
+ phitrans = phi_trans_lookup (expr, pred, get_expression_vuses (expr));
}
else
phitrans = phi_trans_lookup (expr, pred, NULL);
tree oldsc = CALL_EXPR_STATIC_CHAIN (expr);
tree newfn, newsc = NULL;
tree newexpr = NULL_TREE;
- tree vh = get_value_handle (expr);
bool invariantarg = false;
int i, nargs;
- VEC (tree, gc) *vuses = VALUE_HANDLE_VUSES (vh);
+ VEC (tree, gc) *vuses = get_expression_vuses (expr);
VEC (tree, gc) *tvuses;
newfn = phi_translate_1 (find_leader_in_sets (oldfn, set1, set2),
newexpr->base.ann = NULL;
vn_lookup_or_add_with_vuses (newexpr, tvuses);
expr = newexpr;
+ set_expression_vuses (newexpr, tvuses);
}
phi_trans_add (oldexpr, expr, pred, tvuses);
}
VEC (tree, gc) * oldvuses = NULL;
VEC (tree, gc) * newvuses = NULL;
- oldvuses = VALUE_HANDLE_VUSES (get_value_handle (expr));
+ oldvuses = get_expression_vuses (expr);
if (oldvuses)
newvuses = translate_vuses_through_block (oldvuses, phiblock,
pred);
if (oldvuses != newvuses)
- vn_lookup_or_add_with_vuses (expr, newvuses);
-
+ {
+ vn_lookup_or_add_with_vuses (expr, newvuses);
+ set_expression_vuses (expr, newvuses);
+ }
phi_trans_add (oldexpr, expr, pred, newvuses);
}
return expr;
}
}
- oldvuses = VALUE_HANDLE_VUSES (get_value_handle (expr));
+ oldvuses = get_expression_vuses (expr);
if (oldvuses)
newvuses = translate_vuses_through_block (oldvuses, phiblock,
pred);
{
newexpr->base.ann = NULL;
vn_lookup_or_add_with_vuses (newexpr, newvuses);
+ set_expression_vuses (newexpr, newvuses);
}
expr = newexpr;
}
{
tree val;
tree def = PHI_ARG_DEF (phi, e->dest_idx);
-
+
if (is_gimple_min_invariant (def))
return def;
-
- if (is_undefined_value (def))
+
+ if (TREE_CODE (def) == SSA_NAME && ssa_undefined_value_p (def))
return NULL;
-
+
val = get_value_handle (def);
gcc_assert (val);
return def;
}
/* Translate EXPR using phis in PHIBLOCK, so that it has the values of
- the phis in PRED.
+ the phis in PRED.
Return NULL if we can't find a leader for each part of the
- translated expression. */
+ translated expression. */
static tree
phi_translate (tree expr, bitmap_set_t set1, bitmap_set_t set2,
we won't look them up that way, or use the result, anyway. */
if (translated && !is_gimple_min_invariant (translated))
{
- tree vh = get_value_handle (translated);
- VEC (tree, gc) *vuses;
-
- /* The value handle itself may also be an invariant, in
- which case, it has no vuses. */
- vuses = !is_gimple_min_invariant (vh)
- ? VALUE_HANDLE_VUSES (vh) : NULL;
- phi_trans_add (expr, translated, pred, vuses);
+ phi_trans_add (expr, translated, pred,
+ get_expression_vuses (translated));
}
if (translated != NULL)
return NULL;
}
-/* Determine if VALUE, a memory operation, is ANTIC_IN at the top of
+/* Determine if EXPR, a memory expression, is ANTIC_IN at the top of
BLOCK by seeing if it is not killed in the block. Note that we are
only determining whether there is a store that kills it. Because
of the order in which clean iterates over values, we are guaranteed
ANTIC_IN set already. */
static bool
-value_dies_in_block_x (tree vh, basic_block block)
+value_dies_in_block_x (tree expr, basic_block block)
{
int i;
tree vuse;
- VEC (tree, gc) *vuses = VALUE_HANDLE_VUSES (vh);
+ VEC (tree, gc) *vuses = get_expression_vuses (expr);
/* Conservatively, a value dies if it's vuses are defined in this
block, unless they come from phi nodes (which are merge operations,
valid_in_sets (bitmap_set_t set1, bitmap_set_t set2, tree expr,
basic_block block)
{
- tree vh = get_value_handle (expr);
switch (TREE_CODE_CLASS (TREE_CODE (expr)))
{
case tcc_binary:
if (!union_contains_value (set1, set2, arg))
return false;
}
- return !value_dies_in_block_x (vh, block);
+ return !value_dies_in_block_x (expr, block);
}
return false;
}
&& !union_contains_value (set1, set2, op3))
return false;
}
- return bitmap_set_contains_value (ANTIC_SAFE_LOADS (block),
- vh)
- || !value_dies_in_block_x (vh, block);
+ return !value_dies_in_block_x (expr, block);
}
}
return false;
}
case tcc_declaration:
- return !value_dies_in_block_x (vh, block);
+ return !value_dies_in_block_x (expr, block);
default:
/* No other cases should be encountered. */
if (ANTIC_OUT)
print_bitmap_set (dump_file, ANTIC_OUT, "ANTIC_OUT", block->index);
- if (ANTIC_SAFE_LOADS (block))
- print_bitmap_set (dump_file, ANTIC_SAFE_LOADS (block),
- "ANTIC_SAFE_LOADS", block->index);
print_bitmap_set (dump_file, ANTIC_IN (block), "ANTIC_IN",
block->index);
bitmap_set_t PA_OUT;
edge e;
edge_iterator ei;
+ unsigned long max_pa = PARAM_VALUE (PARAM_MAX_PARTIAL_ANTIC_LENGTH);
old_PA_IN = PA_OUT = NULL;
if (block_has_abnormal_pred_edge)
goto maybe_dump_sets;
+ /* If there are too many partially anticipatable values in the
+ block, phi_translate_set can take an exponential time: stop
+ before the translation starts. */
+ if (max_pa
+ && single_succ_p (block)
+ && bitmap_count_bits (PA_IN (single_succ (block))->values) > max_pa)
+ goto maybe_dump_sets;
+
old_PA_IN = PA_IN (block);
PA_OUT = bitmap_set_new ();
sbitmap_free (changed_blocks);
}
-/*
- ANTIC_SAFE_LOADS are those loads generated in a block that actually
- occur before any kill to their vuses in the block, and thus, are
- safe at the top of the block. This function computes the set by
- walking the EXP_GEN set for the block, and checking the VUSES.
-
- This set could be computed as ANTIC calculation is proceeding, but
- but because it does not actually change during that computation, it is
- quicker to pre-calculate the results and use them than to do it on
- the fly (particularly in the presence of multiple iteration). */
-
-static void
-compute_antic_safe (void)
-{
- basic_block bb;
- bitmap_iterator bi;
- unsigned int i;
-
- FOR_EACH_BB (bb)
- {
- FOR_EACH_EXPR_ID_IN_SET (EXP_GEN (bb), i, bi)
- {
- tree expr = expression_for_id (i);
- if (REFERENCE_CLASS_P (expr))
- {
- tree vh = get_value_handle (expr);
- tree maybe = bitmap_find_leader (AVAIL_OUT (bb), vh);
- ssa_op_iter i;
- tree vuse;
- tree stmt;
- bool okay = true;
-
- if (!maybe)
- continue;
- stmt = SSA_NAME_DEF_STMT (maybe);
- if (TREE_CODE (stmt) == PHI_NODE)
- continue;
-
- FOR_EACH_SSA_TREE_OPERAND (vuse, stmt, i,
- SSA_OP_VIRTUAL_USES)
- {
- tree def = SSA_NAME_DEF_STMT (vuse);
-
- if (bb_for_stmt (def) != bb)
- continue;
-
- /* See if the vuse is defined by a statement that
- comes before us in the block. Phi nodes are not
- stores, so they do not count. */
- if (TREE_CODE (def) != PHI_NODE
- && stmt_ann (def)->uid < stmt_ann (stmt)->uid)
- {
- okay = false;
- break;
- }
- }
- if (okay)
- {
- if (ANTIC_SAFE_LOADS (bb) == NULL)
- ANTIC_SAFE_LOADS (bb) = bitmap_set_new ();
- bitmap_value_insert_into_set (ANTIC_SAFE_LOADS (bb),
- expr);
- }
- }
- }
- }
-}
-
/* Return true if we can value number the call in STMT. This is true
if we have a pure or constant call. */
}
/* Return true if OP is an exception handler related operation, such as
- FILTER_EXPRor EXC_PTR_EXPR. */
+ FILTER_EXPR or EXC_PTR_EXPR. */
static bool
is_exception_related (tree op)
static bool
can_value_number_operation (tree op)
{
- return (UNARY_CLASS_P (op)
+ return (UNARY_CLASS_P (op)
&& !is_exception_related (TREE_OPERAND (op, 0)))
|| BINARY_CLASS_P (op)
|| COMPARISON_CLASS_P (op)
NECESSARY (temp) = 0;
VN_INFO_GET (PHI_RESULT (temp))->valnum = PHI_RESULT (temp);
-
+
VEC_safe_push (tree, heap, inserted_exprs, temp);
FOR_EACH_EDGE (pred, ei, block->preds)
add_phi_arg (temp, avail[pred->src->index], pred);
}
-/* Return true if VAR is an SSA variable with no defining statement in
- this procedure, *AND* isn't a live-on-entry parameter. */
-
-static bool
-is_undefined_value (tree expr)
-{
- return (TREE_CODE (expr) == SSA_NAME
- && IS_EMPTY_STMT (SSA_NAME_DEF_STMT (expr))
- /* PARM_DECLs and hard registers are always defined. */
- && TREE_CODE (SSA_NAME_VAR (expr)) != PARM_DECL);
-}
-
/* Add OP to EXP_GEN (block), and possibly to the maximal set if it is
- not defined by a phi node.
+ not defined by a phi node.
PHI nodes can't go in the maximal sets because they are not in
TMP_GEN, so it is possible to get into non-monotonic situations
during ANTIC calculation, because it will *add* bits. */
{
if (!in_fre)
{
- if (TREE_CODE (op) == SSA_NAME && is_undefined_value (op))
+ if (TREE_CODE (op) == SSA_NAME && ssa_undefined_value_p (op))
return;
bitmap_value_insert_into_set (EXP_GEN (block), op);
if (TREE_CODE (op) != SSA_NAME
any). */
static inline void
-add_to_sets (tree var, tree expr, tree stmt, bitmap_set_t s1,
+add_to_sets (tree var, tree expr, VEC(tree, gc) *vuses, bitmap_set_t s1,
bitmap_set_t s2)
{
tree val;
- val = vn_lookup_or_add_with_stmt (expr, stmt);
+ val = vn_lookup_or_add_with_vuses (expr, vuses);
/* VAR and EXPR may be the same when processing statements for which
we are not computing value numbers (e.g., non-assignments, or
and return it if it exists. */
static inline tree
-find_existing_value_expr (tree t, tree stmt)
+find_existing_value_expr (tree t, VEC (tree, gc) *vuses)
{
bitmap_iterator bi;
unsigned int bii;
bitmap_set_t exprset;
if (REFERENCE_CLASS_P (t) || TREE_CODE (t) == CALL_EXPR || DECL_P (t))
- vh = vn_lookup_with_stmt (t, stmt);
+ vh = vn_lookup_with_vuses (t, vuses);
else
vh = vn_lookup (t);
-
+
if (!vh)
return NULL;
exprset = VALUE_HANDLE_EXPR_SET (vh);
any). Insert EXPR's operands into the EXP_GEN set for BLOCK. */
static inline tree
-create_value_expr_from (tree expr, basic_block block, tree stmt)
+create_value_expr_from (tree expr, basic_block block, VEC (tree, gc) *vuses)
{
int i;
enum tree_code code = TREE_CODE (expr);
/* Recursively value-numberize reference ops and tree lists. */
if (REFERENCE_CLASS_P (op))
{
- tree tempop = create_value_expr_from (op, block, stmt);
+ tree tempop = create_value_expr_from (op, block, vuses);
op = tempop ? tempop : op;
- val = vn_lookup_or_add_with_stmt (op, stmt);
+ val = vn_lookup_or_add_with_vuses (op, vuses);
+ set_expression_vuses (op, vuses);
}
else
{
}
if (TREE_CODE (op) != TREE_LIST)
add_to_exp_gen (block, op);
-
+
if (TREE_CODE (val) == VALUE_HANDLE)
TREE_TYPE (val) = TREE_TYPE (TREE_OPERAND (vexpr, i));
TREE_OPERAND (vexpr, i) = val;
}
- efi = find_existing_value_expr (vexpr, stmt);
+ efi = find_existing_value_expr (vexpr, vuses);
if (efi)
return efi;
get_or_alloc_expression_id (vexpr);
case INTEGER_CST:
case STRING_CST:
case REAL_CST:
+ case FIXED_CST:
case PARM_DECL:
case VAR_DECL:
case RESULT_DECL:
lhs = make_ssa_name (storetemp, new_tree);
GIMPLE_STMT_OPERAND (new_tree, 0) = lhs;
- create_ssa_artificial_load_stmt (new_tree, stmt);
+ create_ssa_artificial_load_stmt (new_tree, stmt, false);
NECESSARY (new_tree) = 0;
VEC_safe_push (tree, heap, inserted_exprs, new_tree);
if (!valvh && !is_invariant)
{
tree defstmt = SSA_NAME_DEF_STMT (val);
-
+
gcc_assert (VN_INFO (val)->valnum == val);
/* PHI nodes can't have vuses and attempts to iterate over
their VUSE operands will crash. */
}
valvh = vn_lookup_or_add_with_stmt (val, defstmt);
}
-
+
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "SCCVN says ");
fprintf (dump_file, ")\n");
}
else
- print_generic_stmt (dump_file, val, 0);
+ print_generic_stmt (dump_file, val, 0);
}
if (valvh)
return valvh;
}
}
-
/* Create value handles for STMT in BLOCK. Return true if we handled
the statement. */
tree rhs = GIMPLE_STMT_OPERAND (stmt, 1);
tree valvh = NULL_TREE;
tree lhsval;
-
+ VEC (tree, gc) *vuses = NULL;
+
valvh = get_sccvn_value (lhs);
+
if (valvh)
{
vn_add (lhs, valvh);
- bitmap_value_insert_into_set (AVAIL_OUT (block), lhs);
+ bitmap_value_insert_into_set (AVAIL_OUT (block), lhs);
/* Shortcut for FRE. We have no need to create value expressions,
just want to know what values are available where. */
if (in_fre)
bitmap_value_insert_into_set (AVAIL_OUT (block), lhs);
return true;
}
-
+
lhsval = valvh ? valvh : get_value_handle (lhs);
-
+ vuses = copy_vuses_from_stmt (stmt);
STRIP_USELESS_TYPE_CONVERSION (rhs);
if (can_value_number_operation (rhs)
&& (!lhsval || !is_gimple_min_invariant (lhsval)))
/* For value numberable operation, create a
duplicate expression with the operands replaced
with the value handles of the original RHS. */
- tree newt = create_value_expr_from (rhs, block, stmt);
+ tree newt = create_value_expr_from (rhs, block, vuses);
if (newt)
{
+ set_expression_vuses (newt, vuses);
/* If we already have a value number for the LHS, reuse
it rather than creating a new one. */
if (lhsval)
}
else
{
- tree val = vn_lookup_or_add_with_stmt (newt, stmt);
+ tree val = vn_lookup_or_add_with_vuses (newt, vuses);
vn_add (lhs, val);
}
-
+
add_to_exp_gen (block, newt);
- }
-
+ }
+
bitmap_insert_into_set (TMP_GEN (block), lhs);
bitmap_value_insert_into_set (AVAIL_OUT (block), lhs);
return true;
|| TREE_INVARIANT (rhs)
|| DECL_P (rhs))
{
-
+
if (lhsval)
{
+ set_expression_vuses (rhs, vuses);
set_value_handle (rhs, lhsval);
if (!is_gimple_min_invariant (lhsval))
add_to_value (lhsval, rhs);
/* Compute a value number for the RHS of the statement
and add its value to the AVAIL_OUT set for the block.
Add the LHS to TMP_GEN. */
- add_to_sets (lhs, rhs, stmt, TMP_GEN (block),
+ set_expression_vuses (rhs, vuses);
+ add_to_sets (lhs, rhs, vuses, TMP_GEN (block),
AVAIL_OUT (block));
}
/* None of the rest of these can be PRE'd. */
- if (TREE_CODE (rhs) == SSA_NAME && !is_undefined_value (rhs))
+ if (TREE_CODE (rhs) == SSA_NAME && !ssa_undefined_value_p (rhs))
add_to_exp_gen (block, rhs);
return true;
}
tree def = gimple_default_def (cfun, param);
vn_lookup_or_add (def);
- if (!in_fre)
+ if (!in_fre)
{
bitmap_insert_into_set (TMP_GEN (ENTRY_BLOCK_PTR), def);
bitmap_value_insert_into_set (maximal_set, def);
}
else if (TREE_CODE (stmt) == GIMPLE_MODIFY_STMT
- && !ann->has_volatile_ops
- && TREE_CODE (GIMPLE_STMT_OPERAND (stmt, 0)) == SSA_NAME
- && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI
- (GIMPLE_STMT_OPERAND (stmt, 0)))
+ && !ann->has_volatile_ops
+ && TREE_CODE (GIMPLE_STMT_OPERAND (stmt, 0)) == SSA_NAME
+ && (!SSA_NAME_OCCURS_IN_ABNORMAL_PHI
+ (GIMPLE_STMT_OPERAND (stmt, 0)))
+ && !tree_could_throw_p (stmt))
{
if (make_values_for_stmt (stmt, block))
continue;
sprime = bitmap_find_leader (AVAIL_OUT (b),
get_value_handle (lhs));
-
+
if (sprime
&& sprime != lhs
&& (TREE_CODE (*rhs_p) != SSA_NAME
init_pre (bool do_fre)
{
basic_block bb;
-
+
next_expression_id = 0;
expressions = NULL;
+ expression_vuses = NULL;
in_fre = do_fre;
inserted_exprs = NULL;
insert_fake_stores ();
/* Collect and value number expressions computed in each basic block. */
- run_scc_vn ();
+ if (!run_scc_vn ())
+ {
+ if (!do_fre)
+ remove_dead_inserted_code ();
+ fini_pre ();
+ return;
+ }
switch_to_PRE_table ();
compute_avail ();
computing ANTIC, either, even though it's plenty fast. */
if (!do_fre && n_basic_blocks < 4000)
{
- compute_antic_safe ();
compute_antic ();
insert ();
}
do_pre (void)
{
execute_pre (false);
- return 0;
+ return TODO_rebuild_alias;
}
static bool