/* SSA-PRE for trees.
- Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
- Free Software Foundation, Inc.
+ Copyright (C) 2001-2015 Free Software Foundation, Inc.
Contributed by Daniel Berlin <dan@dberlin.org> and Steven Bosscher
<stevenb@suse.de>
#include "system.h"
#include "coretypes.h"
#include "tm.h"
+#include "alias.h"
+#include "symtab.h"
#include "tree.h"
+#include "fold-const.h"
+#include "predict.h"
+#include "hard-reg-set.h"
+#include "function.h"
+#include "dominance.h"
+#include "cfg.h"
+#include "cfganal.h"
#include "basic-block.h"
#include "gimple-pretty-print.h"
#include "tree-inline.h"
-#include "tree-flow.h"
+#include "tree-ssa-alias.h"
+#include "internal-fn.h"
+#include "gimple-fold.h"
+#include "tree-eh.h"
+#include "gimple-expr.h"
#include "gimple.h"
-#include "hash-table.h"
+#include "gimplify.h"
+#include "gimple-iterator.h"
+#include "gimplify-me.h"
+#include "gimple-ssa.h"
+#include "tree-cfg.h"
+#include "tree-phinodes.h"
+#include "ssa-iterators.h"
+#include "stringpool.h"
+#include "tree-ssanames.h"
+#include "tree-ssa-loop.h"
+#include "tree-into-ssa.h"
+#include "rtl.h"
+#include "flags.h"
+#include "insn-config.h"
+#include "expmed.h"
+#include "dojump.h"
+#include "explow.h"
+#include "calls.h"
+#include "emit-rtl.h"
+#include "varasm.h"
+#include "stmt.h"
+#include "expr.h"
+#include "tree-dfa.h"
+#include "tree-ssa.h"
#include "tree-iterator.h"
#include "alloc-pool.h"
#include "obstack.h"
#include "tree-pass.h"
-#include "flags.h"
-#include "bitmap.h"
#include "langhooks.h"
#include "cfgloop.h"
#include "tree-ssa-sccvn.h"
#include "params.h"
#include "dbgcnt.h"
#include "domwalk.h"
+#include "cgraph.h"
+#include "symbol-summary.h"
+#include "ipa-prop.h"
+#include "tree-ssa-propagate.h"
+#include "ipa-utils.h"
+#include "tree-cfgcleanup.h"
/* TODO:
vn_reference_t reference;
} pre_expr_union;
-typedef struct pre_expr_d : typed_noop_remove <pre_expr_d>
+typedef struct pre_expr_d : nofree_ptr_hash <pre_expr_d>
{
enum pre_expr_kind kind;
unsigned int id;
pre_expr_union u;
/* hash_table support. */
- typedef pre_expr_d value_type;
- typedef pre_expr_d compare_type;
static inline hashval_t hash (const pre_expr_d *);
static inline int equal (const pre_expr_d *, const pre_expr_d *);
} *pre_expr;
/* Compare E1 and E1 for equality. */
inline int
-pre_expr_d::equal (const value_type *e1, const compare_type *e2)
+pre_expr_d::equal (const pre_expr_d *e1, const pre_expr_d *e2)
{
if (e1->kind != e2->kind)
return false;
/* Hash E. */
inline hashval_t
-pre_expr_d::hash (const value_type *e)
+pre_expr_d::hash (const pre_expr_d *e)
{
switch (e->kind)
{
/* Mapping from expression to id number we can use in bitmap sets. */
static vec<pre_expr> expressions;
-static hash_table <pre_expr_d> expression_to_id;
+static hash_table<pre_expr_d> *expression_to_id;
static vec<unsigned> name_to_id;
/* Allocate an expression id for EXPR. */
{
unsigned version = SSA_NAME_VERSION (PRE_EXPR_NAME (expr));
/* vec::safe_grow_cleared allocates no headroom. Avoid frequent
- re-allocations by using vec::reserve upfront. There is no
- vec::quick_grow_cleared unfortunately. */
+ re-allocations by using vec::reserve upfront. */
unsigned old_len = name_to_id.length ();
name_to_id.reserve (num_ssa_names - old_len);
- name_to_id.safe_grow_cleared (num_ssa_names);
+ name_to_id.quick_grow_cleared (num_ssa_names);
gcc_assert (name_to_id[version] == 0);
name_to_id[version] = expr->id;
}
else
{
- slot = expression_to_id.find_slot (expr, INSERT);
+ slot = expression_to_id->find_slot (expr, INSERT);
gcc_assert (!*slot);
*slot = expr;
}
}
else
{
- slot = expression_to_id.find_slot (expr, NO_INSERT);
+ slot = expression_to_id->find_slot (expr, NO_INSERT);
if (!slot)
return 0;
return ((pre_expr)*slot)->id;
expressions.release ();
}
-static alloc_pool pre_expr_pool;
+static pool_allocator<pre_expr_d> pre_expr_pool ("pre_expr nodes", 30);
/* Given an SSA_NAME NAME, get or create a pre_expr to represent it. */
if (result_id != 0)
return expression_for_id (result_id);
- result = (pre_expr) pool_alloc (pre_expr_pool);
+ result = pre_expr_pool.allocate ();
result->kind = NAME;
PRE_EXPR_NAME (result) = name;
alloc_expression_id (result);
} *bitmap_set_t;
#define FOR_EACH_EXPR_ID_IN_SET(set, id, bi) \
- EXECUTE_IF_SET_IN_BITMAP(&(set)->expressions, 0, (id), (bi))
+ EXECUTE_IF_SET_IN_BITMAP (&(set)->expressions, 0, (id), (bi))
#define FOR_EACH_VALUE_ID_IN_SET(set, id, bi) \
- EXECUTE_IF_SET_IN_BITMAP(&(set)->values, 0, (id), (bi))
+ EXECUTE_IF_SET_IN_BITMAP (&(set)->values, 0, (id), (bi))
/* Mapping from value id to expressions with that value_id. */
static vec<bitmap> value_expressions;
/* A cache for value_dies_in_block_x. */
bitmap expr_dies;
+ /* The live virtual operand on successor edges. */
+ tree vop_on_exit;
+
/* True if we have visited this block during ANTIC calculation. */
unsigned int visited : 1;
- /* True we have deferred processing this block during ANTIC
- calculation until its successor is processed. */
- unsigned int deferred : 1;
-
/* True when the block contains a call that might not return. */
unsigned int contains_may_not_return_call : 1;
} *bb_value_sets_t;
#define NEW_SETS(BB) ((bb_value_sets_t) ((BB)->aux))->new_sets
#define EXPR_DIES(BB) ((bb_value_sets_t) ((BB)->aux))->expr_dies
#define BB_VISITED(BB) ((bb_value_sets_t) ((BB)->aux))->visited
-#define BB_DEFERRED(BB) ((bb_value_sets_t) ((BB)->aux))->deferred
#define BB_MAY_NOTRETURN(BB) ((bb_value_sets_t) ((BB)->aux))->contains_may_not_return_call
+#define BB_LIVE_VOP_ON_EXIT(BB) ((bb_value_sets_t) ((BB)->aux))->vop_on_exit
/* Basic block list in postorder. */
/* The number of new PHI nodes added by PRE. */
int phis;
-
- /* The number of values found constant. */
- int constified;
-
} pre_stats;
static bool do_partial_partial;
/* We can add and remove elements and entries to and from sets
and hash tables, so we use alloc pools for them. */
-static alloc_pool bitmap_set_pool;
+static pool_allocator<bitmap_set> bitmap_set_pool ("Bitmap sets", 30);
static bitmap_obstack grand_bitmap_obstack;
/* Set of blocks with statements that have had their EH properties changed. */
/* A three tuple {e, pred, v} used to cache phi translations in the
phi_translate_table. */
-typedef struct expr_pred_trans_d : typed_free_remove<expr_pred_trans_d>
+typedef struct expr_pred_trans_d : free_ptr_hash<expr_pred_trans_d>
{
/* The expression. */
pre_expr e;
hashval_t hashcode;
/* hash_table support. */
- typedef expr_pred_trans_d value_type;
- typedef expr_pred_trans_d compare_type;
- static inline hashval_t hash (const value_type *);
- static inline int equal (const value_type *, const compare_type *);
+ static inline hashval_t hash (const expr_pred_trans_d *);
+ static inline int equal (const expr_pred_trans_d *, const expr_pred_trans_d *);
} *expr_pred_trans_t;
typedef const struct expr_pred_trans_d *const_expr_pred_trans_t;
}
inline int
-expr_pred_trans_d::equal (const value_type *ve1,
- const compare_type *ve2)
+expr_pred_trans_d::equal (const expr_pred_trans_d *ve1,
+ const expr_pred_trans_d *ve2)
{
basic_block b1 = ve1->pred;
basic_block b2 = ve2->pred;
/* The phi_translate_table caches phi translations for a given
expression and predecessor. */
-static hash_table <expr_pred_trans_d> phi_translate_table;
-
-/* Search in the phi translation table for the translation of
- expression E in basic block PRED.
- Return the translated value, if found, NULL otherwise. */
-
-static inline pre_expr
-phi_trans_lookup (pre_expr e, basic_block pred)
-{
- expr_pred_trans_t *slot;
- struct expr_pred_trans_d ept;
-
- ept.e = e;
- ept.pred = pred;
- ept.hashcode = iterative_hash_hashval_t (pre_expr_d::hash (e), pred->index);
- slot = phi_translate_table.find_slot_with_hash (&ept, ept.hashcode,
- NO_INSERT);
- if (!slot)
- return NULL;
- else
- return (*slot)->v;
-}
-
+static hash_table<expr_pred_trans_d> *phi_translate_table;
/* Add the tuple mapping from {expression E, basic block PRED} to
- value V, to the phi translation table. */
+ the phi translation table and return whether it pre-existed. */
-static inline void
-phi_trans_add (pre_expr e, pre_expr v, basic_block pred)
+static inline bool
+phi_trans_add (expr_pred_trans_t *entry, pre_expr e, basic_block pred)
{
expr_pred_trans_t *slot;
- expr_pred_trans_t new_pair = XNEW (struct expr_pred_trans_d);
- new_pair->e = e;
- new_pair->pred = pred;
- new_pair->v = v;
- new_pair->hashcode = iterative_hash_hashval_t (pre_expr_d::hash (e),
- pred->index);
-
- slot = phi_translate_table.find_slot_with_hash (new_pair,
- new_pair->hashcode, INSERT);
- free (*slot);
- *slot = new_pair;
+ expr_pred_trans_d tem;
+ hashval_t hash = iterative_hash_hashval_t (pre_expr_d::hash (e),
+ pred->index);
+ tem.e = e;
+ tem.pred = pred;
+ tem.hashcode = hash;
+ slot = phi_translate_table->find_slot_with_hash (&tem, hash, INSERT);
+ if (*slot)
+ {
+ *entry = *slot;
+ return true;
+ }
+
+ *entry = *slot = XNEW (struct expr_pred_trans_d);
+ (*entry)->e = e;
+ (*entry)->pred = pred;
+ (*entry)->hashcode = hash;
+ return false;
}
static bitmap_set_t
bitmap_set_new (void)
{
- bitmap_set_t ret = (bitmap_set_t) pool_alloc (bitmap_set_pool);
+ bitmap_set_t ret = bitmap_set_pool.allocate ();
bitmap_initialize (&ret->expressions, &grand_bitmap_obstack);
bitmap_initialize (&ret->values, &grand_bitmap_obstack);
return ret;
bitmap_iterator bi, bj;
vec<pre_expr> result;
- /* Pre-allocate roughly enough space for the array. */
- result.create (bitmap_count_bits (&set->values));
+ /* Pre-allocate enough space for the array. */
+ result.create (bitmap_count_bits (&set->expressions));
FOR_EACH_VALUE_ID_IN_SET (set, i, bi)
{
EXECUTE_IF_SET_IN_BITMAP (exprset, 0, j, bj)
{
if (bitmap_bit_p (&set->expressions, j))
- result.safe_push (expression_for_id (j));
+ result.quick_push (expression_for_id (j));
}
}
return;
}
}
+
+ gcc_unreachable ();
}
/* Return true if two bitmap sets are equal. */
{
unsigned int i;
vn_nary_op_t nary = PRE_EXPR_NARY (expr);
- fprintf (outfile, "{%s,", tree_code_name [nary->opcode]);
+ fprintf (outfile, "{%s,", get_tree_code_name (nary->opcode));
for (i = 0; i < nary->length; i++)
{
print_generic_expr (outfile, nary->op[i], 0);
if (vro->opcode != SSA_NAME
&& TREE_CODE_CLASS (vro->opcode) != tcc_declaration)
{
- fprintf (outfile, "%s", tree_code_name [vro->opcode]);
+ fprintf (outfile, "%s", get_tree_code_name (vro->opcode));
if (vro->op0)
{
fprintf (outfile, "<");
if (result_id != 0)
return expression_for_id (result_id);
- newexpr = (pre_expr) pool_alloc (pre_expr_pool);
+ newexpr = pre_expr_pool.allocate ();
newexpr->kind = CONSTANT;
PRE_EXPR_CONSTANT (newexpr) = constant;
alloc_expression_id (newexpr);
vn_nary_op_lookup (t, &result);
if (result != NULL)
{
- pre_expr e = (pre_expr) pool_alloc (pre_expr_pool);
+ pre_expr e = pre_expr_pool.allocate ();
e->kind = NARY;
PRE_EXPR_NARY (e) = result;
result_id = lookup_expression_id (e);
if (result_id != 0)
{
- pool_free (pre_expr_pool, e);
+ pre_expr_pool.remove (e);
e = expression_for_id (result_id);
return e;
}
unsigned int cnt;
/* Try to find a vuse that dominates this phi node by skipping
non-clobbering statements. */
- vuse = get_continuation_for_phi (phi, &ref, &cnt, &visited, false);
+ vuse = get_continuation_for_phi (phi, &ref, &cnt, &visited, false,
+ NULL, NULL);
if (visited)
BITMAP_FREE (visited);
}
case NARY:
return PRE_EXPR_NARY (e)->type;
}
- gcc_unreachable();
+ gcc_unreachable ();
}
/* Get a representative SSA_NAME for a given expression.
pre_expr rep = expression_for_id (i);
if (rep->kind == NAME)
return PRE_EXPR_NAME (rep);
+ else if (rep->kind == CONSTANT)
+ return PRE_EXPR_CONSTANT (rep);
}
}
break;
}
+
/* If we reached here we couldn't find an SSA_NAME. This can
happen when we've discovered a value that has never appeared in
- the program as set to an SSA_NAME, most likely as the result of
- phi translation. */
- if (dump_file)
- {
- fprintf (dump_file,
- "Could not find SSA_NAME representative for expression:");
- print_pre_expr (dump_file, e);
- fprintf (dump_file, "\n");
- }
-
- /* Build and insert the assignment of the end result to the temporary
- that we will return. */
+ the program as set to an SSA_NAME, as the result of phi translation.
+ Create one here.
+ ??? We should be able to re-use this when we insert the statement
+ to compute it. */
name = make_temp_ssa_name (get_expr_type (e), gimple_build_nop (), "pretmp");
VN_INFO_GET (name)->value_id = value_id;
- VN_INFO (name)->valnum = sccvn_valnum_from_value_id (value_id);
- if (VN_INFO (name)->valnum == NULL_TREE)
- VN_INFO (name)->valnum = name;
+ VN_INFO (name)->valnum = name;
+ /* ??? For now mark this SSA name for release by SCCVN. */
+ VN_INFO (name)->needs_insertion = true;
add_to_value (value_id, get_or_alloc_expr_for_name (name));
- if (dump_file)
+ if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "Created SSA_NAME representative ");
print_generic_expr (dump_file, name, 0);
fprintf (dump_file, " for expression:");
print_pre_expr (dump_file, e);
- fprintf (dump_file, "\n");
+ fprintf (dump_file, " (%04d)\n", value_id);
}
return name;
if (result && is_gimple_min_invariant (result))
return get_or_alloc_expr_for_constant (result);
- expr = (pre_expr) pool_alloc (pre_expr_pool);
+ expr = pre_expr_pool.allocate ();
expr->kind = NARY;
expr->id = 0;
if (nary)
else
{
new_val_id = get_next_value_id ();
- value_expressions.safe_grow_cleared (get_max_value_id() + 1);
+ value_expressions.safe_grow_cleared (get_max_value_id () + 1);
nary = vn_nary_op_insert_pieces (newnary->length,
newnary->opcode,
newnary->type,
tree newvuse = vuse;
vec<vn_reference_op_s> newoperands = vNULL;
bool changed = false, same_valid = true;
- unsigned int i, j, n;
+ unsigned int i, n;
vn_reference_op_t operand;
vn_reference_t newref;
- for (i = 0, j = 0;
- operands.iterate (i, &operand); i++, j++)
+ for (i = 0; operands.iterate (i, &operand); i++)
{
pre_expr opresult;
pre_expr leader;
leader = find_leader_in_sets (op_val_id, set1, set2);
if (!leader)
break;
- /* Make sure we do not recursively translate ourselves
- like for translating a[n_1] with the leader for
- n_1 being a[n_1]. */
- if (get_expression_id (leader) != get_expression_id (expr))
+ opresult = phi_translate (leader, set1, set2, pred, phiblock);
+ if (!opresult)
+ break;
+ if (opresult != leader)
{
- opresult = phi_translate (leader, set1, set2,
- pred, phiblock);
- if (!opresult)
+ tree name = get_representative_for (opresult);
+ if (!name)
break;
- if (opresult != leader)
- {
- tree name = get_representative_for (opresult);
- if (!name)
- break;
- changed |= name != op[n];
- op[n] = name;
- }
+ changed |= name != op[n];
+ op[n] = name;
}
}
if (n != 3)
newoperands.release ();
return NULL;
}
+ if (!changed)
+ continue;
if (!newoperands.exists ())
newoperands = operands.copy ();
/* We may have changed from an SSA_NAME to a constant */
newop.op0 = op[0];
newop.op1 = op[1];
newop.op2 = op[2];
- /* If it transforms a non-constant ARRAY_REF into a constant
- one, adjust the constant offset. */
- if (newop.opcode == ARRAY_REF
- && newop.off == -1
- && TREE_CODE (op[0]) == INTEGER_CST
- && TREE_CODE (op[1]) == INTEGER_CST
- && TREE_CODE (op[2]) == INTEGER_CST)
- {
- double_int off = tree_to_double_int (op[0]);
- off += -tree_to_double_int (op[1]);
- off *= tree_to_double_int (op[2]);
- if (off.fits_shwi ())
- newop.off = off.low;
- }
- newoperands[j] = newop;
- /* If it transforms from an SSA_NAME to an address, fold with
- a preceding indirect reference. */
- if (j > 0 && op[0] && TREE_CODE (op[0]) == ADDR_EXPR
- && newoperands[j - 1].opcode == MEM_REF)
- vn_reference_fold_indirect (&newoperands, &j);
- }
- if (i != operands.length ())
- {
- newoperands.release ();
- return NULL;
+ newoperands[i] = newop;
}
+ gcc_checking_assert (i == operands.length ());
if (vuse)
{
- newvuse = translate_vuse_through_block (newoperands,
+ newvuse = translate_vuse_through_block (newoperands.exists ()
+ ? newoperands : operands,
ref->set, ref->type,
vuse, phiblock, pred,
&same_valid);
tree result = vn_reference_lookup_pieces (newvuse, ref->set,
ref->type,
- newoperands,
+ newoperands.exists ()
+ ? newoperands : operands,
&newref, VN_WALK);
if (result)
newoperands.release ();
return NULL;
}
- expr = (pre_expr) pool_alloc (pre_expr_pool);
+ expr = pre_expr_pool.allocate ();
expr->kind = REFERENCE;
expr->id = 0;
if (changed || !same_valid)
{
new_val_id = get_next_value_id ();
- value_expressions.safe_grow_cleared(get_max_value_id() + 1);
+ value_expressions.safe_grow_cleared
+ (get_max_value_id () + 1);
}
else
new_val_id = ref->value_id;
+ if (!newoperands.exists ())
+ newoperands = operands.copy ();
newref = vn_reference_insert_pieces (newvuse, ref->set,
ref->type,
newoperands,
result, new_val_id);
- newoperands.create (0);
+ newoperands = vNULL;
PRE_EXPR_REFERENCE (expr) = newref;
constant = fully_constant_expression (expr);
if (constant != expr)
return get_or_alloc_expr_for_name (def);
}
- /* Otherwise return it unchanged - it will get cleaned if its
- value is not available in PREDs AVAIL_OUT set of expressions. */
+ /* Otherwise return it unchanged - it will get removed if its
+ value is not available in PREDs AVAIL_OUT set of expressions
+ by the subtraction of TMP_GEN. */
return expr;
}
phi_translate (pre_expr expr, bitmap_set_t set1, bitmap_set_t set2,
basic_block pred, basic_block phiblock)
{
+ expr_pred_trans_t slot = NULL;
pre_expr phitrans;
if (!expr)
if (value_id_constant_p (get_expr_value_id (expr)))
return expr;
+ /* Don't add translations of NAMEs as those are cheap to translate. */
if (expr->kind != NAME)
{
- phitrans = phi_trans_lookup (expr, pred);
- if (phitrans)
- return phitrans;
+ if (phi_trans_add (&slot, expr, pred))
+ return slot->v;
+ /* Store NULL for the value we want to return in the case of
+ recursing. */
+ slot->v = NULL;
}
/* Translate. */
phitrans = phi_translate_1 (expr, set1, set2, pred, phiblock);
- /* Don't add empty translations to the cache. Neither add
- translations of NAMEs as those are cheap to translate. */
- if (phitrans
- && expr->kind != NAME)
- phi_trans_add (expr, phitrans, pred);
+ if (slot)
+ {
+ if (phitrans)
+ slot->v = phitrans;
+ else
+ /* Remove failed translations again, they cause insert
+ iteration to not pick up new opportunities reliably. */
+ phi_translate_table->remove_elt_with_hash (slot, slot->hashcode);
+ }
return phitrans;
}
}
/* Find the leader for a value (i.e., the name representing that
- value) in a given set, and return it. If STMT is non-NULL it
- makes sure the defining statement for the leader dominates it.
- Return NULL if no leader is found. */
+ value) in a given set, and return it. Return NULL if no leader
+ is found. */
static pre_expr
bitmap_find_leader (bitmap_set_t set, unsigned int val)
For loads/calls, we also see if the vuse is killed in this block. */
static bool
-valid_in_sets (bitmap_set_t set1, bitmap_set_t set2, pre_expr expr,
- basic_block block)
+valid_in_sets (bitmap_set_t set1, bitmap_set_t set2, pre_expr expr)
{
switch (expr->kind)
{
case NAME:
- return bitmap_set_contains_expr (AVAIL_OUT (block), expr);
+ /* By construction all NAMEs are available. Non-available
+ NAMEs are removed by subtracting TMP_GEN from the sets. */
+ return true;
case NARY:
{
unsigned int i;
PA_IN. */
static void
-dependent_clean (bitmap_set_t set1, bitmap_set_t set2, basic_block block)
+dependent_clean (bitmap_set_t set1, bitmap_set_t set2)
{
vec<pre_expr> exprs = sorted_array_from_bitmap_set (set1);
pre_expr expr;
FOR_EACH_VEC_ELT (exprs, i, expr)
{
- if (!valid_in_sets (set1, set2, expr, block))
+ if (!valid_in_sets (set1, set2, expr))
bitmap_remove_from_set (set1, expr);
}
exprs.release ();
in SET. */
static void
-clean (bitmap_set_t set, basic_block block)
+clean (bitmap_set_t set)
{
vec<pre_expr> exprs = sorted_array_from_bitmap_set (set);
pre_expr expr;
FOR_EACH_VEC_ELT (exprs, i, expr)
{
- if (!valid_in_sets (set, NULL, expr, block))
+ if (!valid_in_sets (set, NULL, expr))
bitmap_remove_from_set (set, expr);
}
exprs.release ();
static sbitmap changed_blocks;
-/* Decide whether to defer a block for a later iteration, or PHI
- translate SOURCE to DEST using phis in PHIBLOCK. Return false if we
- should defer the block, and true if we processed it. */
-
-static bool
-defer_or_phi_translate_block (bitmap_set_t dest, bitmap_set_t source,
- basic_block block, basic_block phiblock)
-{
- if (!BB_VISITED (phiblock))
- {
- bitmap_set_bit (changed_blocks, block->index);
- BB_VISITED (block) = 0;
- BB_DEFERRED (block) = 1;
- return false;
- }
- else
- phi_translate_set (dest, source, block, phiblock);
- return true;
-}
-
/* Compute the ANTIC set for BLOCK.
If succs(BLOCK) > 1 then
else if (single_succ_p (block))
{
basic_block succ_bb = single_succ (block);
-
- /* We trade iterations of the dataflow equations for having to
- phi translate the maximal set, which is incredibly slow
- (since the maximal set often has 300+ members, even when you
- have a small number of blocks).
- Basically, we defer the computation of ANTIC for this block
- until we have processed it's successor, which will inevitably
- have a *much* smaller set of values to phi translate once
- clean has been run on it.
- The cost of doing this is that we technically perform more
- iterations, however, they are lower cost iterations.
-
- Timings for PRE on tramp3d-v4:
- without maximal set fix: 11 seconds
- with maximal set fix/without deferring: 26 seconds
- with maximal set fix/with deferring: 11 seconds
- */
-
- if (!defer_or_phi_translate_block (ANTIC_OUT, ANTIC_IN (succ_bb),
- block, succ_bb))
- {
- changed = true;
- goto maybe_dump_sets;
- }
+ gcc_assert (BB_VISITED (succ_bb));
+ phi_translate_set (ANTIC_OUT, ANTIC_IN (succ_bb), block, succ_bb);
}
/* If we have multiple successors, we take the intersection of all of
them. Note that in the case of loop exit phi nodes, we may have
phis to translate through. */
else
{
- vec<basic_block> worklist;
size_t i;
basic_block bprime, first = NULL;
- worklist.create (EDGE_COUNT (block->succs));
+ auto_vec<basic_block> worklist (EDGE_COUNT (block->succs));
FOR_EACH_EDGE (e, ei, block->succs)
{
if (!first
worklist.quick_push (e->dest);
}
- /* Of multiple successors we have to have visited one already. */
- if (!first)
- {
- bitmap_set_bit (changed_blocks, block->index);
- BB_VISITED (block) = 0;
- BB_DEFERRED (block) = 1;
- changed = true;
- worklist.release ();
- goto maybe_dump_sets;
- }
+ /* Of multiple successors we have to have visited one already
+ which is guaranteed by iteration order. */
+ gcc_assert (first != NULL);
- if (!gimple_seq_empty_p (phi_nodes (first)))
- phi_translate_set (ANTIC_OUT, ANTIC_IN (first), block, first);
- else
- bitmap_set_copy (ANTIC_OUT, ANTIC_IN (first));
+ phi_translate_set (ANTIC_OUT, ANTIC_IN (first), block, first);
FOR_EACH_VEC_ELT (worklist, i, bprime)
{
else
bitmap_set_and (ANTIC_OUT, ANTIC_IN (bprime));
}
- worklist.release ();
}
/* Prune expressions that are clobbered in block and thus become
bitmap_value_insert_into_set (ANTIC_IN (block),
expression_for_id (bii));
- clean (ANTIC_IN (block), block);
+ clean (ANTIC_IN (block));
if (!bitmap_set_equal (old, ANTIC_IN (block)))
{
maybe_dump_sets:
if (dump_file && (dump_flags & TDF_DETAILS))
{
- if (!BB_DEFERRED (block) || BB_VISITED (block))
- {
- if (ANTIC_OUT)
- print_bitmap_set (dump_file, ANTIC_OUT, "ANTIC_OUT", block->index);
+ if (ANTIC_OUT)
+ print_bitmap_set (dump_file, ANTIC_OUT, "ANTIC_OUT", block->index);
- print_bitmap_set (dump_file, ANTIC_IN (block), "ANTIC_IN",
- block->index);
+ print_bitmap_set (dump_file, ANTIC_IN (block), "ANTIC_IN",
+ block->index);
- if (S)
- print_bitmap_set (dump_file, S, "S", block->index);
- }
- else
- {
- fprintf (dump_file,
- "Block %d was deferred for a future iteration.\n",
- block->index);
- }
+ if (S)
+ print_bitmap_set (dump_file, S, "S", block->index);
}
if (old)
bitmap_set_free (old);
them. */
else
{
- vec<basic_block> worklist;
size_t i;
basic_block bprime;
- worklist.create (EDGE_COUNT (block->succs));
+ auto_vec<basic_block> worklist (EDGE_COUNT (block->succs));
FOR_EACH_EDGE (e, ei, block->succs)
{
if (e->flags & EDGE_DFS_BACK)
expression_for_id (i));
}
}
- worklist.release ();
}
/* Prune expressions that are clobbered in block and thus become
/* PA_IN[block] = PA_IN[block] - ANTIC_IN[block] */
bitmap_set_subtract_values (PA_IN (block), ANTIC_IN (block));
- dependent_clean (PA_IN (block), ANTIC_IN (block), block);
+ dependent_clean (PA_IN (block), ANTIC_IN (block));
if (!bitmap_set_equal (old_PA_IN, PA_IN (block)))
{
/* If any predecessor edges are abnormal, we punt, so antic_in is empty.
We pre-build the map of blocks with incoming abnormal edges here. */
- has_abnormal_preds = sbitmap_alloc (last_basic_block);
+ has_abnormal_preds = sbitmap_alloc (last_basic_block_for_fn (cfun));
bitmap_clear (has_abnormal_preds);
- FOR_ALL_BB (block)
+ FOR_ALL_BB_FN (block, cfun)
{
edge_iterator ei;
edge e;
}
BB_VISITED (block) = 0;
- BB_DEFERRED (block) = 0;
/* While we are here, give empty ANTIC_IN sets to each block. */
ANTIC_IN (block) = bitmap_set_new ();
}
/* At the exit block we anticipate nothing. */
- BB_VISITED (EXIT_BLOCK_PTR) = 1;
+ BB_VISITED (EXIT_BLOCK_PTR_FOR_FN (cfun)) = 1;
- changed_blocks = sbitmap_alloc (last_basic_block + 1);
+ changed_blocks = sbitmap_alloc (last_basic_block_for_fn (cfun) + 1);
bitmap_ones (changed_blocks);
while (changed)
{
{
if (bitmap_bit_p (changed_blocks, postorder[i]))
{
- basic_block block = BASIC_BLOCK (postorder[i]);
+ basic_block block = BASIC_BLOCK_FOR_FN (cfun, postorder[i]);
changed |= compute_antic_aux (block,
bitmap_bit_p (has_abnormal_preds,
block->index));
{
if (bitmap_bit_p (changed_blocks, postorder[i]))
{
- basic_block block = BASIC_BLOCK (postorder[i]);
+ basic_block block = BASIC_BLOCK_FOR_FN (cfun, postorder[i]);
changed
|= compute_partial_antic_aux (block,
bitmap_bit_p (has_abnormal_preds,
fn = currop->op0;
else
fn = find_or_generate_expression (block, currop->op0, stmts);
+ if (!fn)
+ return NULL_TREE;
if (currop->op1)
- sc = find_or_generate_expression (block, currop->op1, stmts);
+ {
+ sc = find_or_generate_expression (block, currop->op1, stmts);
+ if (!sc)
+ return NULL_TREE;
+ }
args = XNEWVEC (tree, ref->operands.length () - 1);
while (*operand < ref->operands.length ())
{
args[nargs] = create_component_ref_by_pieces_1 (block, ref,
operand, stmts);
+ if (!args[nargs])
+ return NULL_TREE;
nargs++;
}
folded = build_call_array (currop->type,
(TREE_CODE (fn) == FUNCTION_DECL
? build_fold_addr_expr (fn) : fn),
nargs, args);
+ if (currop->with_bounds)
+ CALL_WITH_BOUNDS_P (folded) = true;
free (args);
if (sc)
CALL_EXPR_STATIC_CHAIN (folded) = sc;
{
tree baseop = create_component_ref_by_pieces_1 (block, ref, operand,
stmts);
+ if (!baseop)
+ return NULL_TREE;
tree offset = currop->op0;
if (TREE_CODE (baseop) == ADDR_EXPR
&& handled_component_p (TREE_OPERAND (baseop, 0)))
vn_reference_op_t nextop = &ref->operands[++*operand];
tree baseop = create_component_ref_by_pieces_1 (block, ref, operand,
stmts);
+ if (!baseop)
+ return NULL_TREE;
if (currop->op0)
- genop0 = find_or_generate_expression (block, currop->op0, stmts);
+ {
+ genop0 = find_or_generate_expression (block, currop->op0, stmts);
+ if (!genop0)
+ return NULL_TREE;
+ }
if (nextop->op0)
- genop1 = find_or_generate_expression (block, nextop->op0, stmts);
+ {
+ genop1 = find_or_generate_expression (block, nextop->op0, stmts);
+ if (!genop1)
+ return NULL_TREE;
+ }
return build5 (TARGET_MEM_REF, currop->type,
baseop, currop->op2, genop0, currop->op1, genop1);
}
case IMAGPART_EXPR:
case VIEW_CONVERT_EXPR:
{
- tree genop0 = create_component_ref_by_pieces_1 (block, ref,
- operand, stmts);
+ tree genop0 = create_component_ref_by_pieces_1 (block, ref, operand,
+ stmts);
+ if (!genop0)
+ return NULL_TREE;
return fold_build1 (currop->opcode, currop->type, genop0);
}
{
tree genop0 = create_component_ref_by_pieces_1 (block, ref, operand,
stmts);
+ if (!genop0)
+ return NULL_TREE;
tree genop1 = find_or_generate_expression (block, currop->op0, stmts);
+ if (!genop1)
+ return NULL_TREE;
return fold_build2 (currop->opcode, currop->type, genop0, genop1);
}
{
tree genop0 = create_component_ref_by_pieces_1 (block, ref, operand,
stmts);
+ if (!genop0)
+ return NULL_TREE;
tree op1 = currop->op0;
tree op2 = currop->op1;
return fold_build3 (BIT_FIELD_REF, currop->type, genop0, op1, op2);
tree genop1 = currop->op0;
tree genop2 = currop->op1;
tree genop3 = currop->op2;
- genop0 = create_component_ref_by_pieces_1 (block, ref, operand, stmts);
+ genop0 = create_component_ref_by_pieces_1 (block, ref, operand,
+ stmts);
+ if (!genop0)
+ return NULL_TREE;
genop1 = find_or_generate_expression (block, genop1, stmts);
+ if (!genop1)
+ return NULL_TREE;
if (genop2)
{
tree domain_type = TYPE_DOMAIN (TREE_TYPE (genop0));
|| integer_zerop (TYPE_MIN_VALUE (domain_type))))
genop2 = NULL_TREE;
else
- genop2 = find_or_generate_expression (block, genop2, stmts);
+ {
+ genop2 = find_or_generate_expression (block, genop2, stmts);
+ if (!genop2)
+ return NULL_TREE;
+ }
}
if (genop3)
{
genop3 = size_binop (EXACT_DIV_EXPR, genop3,
size_int (TYPE_ALIGN_UNIT (elmt_type)));
genop3 = find_or_generate_expression (block, genop3, stmts);
+ if (!genop3)
+ return NULL_TREE;
}
}
return build4 (currop->opcode, currop->type, genop0, genop1,
tree op1;
tree genop2 = currop->op1;
op0 = create_component_ref_by_pieces_1 (block, ref, operand, stmts);
+ if (!op0)
+ return NULL_TREE;
/* op1 should be a FIELD_DECL, which are represented by themselves. */
op1 = currop->op0;
if (genop2)
- genop2 = find_or_generate_expression (block, genop2, stmts);
+ {
+ genop2 = find_or_generate_expression (block, genop2, stmts);
+ if (!genop2)
+ return NULL_TREE;
+ }
return fold_build3 (COMPONENT_REF, TREE_TYPE (op1), op0, op1, genop2);
}
return create_component_ref_by_pieces_1 (block, ref, &op, stmts);
}
-/* Find a leader for an expression, or generate one using
- create_expression_by_pieces if it's ANTIC but
- complex.
+/* Find a simple leader for an expression, or generate one using
+ create_expression_by_pieces from a NARY expression for the value.
BLOCK is the basic_block we are looking for leaders in.
OP is the tree expression to find a leader for or generate.
- STMTS is the statement list to put the inserted expressions on.
- Returns the SSA_NAME of the LHS of the generated expression or the
- leader.
- DOMSTMT if non-NULL is a statement that should be dominated by
- all uses in the generated expression. If DOMSTMT is non-NULL this
- routine can fail and return NULL_TREE. Otherwise it will assert
- on failure. */
+ Returns the leader or NULL_TREE on failure. */
static tree
find_or_generate_expression (basic_block block, tree op, gimple_seq *stmts)
return PRE_EXPR_NAME (leader);
else if (leader->kind == CONSTANT)
return PRE_EXPR_CONSTANT (leader);
+
+ /* Defer. */
+ return NULL_TREE;
}
- /* It must be a complex expression, so generate it recursively. */
+ /* It must be a complex expression, so generate it recursively. Note
+ that this is only necessary to handle gcc.dg/tree-ssa/ssa-pre28.c
+ where the insert algorithm fails to insert a required expression. */
bitmap exprset = value_expressions[lookfor];
bitmap_iterator bi;
unsigned int i;
EXECUTE_IF_SET_IN_BITMAP (exprset, 0, i, bi)
{
pre_expr temp = expression_for_id (i);
- if (temp->kind != NAME)
+ /* We cannot insert random REFERENCE expressions at arbitrary
+ places. We can insert NARYs which eventually re-materializes
+ its operand values. */
+ if (temp->kind == NARY)
return create_expression_by_pieces (block, temp, stmts,
get_expr_type (expr));
}
- gcc_unreachable ();
+ /* Defer. */
+ return NULL_TREE;
}
#define NECESSARY GF_PLF_1
This function will die if we hit some value that shouldn't be
ANTIC but is (IE there is no leader for it, or its components).
+ The function returns NULL_TREE in case a different antic expression
+ has to be inserted first.
This function may also generate expressions that are themselves
partially or fully redundant. Those that are will be either made
fully redundant during the next iteration of insert (for partially
redundant ones), or eliminated by eliminate (for fully redundant
- ones).
-
- If DOMSTMT is non-NULL then we make sure that all uses in the
- expressions dominate that statement. In this case the function
- can return NULL_TREE to signal failure. */
+ ones). */
static tree
create_expression_by_pieces (basic_block block, pre_expr expr,
gimple_stmt_iterator gsi;
tree exprtype = type ? type : get_expr_type (expr);
pre_expr nameexpr;
- gimple newstmt;
+ gassign *newstmt;
switch (expr->kind)
{
{
vn_reference_t ref = PRE_EXPR_REFERENCE (expr);
folded = create_component_ref_by_pieces (block, ref, stmts);
+ if (!folded)
+ return NULL_TREE;
}
break;
case NARY:
for (i = 0; i < nary->length; ++i)
{
genop[i] = find_or_generate_expression (block, nary->op[i], stmts);
+ if (!genop[i])
+ return NULL_TREE;
/* Ensure genop[] is properly typed for POINTER_PLUS_EXPR. It
may have conversions stripped. */
if (nary->opcode == POINTER_PLUS_EXPR)
{
if (i == 0)
- genop[i] = fold_convert (nary->type, genop[i]);
+ genop[i] = gimple_convert (&forced_stmts,
+ nary->type, genop[i]);
else if (i == 1)
- genop[i] = convert_to_ptrofftype (genop[i]);
+ genop[i] = gimple_convert (&forced_stmts,
+ sizetype, genop[i]);
}
else
- genop[i] = fold_convert (TREE_TYPE (nary->op[i]), genop[i]);
+ genop[i] = gimple_convert (&forced_stmts,
+ TREE_TYPE (nary->op[i]), genop[i]);
}
if (nary->opcode == CONSTRUCTOR)
{
break;
case 3:
folded = fold_build3 (nary->opcode, nary->type,
- genop[0], genop[1], genop[3]);
+ genop[0], genop[1], genop[2]);
break;
default:
gcc_unreachable ();
statements.
We have to call unshare_expr because force_gimple_operand may
modify the tree we pass to it. */
- folded = force_gimple_operand (unshare_expr (folded), &forced_stmts,
+ gimple_seq tem = NULL;
+ folded = force_gimple_operand (unshare_expr (folded), &tem,
false, NULL);
+ gimple_seq_add_seq_without_update (&forced_stmts, tem);
/* If we have any intermediate expressions to the value sets, add them
to the value sets and chain them in the instruction stream. */
bitmap_value_replace_in_set (NEW_SETS (block), nameexpr);
bitmap_value_replace_in_set (AVAIL_OUT (block), nameexpr);
}
+
+ gimple_set_vuse (stmt, BB_LIVE_VOP_ON_EXIT (block));
+ gimple_set_modified (stmt, true);
}
gimple_seq_add_seq (stmts, forced_stmts);
}
name = make_temp_ssa_name (exprtype, NULL, "pretmp");
newstmt = gimple_build_assign (name, folded);
+ gimple_set_vuse (newstmt, BB_LIVE_VOP_ON_EXIT (block));
+ gimple_set_modified (newstmt, true);
gimple_set_plf (newstmt, NECESSARY, false);
gimple_seq_add_stmt (stmts, newstmt);
{
fprintf (dump_file, "Inserted ");
print_gimple_stmt (dump_file, newstmt, 0, 0);
- fprintf (dump_file, " in predecessor %d\n", block->index);
+ fprintf (dump_file, " in predecessor %d (%04d)\n",
+ block->index, value_id);
}
return name;
}
-/* Returns true if we want to inhibit the insertions of PHI nodes
- for the given EXPR for basic block BB (a member of a loop).
- We want to do this, when we fear that the induction variable we
- create might inhibit vectorization. */
-
-static bool
-inhibit_phi_insertion (basic_block bb, pre_expr expr)
-{
- vn_reference_t vr = PRE_EXPR_REFERENCE (expr);
- vec<vn_reference_op_s> ops = vr->operands;
- vn_reference_op_t op;
- unsigned i;
-
- /* If we aren't going to vectorize we don't inhibit anything. */
- if (!flag_tree_vectorize)
- return false;
-
- /* Otherwise we inhibit the insertion when the address of the
- memory reference is a simple induction variable. In other
- cases the vectorizer won't do anything anyway (either it's
- loop invariant or a complicated expression). */
- FOR_EACH_VEC_ELT (ops, i, op)
- {
- switch (op->opcode)
- {
- case CALL_EXPR:
- /* Calls are not a problem. */
- return false;
-
- case ARRAY_REF:
- case ARRAY_RANGE_REF:
- if (TREE_CODE (op->op0) != SSA_NAME)
- break;
- /* Fallthru. */
- case SSA_NAME:
- {
- basic_block defbb = gimple_bb (SSA_NAME_DEF_STMT (op->op0));
- affine_iv iv;
- /* Default defs are loop invariant. */
- if (!defbb)
- break;
- /* Defined outside this loop, also loop invariant. */
- if (!flow_bb_inside_loop_p (bb->loop_father, defbb))
- break;
- /* If it's a simple induction variable inhibit insertion,
- the vectorizer might be interested in this one. */
- if (simple_iv (bb->loop_father, bb->loop_father,
- op->op0, &iv, true))
- return true;
- /* No simple IV, vectorizer can't do anything, hence no
- reason to inhibit the transformation for this operand. */
- break;
- }
- default:
- break;
- }
- }
- return false;
-}
-
/* Insert the to-be-made-available values of expression EXPRNUM for each
predecessor, stored in AVAIL, into the predecessors of BLOCK, and
merge the result with a phi node, given the same value number as
edge_iterator ei;
tree type = get_expr_type (expr);
tree temp;
- gimple phi;
+ gphi *phi;
/* Make sure we aren't creating an induction variable. */
if (bb_loop_depth (block) > 0 && EDGE_COUNT (block->preds) == 2)
EDGE_PRED (block, 1)->src);
/* Induction variables only have one edge inside the loop. */
if ((firstinsideloop ^ secondinsideloop)
- && (expr->kind != REFERENCE
- || inhibit_phi_insertion (block, expr)))
+ && expr->kind != REFERENCE)
{
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "Skipping insertion of phi for partial redundancy: Looks like an induction variable\n");
&stmts, type);
gcc_assert (!(pred->flags & EDGE_ABNORMAL));
gsi_insert_seq_on_edge (pred, stmts);
+ if (!builtexpr)
+ {
+ /* We cannot insert a PHI node if we failed to insert
+ on one edge. */
+ nophi = true;
+ continue;
+ }
avail[pred->dest_idx] = get_or_alloc_expr_for_name (builtexpr);
insertions = true;
}
gcc_assert (get_expr_type (ae) == type
|| useless_type_conversion_p (type, get_expr_type (ae)));
if (ae->kind == CONSTANT)
- add_phi_arg (phi, PRE_EXPR_CONSTANT (ae), pred, UNKNOWN_LOCATION);
+ add_phi_arg (phi, unshare_expr (PRE_EXPR_CONSTANT (ae)),
+ pred, UNKNOWN_LOCATION);
else
add_phi_arg (phi, PRE_EXPR_NAME (ae), pred, UNKNOWN_LOCATION);
}
bitmap_insert_into_set (NEW_SETS (block),
newphi);
+ /* If we insert a PHI node for a conversion of another PHI node
+ in the same basic-block try to preserve range information.
+ This is important so that followup loop passes receive optimal
+ number of iteration analysis results. See PR61743. */
+ if (expr->kind == NARY
+ && CONVERT_EXPR_CODE_P (expr->u.nary->opcode)
+ && TREE_CODE (expr->u.nary->op[0]) == SSA_NAME
+ && gimple_bb (SSA_NAME_DEF_STMT (expr->u.nary->op[0])) == block
+ && INTEGRAL_TYPE_P (type)
+ && INTEGRAL_TYPE_P (TREE_TYPE (expr->u.nary->op[0]))
+ && (TYPE_PRECISION (type)
+ >= TYPE_PRECISION (TREE_TYPE (expr->u.nary->op[0])))
+ && SSA_NAME_RANGE_INFO (expr->u.nary->op[0]))
+ {
+ wide_int min, max;
+ if (get_range_info (expr->u.nary->op[0], &min, &max) == VR_RANGE
+ && !wi::neg_p (min, SIGNED)
+ && !wi::neg_p (max, SIGNED))
+ /* Just handle extension and sign-changes of all-positive ranges. */
+ set_range_info (temp,
+ SSA_NAME_RANGE_TYPE (expr->u.nary->op[0]),
+ wide_int_storage::from (min, TYPE_PRECISION (type),
+ TYPE_SIGN (type)),
+ wide_int_storage::from (max, TYPE_PRECISION (type),
+ TYPE_SIGN (type)));
+ }
+
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "Created phi ");
print_gimple_stmt (dump_file, phi, 0, 0);
- fprintf (dump_file, " in block %d\n", block->index);
+ fprintf (dump_file, " in block %d (%04d)\n", block->index, val);
}
pre_stats.phis++;
return true;
bool new_stuff = false;
vec<pre_expr> exprs;
pre_expr expr;
- vec<pre_expr> avail = vNULL;
+ auto_vec<pre_expr> avail;
int i;
exprs = sorted_array_from_bitmap_set (ANTIC_IN (block));
FOR_EACH_VEC_ELT (exprs, i, expr)
{
- if (expr->kind != NAME)
+ if (expr->kind == NARY
+ || expr->kind == REFERENCE)
{
unsigned int val;
bool by_some = false;
if (bitmap_set_contains_value (AVAIL_OUT (dom), val))
{
if (dump_file && (dump_flags & TDF_DETAILS))
- fprintf (dump_file, "Found fully redundant value\n");
+ {
+ fprintf (dump_file, "Found fully redundant value: ");
+ print_pre_expr (dump_file, expr);
+ fprintf (dump_file, "\n");
+ }
continue;
}
/* If all edges produce the same value and that value is
an invariant, then the PHI has the same value on all
edges. Note this. */
- else if (!cant_insert && all_same && eprime
- && (edoubleprime->kind == CONSTANT
- || edoubleprime->kind == NAME)
- && !value_id_constant_p (val))
+ else if (!cant_insert && all_same)
{
- unsigned int j;
- bitmap_iterator bi;
- bitmap exprset = value_expressions[val];
-
- unsigned int new_val = get_expr_value_id (edoubleprime);
- EXECUTE_IF_SET_IN_BITMAP (exprset, 0, j, bi)
- {
- pre_expr expr = expression_for_id (j);
-
- if (expr->kind == NAME)
- {
- vn_ssa_aux_t info = VN_INFO (PRE_EXPR_NAME (expr));
- /* Just reset the value id and valnum so it is
- the same as the constant we have discovered. */
- if (edoubleprime->kind == CONSTANT)
- {
- info->valnum = PRE_EXPR_CONSTANT (edoubleprime);
- pre_stats.constified++;
- }
- else
- info->valnum = VN_INFO (PRE_EXPR_NAME (edoubleprime))->valnum;
- info->value_id = new_val;
- }
- }
+ gcc_assert (edoubleprime->kind == CONSTANT
+ || edoubleprime->kind == NAME);
+
+ tree temp = make_temp_ssa_name (get_expr_type (expr),
+ NULL, "pretmp");
+ gassign *assign
+ = gimple_build_assign (temp,
+ edoubleprime->kind == CONSTANT ?
+ PRE_EXPR_CONSTANT (edoubleprime) :
+ PRE_EXPR_NAME (edoubleprime));
+ gimple_stmt_iterator gsi = gsi_after_labels (block);
+ gsi_insert_before (&gsi, assign, GSI_NEW_STMT);
+
+ gimple_set_plf (assign, NECESSARY, false);
+ VN_INFO_GET (temp)->value_id = val;
+ VN_INFO (temp)->valnum = sccvn_valnum_from_value_id (val);
+ if (VN_INFO (temp)->valnum == NULL_TREE)
+ VN_INFO (temp)->valnum = temp;
+ bitmap_set_bit (inserted_exprs, SSA_NAME_VERSION (temp));
+ pre_expr newe = get_or_alloc_expr_for_name (temp);
+ add_to_value (val, newe);
+ bitmap_value_replace_in_set (AVAIL_OUT (block), newe);
+ bitmap_insert_into_set (NEW_SETS (block), newe);
}
}
}
exprs.release ();
- avail.release ();
return new_stuff;
}
bool new_stuff = false;
vec<pre_expr> exprs;
pre_expr expr;
- vec<pre_expr> avail = vNULL;
+ auto_vec<pre_expr> avail;
int i;
exprs = sorted_array_from_bitmap_set (PA_IN (block));
FOR_EACH_VEC_ELT (exprs, i, expr)
{
- if (expr->kind != NAME)
+ if (expr->kind == NARY
+ || expr->kind == REFERENCE)
{
unsigned int val;
bool by_all = true;
}
exprs.release ();
- avail.release ();
return new_stuff;
}
basic_block bb;
int num_iterations = 0;
- FOR_ALL_BB (bb)
+ FOR_ALL_BB_FN (bb, cfun)
NEW_SETS (bb) = bitmap_set_new ();
while (new_stuff)
num_iterations++;
if (dump_file && dump_flags & TDF_DETAILS)
fprintf (dump_file, "Starting insert iteration %d\n", num_iterations);
- new_stuff = insert_aux (ENTRY_BLOCK_PTR);
+ new_stuff = insert_aux (ENTRY_BLOCK_PTR_FOR_FN (cfun));
+
+ /* Clear the NEW sets before the next iteration. We have already
+ fully propagated its contents. */
+ if (new_stuff)
+ FOR_ALL_BB_FN (bb, cfun)
+ bitmap_set_free (NEW_SETS (bb));
}
statistics_histogram_event (cfun, "insert iterations", num_iterations);
}
e = get_or_alloc_expr_for_name (name);
add_to_value (get_expr_value_id (e), e);
- bitmap_insert_into_set (TMP_GEN (ENTRY_BLOCK_PTR), e);
- bitmap_value_insert_into_set (AVAIL_OUT (ENTRY_BLOCK_PTR), e);
+ bitmap_insert_into_set (TMP_GEN (ENTRY_BLOCK_PTR_FOR_FN (cfun)), e);
+ bitmap_value_insert_into_set (AVAIL_OUT (ENTRY_BLOCK_PTR_FOR_FN (cfun)),
+ e);
}
if (dump_file && (dump_flags & TDF_DETAILS))
{
- print_bitmap_set (dump_file, TMP_GEN (ENTRY_BLOCK_PTR),
+ print_bitmap_set (dump_file, TMP_GEN (ENTRY_BLOCK_PTR_FOR_FN (cfun)),
"tmp_gen", ENTRY_BLOCK);
- print_bitmap_set (dump_file, AVAIL_OUT (ENTRY_BLOCK_PTR),
+ print_bitmap_set (dump_file, AVAIL_OUT (ENTRY_BLOCK_PTR_FOR_FN (cfun)),
"avail_out", ENTRY_BLOCK);
}
/* Allocate the worklist. */
- worklist = XNEWVEC (basic_block, n_basic_blocks);
+ worklist = XNEWVEC (basic_block, n_basic_blocks_for_fn (cfun));
/* Seed the algorithm by putting the dominator children of the entry
block on the worklist. */
- for (son = first_dom_son (CDI_DOMINATORS, ENTRY_BLOCK_PTR);
+ for (son = first_dom_son (CDI_DOMINATORS, ENTRY_BLOCK_PTR_FOR_FN (cfun));
son;
son = next_dom_son (CDI_DOMINATORS, son))
worklist[sp++] = son;
+ BB_LIVE_VOP_ON_EXIT (ENTRY_BLOCK_PTR_FOR_FN (cfun))
+ = ssa_default_def (cfun, gimple_vop (cfun));
+
/* Loop until the worklist is empty. */
while (sp)
{
- gimple_stmt_iterator gsi;
gimple stmt;
basic_block dom;
its immediate dominator. */
dom = get_immediate_dominator (CDI_DOMINATORS, block);
if (dom)
- bitmap_set_copy (AVAIL_OUT (block), AVAIL_OUT (dom));
+ {
+ bitmap_set_copy (AVAIL_OUT (block), AVAIL_OUT (dom));
+ BB_LIVE_VOP_ON_EXIT (block) = BB_LIVE_VOP_ON_EXIT (dom);
+ }
/* Generate values for PHI nodes. */
- for (gsi = gsi_start_phis (block); !gsi_end_p (gsi); gsi_next (&gsi))
+ for (gphi_iterator gsi = gsi_start_phis (block); !gsi_end_p (gsi);
+ gsi_next (&gsi))
{
- tree result = gimple_phi_result (gsi_stmt (gsi));
+ tree result = gimple_phi_result (gsi.phi ());
/* We have no need for virtual phis, as they don't represent
actual computations. */
if (virtual_operand_p (result))
- continue;
+ {
+ BB_LIVE_VOP_ON_EXIT (block) = result;
+ continue;
+ }
pre_expr e = get_or_alloc_expr_for_name (result);
add_to_value (get_expr_value_id (e), e);
/* Now compute value numbers and populate value sets with all
the expressions computed in BLOCK. */
- for (gsi = gsi_start_bb (block); !gsi_end_p (gsi); gsi_next (&gsi))
+ for (gimple_stmt_iterator gsi = gsi_start_bb (block); !gsi_end_p (gsi);
+ gsi_next (&gsi))
{
ssa_op_iter iter;
tree op;
bitmap_value_insert_into_set (AVAIL_OUT (block), e);
}
+ if (gimple_vdef (stmt))
+ BB_LIVE_VOP_ON_EXIT (block) = gimple_vdef (stmt);
+
if (gimple_has_side_effects (stmt)
|| stmt_could_throw_p (stmt)
|| is_gimple_debug (stmt))
case GIMPLE_CALL:
{
vn_reference_t ref;
+ vn_reference_s ref1;
pre_expr result = NULL;
- vec<vn_reference_op_s> ops = vNULL;
/* We can value number only calls to real functions. */
if (gimple_call_internal_p (stmt))
continue;
- copy_reference_ops_from_call (stmt, &ops);
- vn_reference_lookup_pieces (gimple_vuse (stmt), 0,
- gimple_expr_type (stmt),
- ops, &ref, VN_NOWALK);
- ops.release ();
+ vn_reference_lookup_call (as_a <gcall *> (stmt), &ref, &ref1);
if (!ref)
continue;
|| gimple_bb (SSA_NAME_DEF_STMT
(gimple_vuse (stmt))) != block)
{
- result = (pre_expr) pool_alloc (pre_expr_pool);
+ result = pre_expr_pool.allocate ();
result->kind = REFERENCE;
result->id = 0;
PRE_EXPR_REFERENCE (result) = ref;
&& vn_nary_may_trap (nary))
continue;
- result = (pre_expr) pool_alloc (pre_expr_pool);
+ result = pre_expr_pool.allocate ();
result->kind = NARY;
result->id = 0;
PRE_EXPR_NARY (result) = nary;
continue;
}
- result = (pre_expr) pool_alloc (pre_expr_pool);
+ result = pre_expr_pool.allocate ();
result->kind = REFERENCE;
result->id = 0;
PRE_EXPR_REFERENCE (result) = ref;
/* Local state for the eliminate domwalk. */
static vec<gimple> el_to_remove;
-static vec<gimple> el_to_update;
+static vec<gimple> el_to_fixup;
static unsigned int el_todo;
static vec<tree> el_avail;
static vec<tree> el_avail_stack;
{
if (el_avail.length () <= SSA_NAME_VERSION (valnum))
el_avail.safe_grow_cleared (SSA_NAME_VERSION (valnum) + 1);
+ tree pushop = op;
+ if (el_avail[SSA_NAME_VERSION (valnum)])
+ pushop = el_avail[SSA_NAME_VERSION (valnum)];
+ el_avail_stack.safe_push (pushop);
el_avail[SSA_NAME_VERSION (valnum)] = op;
- el_avail_stack.safe_push (op);
}
}
return NULL_TREE;
tree res = make_temp_ssa_name (TREE_TYPE (val), NULL, "pretmp");
- gimple tem = gimple_build_assign (res,
- fold_build1 (TREE_CODE (expr),
- TREE_TYPE (expr), leader));
+ gassign *tem = gimple_build_assign (res,
+ fold_build1 (TREE_CODE (expr),
+ TREE_TYPE (expr), leader));
gsi_insert_before (gsi, tem, GSI_SAME_STMT);
VN_INFO_GET (res)->valnum = val;
return res;
}
+class eliminate_dom_walker : public dom_walker
+{
+public:
+ eliminate_dom_walker (cdi_direction direction, bool do_pre_)
+ : dom_walker (direction), do_pre (do_pre_) {}
+
+ virtual void before_dom_children (basic_block);
+ virtual void after_dom_children (basic_block);
+
+ bool do_pre;
+};
+
/* Perform elimination for the basic-block B during the domwalk. */
-static void
-eliminate_bb (dom_walk_data *, basic_block b)
+void
+eliminate_dom_walker::before_dom_children (basic_block b)
{
- gimple_stmt_iterator gsi;
- gimple stmt;
-
/* Mark new bb. */
el_avail_stack.safe_push (NULL_TREE);
- for (gsi = gsi_start_phis (b); !gsi_end_p (gsi);)
+ /* ??? If we do nothing for unreachable blocks then this will confuse
+ tailmerging. Eventually we can reduce its reliance on SCCVN now
+ that we fully copy/constant-propagate (most) things. */
+
+ for (gphi_iterator gsi = gsi_start_phis (b); !gsi_end_p (gsi);)
{
- gimple stmt, phi = gsi_stmt (gsi);
- tree sprime = NULL_TREE, res = PHI_RESULT (phi);
- gimple_stmt_iterator gsi2;
-
- /* We want to perform redundant PHI elimination. Do so by
- replacing the PHI with a single copy if possible.
- Do not touch inserted, single-argument or virtual PHIs. */
- if (gimple_phi_num_args (phi) == 1
- || virtual_operand_p (res))
- {
- gsi_next (&gsi);
- continue;
- }
+ gphi *phi = gsi.phi ();
+ tree res = PHI_RESULT (phi);
- sprime = eliminate_avail (res);
- if (!sprime
- || sprime == res)
+ if (virtual_operand_p (res))
{
- eliminate_push_avail (res);
gsi_next (&gsi);
continue;
}
- else if (is_gimple_min_invariant (sprime))
- {
- if (!useless_type_conversion_p (TREE_TYPE (res),
- TREE_TYPE (sprime)))
- sprime = fold_convert (TREE_TYPE (res), sprime);
- }
- if (dump_file && (dump_flags & TDF_DETAILS))
+ tree sprime = eliminate_avail (res);
+ if (sprime
+ && sprime != res)
{
- fprintf (dump_file, "Replaced redundant PHI node defining ");
- print_generic_expr (dump_file, res, 0);
- fprintf (dump_file, " with ");
- print_generic_expr (dump_file, sprime, 0);
- fprintf (dump_file, "\n");
- }
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "Replaced redundant PHI node defining ");
+ print_generic_expr (dump_file, res, 0);
+ fprintf (dump_file, " with ");
+ print_generic_expr (dump_file, sprime, 0);
+ fprintf (dump_file, "\n");
+ }
- remove_phi_node (&gsi, false);
+ /* If we inserted this PHI node ourself, it's not an elimination. */
+ if (inserted_exprs
+ && bitmap_bit_p (inserted_exprs, SSA_NAME_VERSION (res)))
+ pre_stats.phis--;
+ else
+ pre_stats.eliminations++;
- if (inserted_exprs
- && !bitmap_bit_p (inserted_exprs, SSA_NAME_VERSION (res))
- && TREE_CODE (sprime) == SSA_NAME)
- gimple_set_plf (SSA_NAME_DEF_STMT (sprime), NECESSARY, true);
-
- if (!useless_type_conversion_p (TREE_TYPE (res), TREE_TYPE (sprime)))
- sprime = fold_convert (TREE_TYPE (res), sprime);
- stmt = gimple_build_assign (res, sprime);
- SSA_NAME_DEF_STMT (res) = stmt;
- gimple_set_plf (stmt, NECESSARY, gimple_plf (phi, NECESSARY));
-
- gsi2 = gsi_after_labels (b);
- gsi_insert_before (&gsi2, stmt, GSI_NEW_STMT);
- /* Queue the copy for eventual removal. */
- el_to_remove.safe_push (stmt);
- /* If we inserted this PHI node ourself, it's not an elimination. */
- if (inserted_exprs
- && bitmap_bit_p (inserted_exprs, SSA_NAME_VERSION (res)))
- pre_stats.phis--;
- else
- pre_stats.eliminations++;
- }
+ /* If we will propagate into all uses don't bother to do
+ anything. */
+ if (may_propagate_copy (res, sprime))
+ {
+ /* Mark the PHI for removal. */
+ el_to_remove.safe_push (phi);
+ gsi_next (&gsi);
+ continue;
+ }
- for (gsi = gsi_start_bb (b); !gsi_end_p (gsi); gsi_next (&gsi))
- {
- tree lhs = NULL_TREE;
- tree rhs = NULL_TREE;
+ remove_phi_node (&gsi, false);
- stmt = gsi_stmt (gsi);
+ if (inserted_exprs
+ && !bitmap_bit_p (inserted_exprs, SSA_NAME_VERSION (res))
+ && TREE_CODE (sprime) == SSA_NAME)
+ gimple_set_plf (SSA_NAME_DEF_STMT (sprime), NECESSARY, true);
- if (gimple_has_lhs (stmt))
- lhs = gimple_get_lhs (stmt);
+ if (!useless_type_conversion_p (TREE_TYPE (res), TREE_TYPE (sprime)))
+ sprime = fold_convert (TREE_TYPE (res), sprime);
+ gimple stmt = gimple_build_assign (res, sprime);
+ /* ??? It cannot yet be necessary (DOM walk). */
+ gimple_set_plf (stmt, NECESSARY, gimple_plf (phi, NECESSARY));
- if (gimple_assign_single_p (stmt))
- rhs = gimple_assign_rhs1 (stmt);
-
- /* Lookup the RHS of the expression, see if we have an
- available computation for it. If so, replace the RHS with
- the available computation.
-
- See PR43491.
- We don't replace global register variable when it is a the RHS of
- a single assign. We do replace local register variable since gcc
- does not guarantee local variable will be allocated in register. */
- if (gimple_has_lhs (stmt)
- && TREE_CODE (lhs) == SSA_NAME
- && !gimple_assign_ssa_name_copy_p (stmt)
- && (!gimple_assign_single_p (stmt)
- || (!is_gimple_min_invariant (rhs)
- && (gimple_assign_rhs_code (stmt) != VAR_DECL
- || !is_global_var (rhs)
- || !DECL_HARD_REGISTER (rhs))))
- && !gimple_has_volatile_ops (stmt))
- {
- tree sprime;
- gimple orig_stmt = stmt;
+ gimple_stmt_iterator gsi2 = gsi_after_labels (b);
+ gsi_insert_before (&gsi2, stmt, GSI_NEW_STMT);
+ continue;
+ }
+
+ eliminate_push_avail (res);
+ gsi_next (&gsi);
+ }
+ for (gimple_stmt_iterator gsi = gsi_start_bb (b);
+ !gsi_end_p (gsi);
+ gsi_next (&gsi))
+ {
+ tree sprime = NULL_TREE;
+ gimple stmt = gsi_stmt (gsi);
+ tree lhs = gimple_get_lhs (stmt);
+ if (lhs && TREE_CODE (lhs) == SSA_NAME
+ && !gimple_has_volatile_ops (stmt)
+ /* See PR43491. Do not replace a global register variable when
+ it is a the RHS of an assignment. Do replace local register
+ variables since gcc does not guarantee a local variable will
+ be allocated in register.
+ ??? The fix isn't effective here. This should instead
+ be ensured by not value-numbering them the same but treating
+ them like volatiles? */
+ && !(gimple_assign_single_p (stmt)
+ && (TREE_CODE (gimple_assign_rhs1 (stmt)) == VAR_DECL
+ && DECL_HARD_REGISTER (gimple_assign_rhs1 (stmt))
+ && is_global_var (gimple_assign_rhs1 (stmt)))))
+ {
sprime = eliminate_avail (lhs);
if (!sprime)
{
if (val != VN_TOP
&& TREE_CODE (val) == SSA_NAME
&& VN_INFO (val)->needs_insertion
+ && VN_INFO (val)->expr != NULL_TREE
&& (sprime = eliminate_insert (&gsi, val)) != NULL_TREE)
eliminate_push_avail (sprime);
}
- else if (is_gimple_min_invariant (sprime))
+
+ /* If this now constitutes a copy duplicate points-to
+ and range info appropriately. This is especially
+ important for inserted code. See tree-ssa-copy.c
+ for similar code. */
+ if (sprime
+ && TREE_CODE (sprime) == SSA_NAME)
{
- /* If there is no existing leader but SCCVN knows this
- value is constant, use that constant. */
- if (!useless_type_conversion_p (TREE_TYPE (lhs),
- TREE_TYPE (sprime)))
- sprime = fold_convert (TREE_TYPE (lhs), sprime);
+ basic_block sprime_b = gimple_bb (SSA_NAME_DEF_STMT (sprime));
+ if (POINTER_TYPE_P (TREE_TYPE (lhs))
+ && SSA_NAME_PTR_INFO (lhs)
+ && !SSA_NAME_PTR_INFO (sprime))
+ {
+ duplicate_ssa_name_ptr_info (sprime,
+ SSA_NAME_PTR_INFO (lhs));
+ if (b != sprime_b)
+ mark_ptr_info_alignment_unknown
+ (SSA_NAME_PTR_INFO (sprime));
+ }
+ else if (!POINTER_TYPE_P (TREE_TYPE (lhs))
+ && SSA_NAME_RANGE_INFO (lhs)
+ && !SSA_NAME_RANGE_INFO (sprime)
+ && b == sprime_b)
+ duplicate_ssa_name_range_info (sprime,
+ SSA_NAME_RANGE_TYPE (lhs),
+ SSA_NAME_RANGE_INFO (lhs));
+ }
- if (dump_file && (dump_flags & TDF_DETAILS))
+ /* Inhibit the use of an inserted PHI on a loop header when
+ the address of the memory reference is a simple induction
+ variable. In other cases the vectorizer won't do anything
+ anyway (either it's loop invariant or a complicated
+ expression). */
+ if (sprime
+ && TREE_CODE (sprime) == SSA_NAME
+ && do_pre
+ && flag_tree_loop_vectorize
+ && loop_outer (b->loop_father)
+ && has_zero_uses (sprime)
+ && bitmap_bit_p (inserted_exprs, SSA_NAME_VERSION (sprime))
+ && gimple_assign_load_p (stmt))
+ {
+ gimple def_stmt = SSA_NAME_DEF_STMT (sprime);
+ basic_block def_bb = gimple_bb (def_stmt);
+ if (gimple_code (def_stmt) == GIMPLE_PHI
+ && b->loop_father->header == def_bb)
{
- fprintf (dump_file, "Replaced ");
- print_gimple_expr (dump_file, stmt, 0, 0);
- fprintf (dump_file, " with ");
- print_generic_expr (dump_file, sprime, 0);
- fprintf (dump_file, " in ");
- print_gimple_stmt (dump_file, stmt, 0, 0);
+ ssa_op_iter iter;
+ tree op;
+ bool found = false;
+ FOR_EACH_SSA_TREE_OPERAND (op, stmt, iter, SSA_OP_USE)
+ {
+ affine_iv iv;
+ def_bb = gimple_bb (SSA_NAME_DEF_STMT (op));
+ if (def_bb
+ && flow_bb_inside_loop_p (b->loop_father, def_bb)
+ && simple_iv (b->loop_father,
+ b->loop_father, op, &iv, true))
+ {
+ found = true;
+ break;
+ }
+ }
+ if (found)
+ {
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "Not replacing ");
+ print_gimple_expr (dump_file, stmt, 0, 0);
+ fprintf (dump_file, " with ");
+ print_generic_expr (dump_file, sprime, 0);
+ fprintf (dump_file, " which would add a loop"
+ " carried dependence to loop %d\n",
+ b->loop_father->num);
+ }
+ /* Don't keep sprime available. */
+ sprime = NULL_TREE;
+ }
}
- pre_stats.eliminations++;
- propagate_tree_value_into_stmt (&gsi, sprime);
- stmt = gsi_stmt (gsi);
- update_stmt (stmt);
+ }
- /* If we removed EH side-effects from the statement, clean
- its EH information. */
- if (maybe_clean_or_replace_eh_stmt (orig_stmt, stmt))
+ if (sprime)
+ {
+ /* If we can propagate the value computed for LHS into
+ all uses don't bother doing anything with this stmt. */
+ if (may_propagate_copy (lhs, sprime))
{
- bitmap_set_bit (need_eh_cleanup,
- gimple_bb (stmt)->index);
+ /* Mark it for removal. */
+ el_to_remove.safe_push (stmt);
+
+ /* ??? Don't count copy/constant propagations. */
+ if (gimple_assign_single_p (stmt)
+ && (TREE_CODE (gimple_assign_rhs1 (stmt)) == SSA_NAME
+ || gimple_assign_rhs1 (stmt) == sprime))
+ continue;
+
if (dump_file && (dump_flags & TDF_DETAILS))
- fprintf (dump_file, " Removed EH side-effects.\n");
+ {
+ fprintf (dump_file, "Replaced ");
+ print_gimple_expr (dump_file, stmt, 0, 0);
+ fprintf (dump_file, " with ");
+ print_generic_expr (dump_file, sprime, 0);
+ fprintf (dump_file, " in all uses of ");
+ print_gimple_stmt (dump_file, stmt, 0, 0);
+ }
+
+ pre_stats.eliminations++;
+ continue;
}
- continue;
- }
- /* If there is no usable leader mark lhs as leader for its value. */
- if (!sprime)
- eliminate_push_avail (lhs);
+ /* If this is an assignment from our leader (which
+ happens in the case the value-number is a constant)
+ then there is nothing to do. */
+ if (gimple_assign_single_p (stmt)
+ && sprime == gimple_assign_rhs1 (stmt))
+ continue;
- if (sprime
- && sprime != lhs
- && (rhs == NULL_TREE
- || TREE_CODE (rhs) != SSA_NAME
- || may_propagate_copy (rhs, sprime)))
- {
+ /* Else replace its RHS. */
bool can_make_abnormal_goto
= is_gimple_call (stmt)
&& stmt_can_make_abnormal_goto (stmt);
- gcc_assert (sprime != rhs);
-
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "Replaced ");
if (TREE_CODE (sprime) == SSA_NAME)
gimple_set_plf (SSA_NAME_DEF_STMT (sprime),
NECESSARY, true);
- /* We need to make sure the new and old types actually match,
- which may require adding a simple cast, which fold_convert
- will do for us. */
- if ((!rhs || TREE_CODE (rhs) != SSA_NAME)
- && !useless_type_conversion_p (gimple_expr_type (stmt),
- TREE_TYPE (sprime)))
- sprime = fold_convert (gimple_expr_type (stmt), sprime);
pre_stats.eliminations++;
+ gimple orig_stmt = stmt;
+ if (!useless_type_conversion_p (TREE_TYPE (lhs),
+ TREE_TYPE (sprime)))
+ sprime = fold_convert (TREE_TYPE (lhs), sprime);
+ tree vdef = gimple_vdef (stmt);
+ tree vuse = gimple_vuse (stmt);
propagate_tree_value_into_stmt (&gsi, sprime);
stmt = gsi_stmt (gsi);
update_stmt (stmt);
+ if (vdef != gimple_vdef (stmt))
+ VN_INFO (vdef)->valnum = vuse;
/* If we removed EH side-effects from the statement, clean
its EH information. */
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, " Removed AB side-effects.\n");
}
+
+ continue;
}
}
+
/* If the statement is a scalar store, see if the expression
- has the same value number as its rhs. If so, the store is
- dead. */
- else if (gimple_assign_single_p (stmt)
- && !gimple_has_volatile_ops (stmt)
- && !is_gimple_reg (gimple_assign_lhs (stmt))
- && (TREE_CODE (rhs) == SSA_NAME
- || is_gimple_min_invariant (rhs)))
- {
- tree val;
- val = vn_reference_lookup (gimple_assign_lhs (stmt),
- gimple_vuse (stmt), VN_WALK, NULL);
- if (TREE_CODE (rhs) == SSA_NAME)
- rhs = VN_INFO (rhs)->valnum;
- if (val
- && operand_equal_p (val, rhs, 0))
- {
- if (dump_file && (dump_flags & TDF_DETAILS))
- {
- fprintf (dump_file, "Deleted redundant store ");
- print_gimple_stmt (dump_file, stmt, 0, 0);
- }
+ has the same value number as its rhs. If so, the store is
+ dead. */
+ if (gimple_assign_single_p (stmt)
+ && !gimple_has_volatile_ops (stmt)
+ && !is_gimple_reg (gimple_assign_lhs (stmt))
+ && (TREE_CODE (gimple_assign_rhs1 (stmt)) == SSA_NAME
+ || is_gimple_min_invariant (gimple_assign_rhs1 (stmt))))
+ {
+ tree val;
+ tree rhs = gimple_assign_rhs1 (stmt);
+ val = vn_reference_lookup (gimple_assign_lhs (stmt),
+ gimple_vuse (stmt), VN_WALK, NULL);
+ if (TREE_CODE (rhs) == SSA_NAME)
+ rhs = VN_INFO (rhs)->valnum;
+ if (val
+ && operand_equal_p (val, rhs, 0))
+ {
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "Deleted redundant store ");
+ print_gimple_stmt (dump_file, stmt, 0, 0);
+ }
+
+ /* Queue stmt for removal. */
+ el_to_remove.safe_push (stmt);
+ continue;
+ }
+ }
- /* Queue stmt for removal. */
- el_to_remove.safe_push (stmt);
- }
- }
- /* Visit COND_EXPRs and fold the comparison with the
- available value-numbers. */
- else if (gimple_code (stmt) == GIMPLE_COND)
+ bool can_make_abnormal_goto = stmt_can_make_abnormal_goto (stmt);
+ bool was_noreturn = (is_gimple_call (stmt)
+ && gimple_call_noreturn_p (stmt));
+ tree vdef = gimple_vdef (stmt);
+ tree vuse = gimple_vuse (stmt);
+
+ /* If we didn't replace the whole stmt (or propagate the result
+ into all uses), replace all uses on this stmt with their
+ leaders. */
+ use_operand_p use_p;
+ ssa_op_iter iter;
+ FOR_EACH_SSA_USE_OPERAND (use_p, stmt, iter, SSA_OP_USE)
{
- tree op0 = gimple_cond_lhs (stmt);
- tree op1 = gimple_cond_rhs (stmt);
- tree result;
-
- if (TREE_CODE (op0) == SSA_NAME)
- op0 = VN_INFO (op0)->valnum;
- if (TREE_CODE (op1) == SSA_NAME)
- op1 = VN_INFO (op1)->valnum;
- result = fold_binary (gimple_cond_code (stmt), boolean_type_node,
- op0, op1);
- if (result && TREE_CODE (result) == INTEGER_CST)
+ tree use = USE_FROM_PTR (use_p);
+ /* ??? The call code above leaves stmt operands un-updated. */
+ if (TREE_CODE (use) != SSA_NAME)
+ continue;
+ tree sprime = eliminate_avail (use);
+ if (sprime && sprime != use
+ && may_propagate_copy (use, sprime)
+ /* We substitute into debug stmts to avoid excessive
+ debug temporaries created by removed stmts, but we need
+ to avoid doing so for inserted sprimes as we never want
+ to create debug temporaries for them. */
+ && (!inserted_exprs
+ || TREE_CODE (sprime) != SSA_NAME
+ || !is_gimple_debug (stmt)
+ || !bitmap_bit_p (inserted_exprs, SSA_NAME_VERSION (sprime))))
{
- if (integer_zerop (result))
- gimple_cond_make_false (stmt);
- else
- gimple_cond_make_true (stmt);
- update_stmt (stmt);
- el_todo = TODO_cleanup_cfg;
+ propagate_value (use_p, sprime);
+ gimple_set_modified (stmt, true);
+ if (TREE_CODE (sprime) == SSA_NAME
+ && !is_gimple_debug (stmt))
+ gimple_set_plf (SSA_NAME_DEF_STMT (sprime),
+ NECESSARY, true);
}
}
+
/* Visit indirect calls and turn them into direct calls if
- possible. */
- if (is_gimple_call (stmt))
+ possible using the devirtualization machinery. */
+ if (gcall *call_stmt = dyn_cast <gcall *> (stmt))
{
- tree orig_fn = gimple_call_fn (stmt);
- tree fn;
- if (!orig_fn)
- continue;
- if (TREE_CODE (orig_fn) == SSA_NAME)
- fn = VN_INFO (orig_fn)->valnum;
- else if (TREE_CODE (orig_fn) == OBJ_TYPE_REF
- && TREE_CODE (OBJ_TYPE_REF_EXPR (orig_fn)) == SSA_NAME)
- fn = VN_INFO (OBJ_TYPE_REF_EXPR (orig_fn))->valnum;
- else
- continue;
- if (gimple_call_addr_fndecl (fn) != NULL_TREE
- && useless_type_conversion_p (TREE_TYPE (orig_fn),
- TREE_TYPE (fn)))
+ tree fn = gimple_call_fn (call_stmt);
+ if (fn
+ && flag_devirtualize
+ && virtual_method_call_p (fn))
{
- bool can_make_abnormal_goto
- = stmt_can_make_abnormal_goto (stmt);
- bool was_noreturn = gimple_call_noreturn_p (stmt);
-
- if (dump_file && (dump_flags & TDF_DETAILS))
+ tree otr_type = obj_type_ref_class (fn);
+ tree instance;
+ ipa_polymorphic_call_context context (current_function_decl, fn, stmt, &instance);
+ bool final;
+
+ context.get_dynamic_type (instance, OBJ_TYPE_REF_OBJECT (fn), otr_type, stmt);
+
+ vec <cgraph_node *>targets
+ = possible_polymorphic_call_targets (obj_type_ref_class (fn),
+ tree_to_uhwi
+ (OBJ_TYPE_REF_TOKEN (fn)),
+ context,
+ &final);
+ if (dump_file)
+ dump_possible_polymorphic_call_targets (dump_file,
+ obj_type_ref_class (fn),
+ tree_to_uhwi
+ (OBJ_TYPE_REF_TOKEN (fn)),
+ context);
+ if (final && targets.length () <= 1 && dbg_cnt (devirt))
{
- fprintf (dump_file, "Replacing call target with ");
- print_generic_expr (dump_file, fn, 0);
- fprintf (dump_file, " in ");
- print_gimple_stmt (dump_file, stmt, 0, 0);
+ tree fn;
+ if (targets.length () == 1)
+ fn = targets[0]->decl;
+ else
+ fn = builtin_decl_implicit (BUILT_IN_UNREACHABLE);
+ if (dump_enabled_p ())
+ {
+ location_t loc = gimple_location_safe (stmt);
+ dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, loc,
+ "converting indirect call to "
+ "function %s\n",
+ cgraph_node::get (fn)->name ());
+ }
+ gimple_call_set_fndecl (call_stmt, fn);
+ maybe_remove_unused_call_args (cfun, call_stmt);
+ gimple_set_modified (stmt, true);
}
+ }
+ }
- gimple_call_set_fn (stmt, fn);
- el_to_update.safe_push (stmt);
-
+ if (gimple_modified_p (stmt))
+ {
+ /* If a formerly non-invariant ADDR_EXPR is turned into an
+ invariant one it was on a separate stmt. */
+ if (gimple_assign_single_p (stmt)
+ && TREE_CODE (gimple_assign_rhs1 (stmt)) == ADDR_EXPR)
+ recompute_tree_invariant_for_addr_expr (gimple_assign_rhs1 (stmt));
+ gimple old_stmt = stmt;
+ if (is_gimple_call (stmt))
+ {
+ /* ??? Only fold calls inplace for now, this may create new
+ SSA names which in turn will confuse free_scc_vn SSA name
+ release code. */
+ fold_stmt_inplace (&gsi);
/* When changing a call into a noreturn call, cfg cleanup
is needed to fix up the noreturn call. */
if (!was_noreturn && gimple_call_noreturn_p (stmt))
+ el_to_fixup.safe_push (stmt);
+ }
+ else
+ {
+ fold_stmt (&gsi);
+ stmt = gsi_stmt (gsi);
+ if ((gimple_code (stmt) == GIMPLE_COND
+ && (gimple_cond_true_p (as_a <gcond *> (stmt))
+ || gimple_cond_false_p (as_a <gcond *> (stmt))))
+ || (gimple_code (stmt) == GIMPLE_SWITCH
+ && TREE_CODE (gimple_switch_index (
+ as_a <gswitch *> (stmt)))
+ == INTEGER_CST))
el_todo |= TODO_cleanup_cfg;
+ }
+ /* If we removed EH side-effects from the statement, clean
+ its EH information. */
+ if (maybe_clean_or_replace_eh_stmt (old_stmt, stmt))
+ {
+ bitmap_set_bit (need_eh_cleanup,
+ gimple_bb (stmt)->index);
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ fprintf (dump_file, " Removed EH side-effects.\n");
+ }
+ /* Likewise for AB side-effects. */
+ if (can_make_abnormal_goto
+ && !stmt_can_make_abnormal_goto (stmt))
+ {
+ bitmap_set_bit (need_ab_cleanup,
+ gimple_bb (stmt)->index);
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ fprintf (dump_file, " Removed AB side-effects.\n");
+ }
+ update_stmt (stmt);
+ if (vdef != gimple_vdef (stmt))
+ VN_INFO (vdef)->valnum = vuse;
+ }
- /* If we removed EH side-effects from the statement, clean
- its EH information. */
- if (maybe_clean_or_replace_eh_stmt (stmt, stmt))
- {
- bitmap_set_bit (need_eh_cleanup,
- gimple_bb (stmt)->index);
- if (dump_file && (dump_flags & TDF_DETAILS))
- fprintf (dump_file, " Removed EH side-effects.\n");
- }
-
- /* Likewise for AB side-effects. */
- if (can_make_abnormal_goto
- && !stmt_can_make_abnormal_goto (stmt))
- {
- bitmap_set_bit (need_ab_cleanup,
- gimple_bb (stmt)->index);
- if (dump_file && (dump_flags & TDF_DETAILS))
- fprintf (dump_file, " Removed AB side-effects.\n");
- }
+ /* Make new values available - for fully redundant LHS we
+ continue with the next stmt above and skip this. */
+ def_operand_p defp;
+ FOR_EACH_SSA_DEF_OPERAND (defp, stmt, iter, SSA_OP_DEF)
+ eliminate_push_avail (DEF_FROM_PTR (defp));
+ }
- /* Changing an indirect call to a direct call may
- have exposed different semantics. This may
- require an SSA update. */
- el_todo |= TODO_update_ssa_only_virtuals;
+ /* Replace destination PHI arguments. */
+ edge_iterator ei;
+ edge e;
+ FOR_EACH_EDGE (e, ei, b->succs)
+ {
+ for (gphi_iterator gsi = gsi_start_phis (e->dest);
+ !gsi_end_p (gsi);
+ gsi_next (&gsi))
+ {
+ gphi *phi = gsi.phi ();
+ use_operand_p use_p = PHI_ARG_DEF_PTR_FROM_EDGE (phi, e);
+ tree arg = USE_FROM_PTR (use_p);
+ if (TREE_CODE (arg) != SSA_NAME
+ || virtual_operand_p (arg))
+ continue;
+ tree sprime = eliminate_avail (arg);
+ if (sprime && may_propagate_copy (arg, sprime))
+ {
+ propagate_value (use_p, sprime);
+ if (TREE_CODE (sprime) == SSA_NAME)
+ gimple_set_plf (SSA_NAME_DEF_STMT (sprime), NECESSARY, true);
}
}
}
/* Make no longer available leaders no longer available. */
-static void
-eliminate_leave_block (dom_walk_data *, basic_block)
+void
+eliminate_dom_walker::after_dom_children (basic_block)
{
tree entry;
while ((entry = el_avail_stack.pop ()) != NULL_TREE)
- el_avail[SSA_NAME_VERSION (VN_INFO (entry)->valnum)] = NULL_TREE;
+ {
+ tree valnum = VN_INFO (entry)->valnum;
+ tree old = el_avail[SSA_NAME_VERSION (valnum)];
+ if (old == entry)
+ el_avail[SSA_NAME_VERSION (valnum)] = NULL_TREE;
+ else
+ el_avail[SSA_NAME_VERSION (valnum)] = entry;
+ }
}
/* Eliminate fully redundant computations. */
static unsigned int
-eliminate (void)
+eliminate (bool do_pre)
{
- struct dom_walk_data walk_data;
gimple_stmt_iterator gsi;
gimple stmt;
- unsigned i;
need_eh_cleanup = BITMAP_ALLOC (NULL);
need_ab_cleanup = BITMAP_ALLOC (NULL);
el_to_remove.create (0);
- el_to_update.create (0);
+ el_to_fixup.create (0);
el_todo = 0;
- el_avail.create (0);
+ el_avail.create (num_ssa_names);
el_avail_stack.create (0);
- walk_data.dom_direction = CDI_DOMINATORS;
- walk_data.initialize_block_local_data = NULL;
- walk_data.before_dom_children = eliminate_bb;
- walk_data.after_dom_children = eliminate_leave_block;
- walk_data.global_data = NULL;
- walk_data.block_local_data_size = 0;
- init_walk_dominator_tree (&walk_data);
- walk_dominator_tree (&walk_data, ENTRY_BLOCK_PTR);
- fini_walk_dominator_tree (&walk_data);
+ eliminate_dom_walker (CDI_DOMINATORS,
+ do_pre).walk (cfun->cfg->x_entry_block_ptr);
el_avail.release ();
el_avail_stack.release ();
/* We cannot remove stmts during BB walk, especially not release SSA
names there as this confuses the VN machinery. The stmts ending
- up in el_to_remove are either stores or simple copies. */
- FOR_EACH_VEC_ELT (el_to_remove, i, stmt)
+ up in el_to_remove are either stores or simple copies.
+ Remove stmts in reverse order to make debug stmt creation possible. */
+ while (!el_to_remove.is_empty ())
{
- tree lhs = gimple_assign_lhs (stmt);
- tree rhs = gimple_assign_rhs1 (stmt);
- use_operand_p use_p;
- gimple use_stmt;
-
- /* If there is a single use only, propagate the equivalency
- instead of keeping the copy. */
- if (TREE_CODE (lhs) == SSA_NAME
- && TREE_CODE (rhs) == SSA_NAME
- && single_imm_use (lhs, &use_p, &use_stmt)
- && may_propagate_copy (USE_FROM_PTR (use_p), rhs))
+ stmt = el_to_remove.pop ();
+
+ if (dump_file && (dump_flags & TDF_DETAILS))
{
- SET_USE (use_p, rhs);
- update_stmt (use_stmt);
- if (inserted_exprs
- && bitmap_bit_p (inserted_exprs, SSA_NAME_VERSION (lhs))
- && TREE_CODE (rhs) == SSA_NAME)
- gimple_set_plf (SSA_NAME_DEF_STMT (rhs), NECESSARY, true);
+ fprintf (dump_file, "Removing dead stmt ");
+ print_gimple_stmt (dump_file, stmt, 0, 0);
}
- /* If this is a store or a now unused copy, remove it. */
- if (TREE_CODE (lhs) != SSA_NAME
- || has_zero_uses (lhs))
+ tree lhs;
+ if (gimple_code (stmt) == GIMPLE_PHI)
+ lhs = gimple_phi_result (stmt);
+ else
+ lhs = gimple_get_lhs (stmt);
+
+ if (inserted_exprs
+ && TREE_CODE (lhs) == SSA_NAME)
+ bitmap_clear_bit (inserted_exprs, SSA_NAME_VERSION (lhs));
+
+ gsi = gsi_for_stmt (stmt);
+ if (gimple_code (stmt) == GIMPLE_PHI)
+ remove_phi_node (&gsi, true);
+ else
{
basic_block bb = gimple_bb (stmt);
- gsi = gsi_for_stmt (stmt);
unlink_stmt_vdef (stmt);
if (gsi_remove (&gsi, true))
bitmap_set_bit (need_eh_cleanup, bb->index);
- if (inserted_exprs
- && TREE_CODE (lhs) == SSA_NAME)
- bitmap_clear_bit (inserted_exprs, SSA_NAME_VERSION (lhs));
release_defs (stmt);
}
+
+ /* Removing a stmt may expose a forwarder block. */
+ el_todo |= TODO_cleanup_cfg;
}
el_to_remove.release ();
- /* We cannot update call statements with virtual operands during
- SSA walk. This might remove them which in turn makes our
- VN lattice invalid. */
- FOR_EACH_VEC_ELT (el_to_update, i, stmt)
- update_stmt (stmt);
- el_to_update.release ();
+ /* Fixup stmts that became noreturn calls. This may require splitting
+ blocks and thus isn't possible during the dominator walk. Do this
+ in reverse order so we don't inadvertedly remove a stmt we want to
+ fixup by visiting a dominating now noreturn call first. */
+ while (!el_to_fixup.is_empty ())
+ {
+ stmt = el_to_fixup.pop ();
+
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "Fixing up noreturn call ");
+ print_gimple_stmt (dump_file, stmt, 0, 0);
+ }
+
+ if (fixup_noreturn_call (stmt))
+ el_todo |= TODO_cleanup_cfg;
+ }
+ el_to_fixup.release ();
return el_todo;
}
expressions.create (0);
expressions.safe_push (NULL);
value_expressions.create (get_max_value_id () + 1);
- value_expressions.safe_grow_cleared (get_max_value_id() + 1);
+ value_expressions.safe_grow_cleared (get_max_value_id () + 1);
name_to_id.create (0);
inserted_exprs = BITMAP_ALLOC (NULL);
connect_infinite_loops_to_exit ();
memset (&pre_stats, 0, sizeof (pre_stats));
- postorder = XNEWVEC (int, n_basic_blocks);
+ postorder = XNEWVEC (int, n_basic_blocks_for_fn (cfun));
postorder_num = inverted_post_order_compute (postorder);
alloc_aux_for_blocks (sizeof (struct bb_bitmap_sets));
calculate_dominance_info (CDI_DOMINATORS);
bitmap_obstack_initialize (&grand_bitmap_obstack);
- phi_translate_table.create (5110);
- expression_to_id.create (num_ssa_names * 3);
- bitmap_set_pool = create_alloc_pool ("Bitmap sets",
- sizeof (struct bitmap_set), 30);
- pre_expr_pool = create_alloc_pool ("pre_expr nodes",
- sizeof (struct pre_expr_d), 30);
- FOR_ALL_BB (bb)
+ phi_translate_table = new hash_table<expr_pred_trans_d> (5110);
+ expression_to_id = new hash_table<pre_expr_d> (num_ssa_names * 3);
+ FOR_ALL_BB_FN (bb, cfun)
{
EXP_GEN (bb) = bitmap_set_new ();
PHI_GEN (bb) = bitmap_set_new ();
value_expressions.release ();
BITMAP_FREE (inserted_exprs);
bitmap_obstack_release (&grand_bitmap_obstack);
- free_alloc_pool (bitmap_set_pool);
- free_alloc_pool (pre_expr_pool);
- phi_translate_table.dispose ();
- expression_to_id.dispose ();
+ bitmap_set_pool.release ();
+ pre_expr_pool.release ();
+ delete phi_translate_table;
+ phi_translate_table = NULL;
+ delete expression_to_id;
+ expression_to_id = NULL;
name_to_id.release ();
free_aux_for_blocks ();
free_dominance_info (CDI_POST_DOMINATORS);
}
-/* Gate and execute functions for PRE. */
+namespace {
-static unsigned int
-do_pre (void)
+const pass_data pass_data_pre =
+{
+ GIMPLE_PASS, /* type */
+ "pre", /* name */
+ OPTGROUP_NONE, /* optinfo_flags */
+ TV_TREE_PRE, /* tv_id */
+ /* PROP_no_crit_edges is ensured by placing pass_split_crit_edges before
+ pass_pre. */
+ ( PROP_no_crit_edges | PROP_cfg | PROP_ssa ), /* properties_required */
+ 0, /* properties_provided */
+ PROP_no_crit_edges, /* properties_destroyed */
+ TODO_rebuild_alias, /* todo_flags_start */
+ 0, /* todo_flags_finish */
+};
+
+class pass_pre : public gimple_opt_pass
+{
+public:
+ pass_pre (gcc::context *ctxt)
+ : gimple_opt_pass (pass_data_pre, ctxt)
+ {}
+
+ /* opt_pass methods: */
+ virtual bool gate (function *) { return flag_tree_pre != 0; }
+ virtual unsigned int execute (function *);
+
+}; // class pass_pre
+
+unsigned int
+pass_pre::execute (function *fun)
{
unsigned int todo = 0;
do_partial_partial =
- flag_tree_partial_pre && optimize_function_for_speed_p (cfun);
+ flag_tree_partial_pre && optimize_function_for_speed_p (fun);
/* This has to happen before SCCVN runs because
loop_optimizer_init may create new phis, etc. */
fixed, don't run it when he have an incredibly large number of
bb's. If we aren't going to run insert, there is no point in
computing ANTIC, either, even though it's plenty fast. */
- if (n_basic_blocks < 4000)
+ if (n_basic_blocks_for_fn (fun) < 4000)
{
compute_antic ();
insert ();
remove_fake_exit_edges ();
gsi_commit_edge_inserts ();
+ /* Eliminate folds statements which might (should not...) end up
+ not keeping virtual operands up-to-date. */
+ gcc_assert (!need_ssa_update_p (fun));
+
/* Remove all the redundant expressions. */
- todo |= eliminate ();
+ todo |= eliminate (true);
- statistics_counter_event (cfun, "Insertions", pre_stats.insertions);
- statistics_counter_event (cfun, "PA inserted", pre_stats.pa_insert);
- statistics_counter_event (cfun, "New PHIs", pre_stats.phis);
- statistics_counter_event (cfun, "Eliminated", pre_stats.eliminations);
- statistics_counter_event (cfun, "Constified", pre_stats.constified);
+ statistics_counter_event (fun, "Insertions", pre_stats.insertions);
+ statistics_counter_event (fun, "PA inserted", pre_stats.pa_insert);
+ statistics_counter_event (fun, "New PHIs", pre_stats.phis);
+ statistics_counter_event (fun, "Eliminated", pre_stats.eliminations);
clear_expression_ids ();
remove_dead_inserted_code ();
- todo |= TODO_verify_flow;
scev_finalize ();
fini_pre ();
return todo;
}
-static bool
-gate_pre (void)
+} // anon namespace
+
+gimple_opt_pass *
+make_pass_pre (gcc::context *ctxt)
{
- return flag_tree_pre != 0;
+ return new pass_pre (ctxt);
}
-struct gimple_opt_pass pass_pre =
+namespace {
+
+const pass_data pass_data_fre =
{
- {
- GIMPLE_PASS,
- "pre", /* name */
- OPTGROUP_NONE, /* optinfo_flags */
- gate_pre, /* gate */
- do_pre, /* execute */
- NULL, /* sub */
- NULL, /* next */
- 0, /* static_pass_number */
- TV_TREE_PRE, /* tv_id */
- PROP_no_crit_edges | PROP_cfg
- | PROP_ssa, /* properties_required */
- 0, /* properties_provided */
- 0, /* properties_destroyed */
- TODO_rebuild_alias, /* todo_flags_start */
- TODO_ggc_collect | TODO_verify_ssa /* todo_flags_finish */
- }
+ GIMPLE_PASS, /* type */
+ "fre", /* name */
+ OPTGROUP_NONE, /* optinfo_flags */
+ TV_TREE_FRE, /* tv_id */
+ ( PROP_cfg | PROP_ssa ), /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ 0, /* todo_flags_finish */
};
+class pass_fre : public gimple_opt_pass
+{
+public:
+ pass_fre (gcc::context *ctxt)
+ : gimple_opt_pass (pass_data_fre, ctxt)
+ {}
-/* Gate and execute functions for FRE. */
+ /* opt_pass methods: */
+ opt_pass * clone () { return new pass_fre (m_ctxt); }
+ virtual bool gate (function *) { return flag_tree_fre != 0; }
+ virtual unsigned int execute (function *);
-static unsigned int
-execute_fre (void)
+}; // class pass_fre
+
+unsigned int
+pass_fre::execute (function *fun)
{
unsigned int todo = 0;
memset (&pre_stats, 0, sizeof (pre_stats));
/* Remove all the redundant expressions. */
- todo |= eliminate ();
+ todo |= eliminate (false);
todo |= fini_eliminate ();
free_scc_vn ();
- statistics_counter_event (cfun, "Insertions", pre_stats.insertions);
- statistics_counter_event (cfun, "Eliminated", pre_stats.eliminations);
- statistics_counter_event (cfun, "Constified", pre_stats.constified);
+ statistics_counter_event (fun, "Insertions", pre_stats.insertions);
+ statistics_counter_event (fun, "Eliminated", pre_stats.eliminations);
return todo;
}
-static bool
-gate_fre (void)
-{
- return flag_tree_fre != 0;
-}
+} // anon namespace
-struct gimple_opt_pass pass_fre =
+gimple_opt_pass *
+make_pass_fre (gcc::context *ctxt)
{
- {
- GIMPLE_PASS,
- "fre", /* name */
- OPTGROUP_NONE, /* optinfo_flags */
- gate_fre, /* gate */
- execute_fre, /* execute */
- NULL, /* sub */
- NULL, /* next */
- 0, /* static_pass_number */
- TV_TREE_FRE, /* tv_id */
- PROP_cfg | PROP_ssa, /* properties_required */
- 0, /* properties_provided */
- 0, /* properties_destroyed */
- 0, /* todo_flags_start */
- TODO_ggc_collect | TODO_verify_ssa /* todo_flags_finish */
- }
-};
+ return new pass_fre (ctxt);
+}