Index: gcc/gcc/tree-ssa-pre.c |
diff --git a/gcc/gcc/tree-ssa-pre.c b/gcc/gcc/tree-ssa-pre.c |
index c9e70003de6e1b7ae51c70158f15961a59ee57c7..04177f9267ed4034c62866c30c6cee3e7781c85f 100644 |
--- a/gcc/gcc/tree-ssa-pre.c |
+++ b/gcc/gcc/tree-ssa-pre.c |
@@ -1,5 +1,5 @@ |
/* SSA-PRE for trees. |
- Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 |
+ Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 |
Free Software Foundation, Inc. |
Contributed by Daniel Berlin <dan@dberlin.org> and Steven Bosscher |
<stevenb@suse.de> |
@@ -45,6 +45,7 @@ along with GCC; see the file COPYING3. If not see |
#include "langhooks.h" |
#include "cfgloop.h" |
#include "tree-ssa-sccvn.h" |
+#include "tree-scalar-evolution.h" |
#include "params.h" |
#include "dbgcnt.h" |
@@ -134,7 +135,7 @@ along with GCC; see the file COPYING3. If not see |
/* Representation of expressions on value numbers: |
- Expressions consisting of value numbers are represented the same |
+ Expressions consisting of value numbers are represented the same |
way as our VN internally represents them, with an additional |
"pre_expr" wrapping around them in order to facilitate storing all |
of the expressions in the same sets. */ |
@@ -203,7 +204,7 @@ pre_expr_eq (const void *p1, const void *p2) |
return vn_reference_eq (PRE_EXPR_REFERENCE (e1), |
PRE_EXPR_REFERENCE (e2)); |
default: |
- abort(); |
+ gcc_unreachable (); |
} |
} |
@@ -216,13 +217,13 @@ pre_expr_hash (const void *p1) |
case CONSTANT: |
return vn_hash_constant_with_type (PRE_EXPR_CONSTANT (e)); |
case NAME: |
- return iterative_hash_hashval_t (SSA_NAME_VERSION (PRE_EXPR_NAME (e)), 0); |
+ return SSA_NAME_VERSION (PRE_EXPR_NAME (e)); |
case NARY: |
return PRE_EXPR_NARY (e)->hashcode; |
case REFERENCE: |
return PRE_EXPR_REFERENCE (e)->hashcode; |
default: |
- abort (); |
+ gcc_unreachable (); |
} |
} |
@@ -235,6 +236,7 @@ DEF_VEC_P (pre_expr); |
DEF_VEC_ALLOC_P (pre_expr, heap); |
static VEC(pre_expr, heap) *expressions; |
static htab_t expression_to_id; |
+static VEC(unsigned, heap) *name_to_id; |
/* Allocate an expression id for EXPR. */ |
@@ -246,9 +248,23 @@ alloc_expression_id (pre_expr expr) |
gcc_assert (next_expression_id + 1 > next_expression_id); |
expr->id = next_expression_id++; |
VEC_safe_push (pre_expr, heap, expressions, expr); |
- slot = htab_find_slot (expression_to_id, expr, INSERT); |
- gcc_assert (!*slot); |
- *slot = expr; |
+ if (expr->kind == NAME) |
+ { |
+ 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. */ |
+ VEC_reserve (unsigned, heap, name_to_id, num_ssa_names); |
+ VEC_safe_grow_cleared (unsigned, heap, name_to_id, num_ssa_names); |
+ gcc_assert (VEC_index (unsigned, name_to_id, version) == 0); |
+ VEC_replace (unsigned, name_to_id, version, expr->id); |
+ } |
+ else |
+ { |
+ slot = htab_find_slot (expression_to_id, expr, INSERT); |
+ gcc_assert (!*slot); |
+ *slot = expr; |
+ } |
return next_expression_id - 1; |
} |
@@ -265,10 +281,20 @@ lookup_expression_id (const pre_expr expr) |
{ |
void **slot; |
- slot = htab_find_slot (expression_to_id, expr, NO_INSERT); |
- if (!slot) |
- return 0; |
- return ((pre_expr)*slot)->id; |
+ if (expr->kind == NAME) |
+ { |
+ unsigned version = SSA_NAME_VERSION (PRE_EXPR_NAME (expr)); |
+ if (VEC_length (unsigned, name_to_id) <= version) |
+ return 0; |
+ return VEC_index (unsigned, name_to_id, version); |
+ } |
+ else |
+ { |
+ slot = htab_find_slot (expression_to_id, expr, NO_INSERT); |
+ if (!slot) |
+ return 0; |
+ return ((pre_expr)*slot)->id; |
+ } |
} |
/* Return the existing expression id for EXPR, or create one if one |
@@ -307,20 +333,21 @@ static alloc_pool pre_expr_pool; |
static pre_expr |
get_or_alloc_expr_for_name (tree name) |
{ |
- pre_expr result = (pre_expr) pool_alloc (pre_expr_pool); |
+ struct pre_expr_d expr; |
+ pre_expr result; |
unsigned int result_id; |
+ expr.kind = NAME; |
+ expr.id = 0; |
+ PRE_EXPR_NAME (&expr) = name; |
+ result_id = lookup_expression_id (&expr); |
+ if (result_id != 0) |
+ return expression_for_id (result_id); |
+ |
+ result = (pre_expr) pool_alloc (pre_expr_pool); |
result->kind = NAME; |
- result->id = 0; |
PRE_EXPR_NAME (result) = name; |
- result_id = lookup_expression_id (result); |
- if (result_id != 0) |
- { |
- pool_free (pre_expr_pool, result); |
- result = expression_for_id (result_id); |
- return result; |
- } |
- get_or_alloc_expression_id (result); |
+ alloc_expression_id (result); |
return result; |
} |
@@ -377,12 +404,18 @@ typedef struct bb_bitmap_sets |
the current iteration. */ |
bitmap_set_t new_sets; |
+ /* A cache for value_dies_in_block_x. */ |
+ bitmap expr_dies; |
+ |
/* True if we have visited this block during ANTIC calculation. */ |
- unsigned int visited:1; |
+ 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 EXP_GEN(BB) ((bb_value_sets_t) ((BB)->aux))->exp_gen |
@@ -392,8 +425,10 @@ typedef struct bb_bitmap_sets |
#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 BB_VISITED(BB) ((bb_value_sets_t) ((BB)->aux))->visited |
+#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 |
/* Basic block list in postorder. */ |
@@ -427,7 +462,8 @@ static void bitmap_value_replace_in_set (bitmap_set_t, pre_expr); |
static void bitmap_set_copy (bitmap_set_t, bitmap_set_t); |
static bool bitmap_set_contains_value (bitmap_set_t, unsigned int); |
static void bitmap_insert_into_set (bitmap_set_t, pre_expr); |
-static void bitmap_insert_into_set_1 (bitmap_set_t, pre_expr, bool); |
+static void bitmap_insert_into_set_1 (bitmap_set_t, pre_expr, |
+ unsigned int, bool); |
static bitmap_set_t bitmap_set_new (void); |
static tree create_expression_by_pieces (basic_block, pre_expr, gimple_seq *, |
gimple, tree); |
@@ -571,7 +607,7 @@ add_to_value (unsigned int v, pre_expr e) |
VEC_replace (bitmap_set_t, value_expressions, v, set); |
} |
- bitmap_insert_into_set_1 (set, e, true); |
+ bitmap_insert_into_set_1 (set, e, v, true); |
} |
/* Create a new bitmap set and return it. */ |
@@ -629,9 +665,8 @@ bitmap_remove_from_set (bitmap_set_t set, pre_expr expr) |
static void |
bitmap_insert_into_set_1 (bitmap_set_t set, pre_expr expr, |
- bool allow_constants) |
+ unsigned int val, bool allow_constants) |
{ |
- unsigned int val = get_expr_value_id (expr); |
if (allow_constants || !value_id_constant_p (val)) |
{ |
/* We specifically expect this and only this function to be able to |
@@ -646,7 +681,7 @@ bitmap_insert_into_set_1 (bitmap_set_t set, pre_expr expr, |
static void |
bitmap_insert_into_set (bitmap_set_t set, pre_expr expr) |
{ |
- bitmap_insert_into_set_1 (set, expr, false); |
+ bitmap_insert_into_set_1 (set, expr, get_expr_value_id (expr), false); |
} |
/* Copy a bitmapped set ORIG, into bitmapped set DEST. */ |
@@ -675,7 +710,10 @@ sorted_array_from_bitmap_set (bitmap_set_t set) |
{ |
unsigned int i, j; |
bitmap_iterator bi, bj; |
- VEC(pre_expr, heap) *result = NULL; |
+ VEC(pre_expr, heap) *result; |
+ |
+ /* Pre-allocate roughly enough space for the array. */ |
+ result = VEC_alloc (pre_expr, heap, bitmap_count_bits (set->values)); |
FOR_EACH_VALUE_ID_IN_SET (set, i, bi) |
{ |
@@ -854,11 +892,17 @@ bitmap_value_insert_into_set (bitmap_set_t set, pre_expr expr) |
{ |
unsigned int val = get_expr_value_id (expr); |
+#ifdef ENABLE_CHECKING |
+ gcc_assert (expr->id == get_or_alloc_expression_id (expr)); |
+#endif |
+ |
+ /* Constant values are always considered to be part of the set. */ |
if (value_id_constant_p (val)) |
return; |
- if (!bitmap_set_contains_value (set, val)) |
- bitmap_insert_into_set (set, expr); |
+ /* If the value membership changed, add the expression. */ |
+ if (bitmap_set_bit (set->values, val)) |
+ bitmap_set_bit (set->expressions, expr->id); |
} |
/* Print out EXPR to outfile. */ |
@@ -899,26 +943,42 @@ print_pre_expr (FILE *outfile, const pre_expr expr) |
VEC_iterate (vn_reference_op_s, ref->operands, i, vro); |
i++) |
{ |
+ bool closebrace = false; |
if (vro->opcode != SSA_NAME |
&& TREE_CODE_CLASS (vro->opcode) != tcc_declaration) |
- fprintf (outfile, "%s ", tree_code_name [vro->opcode]); |
+ { |
+ fprintf (outfile, "%s", tree_code_name [vro->opcode]); |
+ if (vro->op0) |
+ { |
+ fprintf (outfile, "<"); |
+ closebrace = true; |
+ } |
+ } |
if (vro->op0) |
{ |
- if (vro->op1) |
- fprintf (outfile, "<"); |
print_generic_expr (outfile, vro->op0, 0); |
if (vro->op1) |
{ |
fprintf (outfile, ","); |
print_generic_expr (outfile, vro->op1, 0); |
} |
- if (vro->op1) |
- fprintf (outfile, ">"); |
+ if (vro->op2) |
+ { |
+ fprintf (outfile, ","); |
+ print_generic_expr (outfile, vro->op2, 0); |
+ } |
} |
+ if (closebrace) |
+ fprintf (outfile, ">"); |
if (i != VEC_length (vn_reference_op_s, ref->operands) - 1) |
fprintf (outfile, ","); |
} |
fprintf (outfile, "}"); |
+ if (ref->vuse) |
+ { |
+ fprintf (outfile, "@"); |
+ print_generic_expr (outfile, ref->vuse, 0); |
+ } |
} |
break; |
} |
@@ -998,18 +1058,20 @@ get_or_alloc_expr_for_constant (tree constant) |
{ |
unsigned int result_id; |
unsigned int value_id; |
- pre_expr newexpr = (pre_expr) pool_alloc (pre_expr_pool); |
+ struct pre_expr_d expr; |
+ pre_expr newexpr; |
+ |
+ expr.kind = CONSTANT; |
+ PRE_EXPR_CONSTANT (&expr) = constant; |
+ result_id = lookup_expression_id (&expr); |
+ if (result_id != 0) |
+ return expression_for_id (result_id); |
+ |
+ newexpr = (pre_expr) pool_alloc (pre_expr_pool); |
newexpr->kind = CONSTANT; |
PRE_EXPR_CONSTANT (newexpr) = constant; |
- result_id = lookup_expression_id (newexpr); |
- if (result_id != 0) |
- { |
- pool_free (pre_expr_pool, newexpr); |
- newexpr = expression_for_id (result_id); |
- return newexpr; |
- } |
+ alloc_expression_id (newexpr); |
value_id = get_or_alloc_constant_value_id (constant); |
- get_or_alloc_expression_id (newexpr); |
add_to_value (value_id, newexpr); |
return newexpr; |
} |
@@ -1132,7 +1194,7 @@ fully_constant_expression (pre_expr e) |
} |
case tcc_reference: |
if (nary->opcode != REALPART_EXPR |
- && nary->opcode != IMAGPART_EXPR |
+ && nary->opcode != IMAGPART_EXPR |
&& nary->opcode != VIEW_CONVERT_EXPR) |
return e; |
/* Fallthrough. */ |
@@ -1218,51 +1280,81 @@ do_unary: |
return e; |
} |
-/* Translate the vuses in the VUSES vector backwards through phi nodes |
- in PHIBLOCK, so that they have the value they would have in |
- BLOCK. */ |
+/* Translate the VUSE backwards through phi nodes in PHIBLOCK, so that |
+ it has the value it would have in BLOCK. Set *SAME_VALID to true |
+ in case the new vuse doesn't change the value id of the OPERANDS. */ |
-static VEC(tree, gc) * |
-translate_vuses_through_block (VEC (tree, gc) *vuses, |
- basic_block phiblock, |
- basic_block block) |
+static tree |
+translate_vuse_through_block (VEC (vn_reference_op_s, heap) *operands, |
+ alias_set_type set, tree type, tree vuse, |
+ basic_block phiblock, |
+ basic_block block, bool *same_valid) |
{ |
- tree oldvuse; |
- VEC(tree, gc) *result = NULL; |
- int i; |
+ gimple phi = SSA_NAME_DEF_STMT (vuse); |
+ ao_ref ref; |
+ edge e = NULL; |
+ bool use_oracle; |
+ |
+ *same_valid = true; |
+ |
+ if (gimple_bb (phi) != phiblock) |
+ return vuse; |
- for (i = 0; VEC_iterate (tree, vuses, i, oldvuse); i++) |
+ use_oracle = ao_ref_init_from_vn_reference (&ref, set, type, operands); |
+ |
+ /* Use the alias-oracle to find either the PHI node in this block, |
+ the first VUSE used in this block that is equivalent to vuse or |
+ the first VUSE which definition in this block kills the value. */ |
+ if (gimple_code (phi) == GIMPLE_PHI) |
+ e = find_edge (block, phiblock); |
+ else if (use_oracle) |
+ while (!stmt_may_clobber_ref_p_1 (phi, &ref)) |
+ { |
+ vuse = gimple_vuse (phi); |
+ phi = SSA_NAME_DEF_STMT (vuse); |
+ if (gimple_bb (phi) != phiblock) |
+ return vuse; |
+ if (gimple_code (phi) == GIMPLE_PHI) |
+ { |
+ e = find_edge (block, phiblock); |
+ break; |
+ } |
+ } |
+ else |
+ return NULL_TREE; |
+ |
+ if (e) |
{ |
- gimple phi = SSA_NAME_DEF_STMT (oldvuse); |
- if (gimple_code (phi) == GIMPLE_PHI |
- && gimple_bb (phi) == phiblock) |
+ if (use_oracle) |
{ |
- edge e = find_edge (block, gimple_bb (phi)); |
- if (e) |
- { |
- tree def = PHI_ARG_DEF (phi, e->dest_idx); |
- if (def != oldvuse) |
- { |
- if (!result) |
- result = VEC_copy (tree, gc, vuses); |
- VEC_replace (tree, result, i, def); |
- } |
- } |
+ bitmap visited = NULL; |
+ /* Try to find a vuse that dominates this phi node by skipping |
+ non-clobbering statements. */ |
+ vuse = get_continuation_for_phi (phi, &ref, &visited); |
+ if (visited) |
+ BITMAP_FREE (visited); |
} |
+ else |
+ vuse = NULL_TREE; |
+ if (!vuse) |
+ { |
+ /* If we didn't find any, the value ID can't stay the same, |
+ but return the translated vuse. */ |
+ *same_valid = false; |
+ vuse = PHI_ARG_DEF (phi, e->dest_idx); |
+ } |
+ /* ??? We would like to return vuse here as this is the canonical |
+ upmost vdef that this reference is associated with. But during |
+ insertion of the references into the hash tables we only ever |
+ directly insert with their direct gimple_vuse, hence returning |
+ something else would make us not find the other expression. */ |
+ return PHI_ARG_DEF (phi, e->dest_idx); |
} |
- /* We avoid creating a new copy of the vuses unless something |
- actually changed, so result can be NULL. */ |
- if (result) |
- { |
- sort_vuses (result); |
- return result; |
- } |
- return vuses; |
- |
+ return NULL_TREE; |
} |
-/* Like find_leader, but checks for the value existing in SET1 *or* |
+/* Like bitmap_find_leader, but checks for the value existing in SET1 *or* |
SET2. This is used to avoid making a set consisting of the union |
of PA_IN and ANTIC_IN during insert. */ |
@@ -1289,23 +1381,7 @@ get_expr_type (const pre_expr e) |
case CONSTANT: |
return TREE_TYPE (PRE_EXPR_CONSTANT (e)); |
case REFERENCE: |
- { |
- vn_reference_op_t vro; |
- |
- gcc_assert (PRE_EXPR_REFERENCE (e)->operands); |
- vro = VEC_index (vn_reference_op_s, |
- PRE_EXPR_REFERENCE (e)->operands, |
- 0); |
- /* We don't store type along with COMPONENT_REF because it is |
- always the same as FIELD_DECL's type. */ |
- if (!vro->type) |
- { |
- gcc_assert (vro->opcode == COMPONENT_REF); |
- return TREE_TYPE (vro->op0); |
- } |
- return vro->type; |
- } |
- |
+ return PRE_EXPR_REFERENCE (e)->type; |
case NARY: |
return PRE_EXPR_NARY (e)->type; |
} |
@@ -1395,34 +1471,20 @@ get_representative_for (const pre_expr e) |
+static pre_expr |
+phi_translate (pre_expr expr, bitmap_set_t set1, bitmap_set_t set2, |
+ basic_block pred, basic_block phiblock); |
/* Translate EXPR using phis in PHIBLOCK, so that it has the values of |
the phis in PRED. Return NULL if we can't find a leader for each part |
of the translated expression. */ |
static pre_expr |
-phi_translate (pre_expr expr, bitmap_set_t set1, bitmap_set_t set2, |
- basic_block pred, basic_block phiblock) |
+phi_translate_1 (pre_expr expr, bitmap_set_t set1, bitmap_set_t set2, |
+ basic_block pred, basic_block phiblock) |
{ |
- pre_expr oldexpr = expr; |
- pre_expr phitrans; |
- |
- if (!expr) |
- return NULL; |
- |
- if (value_id_constant_p (get_expr_value_id (expr))) |
- return expr; |
- |
- phitrans = phi_trans_lookup (expr, pred); |
- if (phitrans) |
- return phitrans; |
- |
switch (expr->kind) |
{ |
- /* Constants contain no values that need translation. */ |
- case CONSTANT: |
- return expr; |
- |
case NARY: |
{ |
unsigned int i; |
@@ -1460,6 +1522,7 @@ phi_translate (pre_expr expr, bitmap_set_t set1, bitmap_set_t set2, |
if (changed) |
{ |
pre_expr constant; |
+ unsigned int new_val_id; |
tree result = vn_nary_op_lookup_pieces (newnary.length, |
newnary.opcode, |
@@ -1469,15 +1532,12 @@ phi_translate (pre_expr expr, bitmap_set_t set1, bitmap_set_t set2, |
newnary.op[2], |
newnary.op[3], |
&nary); |
- unsigned int new_val_id; |
+ if (result && is_gimple_min_invariant (result)) |
+ return get_or_alloc_expr_for_constant (result); |
expr = (pre_expr) pool_alloc (pre_expr_pool); |
expr->kind = NARY; |
expr->id = 0; |
- if (result && is_gimple_min_invariant (result)) |
- return get_or_alloc_expr_for_constant (result); |
- |
- |
if (nary) |
{ |
PRE_EXPR_NARY (expr) = nary; |
@@ -1510,7 +1570,6 @@ phi_translate (pre_expr expr, bitmap_set_t set1, bitmap_set_t set2, |
} |
add_to_value (new_val_id, expr); |
} |
- phi_trans_add (oldexpr, expr, pred); |
return expr; |
} |
break; |
@@ -1519,15 +1578,16 @@ phi_translate (pre_expr expr, bitmap_set_t set1, bitmap_set_t set2, |
{ |
vn_reference_t ref = PRE_EXPR_REFERENCE (expr); |
VEC (vn_reference_op_s, heap) *operands = ref->operands; |
- VEC (tree, gc) *vuses = ref->vuses; |
- VEC (tree, gc) *newvuses = vuses; |
+ tree vuse = ref->vuse; |
+ tree newvuse = vuse; |
VEC (vn_reference_op_s, heap) *newoperands = NULL; |
- bool changed = false; |
- unsigned int i; |
+ bool changed = false, same_valid = true; |
+ unsigned int i, j; |
vn_reference_op_t operand; |
vn_reference_t newref; |
- for (i = 0; VEC_iterate (vn_reference_op_s, operands, i, operand); i++) |
+ for (i = 0, j = 0; |
+ VEC_iterate (vn_reference_op_s, operands, i, operand); i++, j++) |
{ |
pre_expr opresult; |
pre_expr leader; |
@@ -1572,6 +1632,9 @@ phi_translate (pre_expr expr, bitmap_set_t set1, bitmap_set_t set2, |
else if (!opresult) |
break; |
} |
+ /* We can't possibly insert these. */ |
+ else if (op1 && !is_gimple_min_invariant (op1)) |
+ break; |
changed |= op1 != oldop1; |
if (op2 && TREE_CODE (op2) == SSA_NAME) |
{ |
@@ -1588,6 +1651,9 @@ phi_translate (pre_expr expr, bitmap_set_t set1, bitmap_set_t set2, |
else if (!opresult) |
break; |
} |
+ /* We can't possibly insert these. */ |
+ else if (op2 && !is_gimple_min_invariant (op2)) |
+ break; |
changed |= op2 != oldop2; |
if (!newoperands) |
@@ -1599,7 +1665,13 @@ phi_translate (pre_expr expr, bitmap_set_t set1, bitmap_set_t set2, |
newop.op0 = op0; |
newop.op1 = op1; |
newop.op2 = op2; |
- VEC_replace (vn_reference_op_s, newoperands, i, &newop); |
+ VEC_replace (vn_reference_op_s, newoperands, j, &newop); |
+ /* If it transforms from an SSA_NAME to an address, fold with |
+ a preceding indirect reference. */ |
+ if (j > 0 && op0 && TREE_CODE (op0) == ADDR_EXPR |
+ && VEC_index (vn_reference_op_s, |
+ newoperands, j - 1)->opcode == INDIRECT_REF) |
+ vn_reference_fold_indirect (&newoperands, &j); |
} |
if (i != VEC_length (vn_reference_op_s, operands)) |
{ |
@@ -1608,15 +1680,26 @@ phi_translate (pre_expr expr, bitmap_set_t set1, bitmap_set_t set2, |
return NULL; |
} |
- newvuses = translate_vuses_through_block (vuses, phiblock, pred); |
- changed |= newvuses != vuses; |
+ if (vuse) |
+ { |
+ newvuse = translate_vuse_through_block (newoperands, |
+ ref->set, ref->type, |
+ vuse, phiblock, pred, |
+ &same_valid); |
+ if (newvuse == NULL_TREE) |
+ { |
+ VEC_free (vn_reference_op_s, heap, newoperands); |
+ return NULL; |
+ } |
+ } |
- if (changed) |
+ if (changed || newvuse != vuse) |
{ |
unsigned int new_val_id; |
pre_expr constant; |
- tree result = vn_reference_lookup_pieces (newvuses, |
+ tree result = vn_reference_lookup_pieces (newvuse, ref->set, |
+ ref->type, |
newoperands, |
&newref, true); |
if (newref) |
@@ -1644,10 +1727,17 @@ phi_translate (pre_expr expr, bitmap_set_t set1, bitmap_set_t set2, |
} |
else |
{ |
- new_val_id = get_next_value_id (); |
- VEC_safe_grow_cleared (bitmap_set_t, heap, value_expressions, |
- get_max_value_id() + 1); |
- newref = vn_reference_insert_pieces (newvuses, |
+ if (changed || !same_valid) |
+ { |
+ new_val_id = get_next_value_id (); |
+ VEC_safe_grow_cleared (bitmap_set_t, heap, |
+ value_expressions, |
+ get_max_value_id() + 1); |
+ } |
+ else |
+ new_val_id = ref->value_id; |
+ newref = vn_reference_insert_pieces (newvuse, ref->set, |
+ ref->type, |
newoperands, |
result, new_val_id); |
newoperands = NULL; |
@@ -1660,7 +1750,6 @@ phi_translate (pre_expr expr, bitmap_set_t set1, bitmap_set_t set2, |
add_to_value (new_val_id, expr); |
} |
VEC_free (vn_reference_op_s, heap, newoperands); |
- phi_trans_add (oldexpr, expr, pred); |
return expr; |
} |
break; |
@@ -1706,6 +1795,44 @@ phi_translate (pre_expr expr, bitmap_set_t set1, bitmap_set_t set2, |
} |
} |
+/* Wrapper around phi_translate_1 providing caching functionality. */ |
+ |
+static pre_expr |
+phi_translate (pre_expr expr, bitmap_set_t set1, bitmap_set_t set2, |
+ basic_block pred, basic_block phiblock) |
+{ |
+ pre_expr phitrans; |
+ |
+ if (!expr) |
+ return NULL; |
+ |
+ /* Constants contain no values that need translation. */ |
+ if (expr->kind == CONSTANT) |
+ return expr; |
+ |
+ if (value_id_constant_p (get_expr_value_id (expr))) |
+ return expr; |
+ |
+ if (expr->kind != NAME) |
+ { |
+ phitrans = phi_trans_lookup (expr, pred); |
+ if (phitrans) |
+ return phitrans; |
+ } |
+ |
+ /* 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); |
+ |
+ return phitrans; |
+} |
+ |
+ |
/* For each expression in SET, translate the values through phi nodes |
in PHIBLOCK using edge PHIBLOCK->PRED, and store the resulting |
expressions in DEST. */ |
@@ -1729,12 +1856,16 @@ phi_translate_set (bitmap_set_t dest, bitmap_set_t set, basic_block pred, |
{ |
pre_expr translated; |
translated = phi_translate (expr, set, NULL, pred, phiblock); |
+ if (!translated) |
+ continue; |
- /* Don't add empty translations to the cache */ |
- if (translated) |
- phi_trans_add (expr, translated, pred); |
- |
- if (translated != NULL) |
+ /* We might end up with multiple expressions from SET being |
+ translated to the same value. In this case we do not want |
+ to retain the NARY or REFERENCE expression but prefer a NAME |
+ which would be the leader. */ |
+ if (translated->kind == NAME) |
+ bitmap_value_replace_in_set (dest, translated); |
+ else |
bitmap_value_insert_into_set (dest, translated); |
} |
VEC_free (pre_expr, heap, exprs); |
@@ -1808,24 +1939,73 @@ bitmap_find_leader (bitmap_set_t set, unsigned int val, gimple stmt) |
static bool |
value_dies_in_block_x (pre_expr expr, basic_block block) |
{ |
- int i; |
- tree vuse; |
- VEC (tree, gc) *vuses = PRE_EXPR_REFERENCE (expr)->vuses; |
+ tree vuse = PRE_EXPR_REFERENCE (expr)->vuse; |
+ vn_reference_t refx = PRE_EXPR_REFERENCE (expr); |
+ gimple def; |
+ gimple_stmt_iterator gsi; |
+ unsigned id = get_expression_id (expr); |
+ bool res = false; |
+ ao_ref ref; |
- /* Conservatively, a value dies if it's vuses are defined in this |
- block, unless they come from phi nodes (which are merge operations, |
- rather than stores. */ |
- for (i = 0; VEC_iterate (tree, vuses, i, vuse); i++) |
+ if (!vuse) |
+ return false; |
+ |
+ /* Lookup a previously calculated result. */ |
+ if (EXPR_DIES (block) |
+ && bitmap_bit_p (EXPR_DIES (block), id * 2)) |
+ return bitmap_bit_p (EXPR_DIES (block), id * 2 + 1); |
+ |
+ /* A memory expression {e, VUSE} dies in the block if there is a |
+ statement that may clobber e. If, starting statement walk from the |
+ top of the basic block, a statement uses VUSE there can be no kill |
+ inbetween that use and the original statement that loaded {e, VUSE}, |
+ so we can stop walking. */ |
+ ref.base = NULL_TREE; |
+ for (gsi = gsi_start_bb (block); !gsi_end_p (gsi); gsi_next (&gsi)) |
{ |
- gimple def = SSA_NAME_DEF_STMT (vuse); |
+ tree def_vuse, def_vdef; |
+ def = gsi_stmt (gsi); |
+ def_vuse = gimple_vuse (def); |
+ def_vdef = gimple_vdef (def); |
- if (gimple_bb (def) != block) |
- continue; |
- if (gimple_code (def) == GIMPLE_PHI) |
+ /* Not a memory statement. */ |
+ if (!def_vuse) |
continue; |
- return true; |
+ |
+ /* Not a may-def. */ |
+ if (!def_vdef) |
+ { |
+ /* A load with the same VUSE, we're done. */ |
+ if (def_vuse == vuse) |
+ break; |
+ |
+ continue; |
+ } |
+ |
+ /* Init ref only if we really need it. */ |
+ if (ref.base == NULL_TREE |
+ && !ao_ref_init_from_vn_reference (&ref, refx->set, refx->type, |
+ refx->operands)) |
+ { |
+ res = true; |
+ break; |
+ } |
+ /* If the statement may clobber expr, it dies. */ |
+ if (stmt_may_clobber_ref_p_1 (def, &ref)) |
+ { |
+ res = true; |
+ break; |
+ } |
} |
- return false; |
+ |
+ /* Remember the result. */ |
+ if (!EXPR_DIES (block)) |
+ EXPR_DIES (block) = BITMAP_ALLOC (&grand_bitmap_obstack); |
+ bitmap_set_bit (EXPR_DIES (block), id * 2); |
+ if (res) |
+ bitmap_set_bit (EXPR_DIES (block), id * 2 + 1); |
+ |
+ return res; |
} |
@@ -1887,8 +2067,7 @@ vro_valid_in_sets (bitmap_set_t set1, bitmap_set_t set2, |
ONLY SET2 CAN BE NULL. |
This means that we have a leader for each part of the expression |
(if it consists of values), or the expression is an SSA_NAME. |
- For loads/calls, we also see if the vuses are killed in this block. |
-*/ |
+ 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, |
@@ -1918,6 +2097,13 @@ valid_in_sets (bitmap_set_t set1, bitmap_set_t set2, pre_expr expr, |
return false; |
} |
} |
+ /* If the NARY may trap make sure the block does not contain |
+ a possible exit point. |
+ ??? This is overly conservative if we translate AVAIL_OUT |
+ as the available expression might be after the exit point. */ |
+ if (BB_MAY_NOTRETURN (block) |
+ && vn_nary_may_trap (nary)) |
+ return false; |
return true; |
} |
break; |
@@ -1932,6 +2118,15 @@ valid_in_sets (bitmap_set_t set1, bitmap_set_t set2, pre_expr expr, |
if (!vro_valid_in_sets (set1, set2, vro)) |
return false; |
} |
+ if (ref->vuse) |
+ { |
+ gimple def_stmt = SSA_NAME_DEF_STMT (ref->vuse); |
+ if (!gimple_nop_p (def_stmt) |
+ && gimple_bb (def_stmt) != block |
+ && !dominated_by_p (CDI_DOMINATORS, |
+ block, gimple_bb (def_stmt))) |
+ return false; |
+ } |
return !value_dies_in_block_x (expr, block); |
} |
default: |
@@ -2346,6 +2541,7 @@ compute_antic (void) |
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 (); |
PA_IN (block) = bitmap_set_new (); |
@@ -2364,7 +2560,7 @@ compute_antic (void) |
fprintf (dump_file, "Starting iteration %d\n", num_iterations); |
num_iterations++; |
changed = false; |
- for (i = 0; i < n_basic_blocks - NUM_FIXED_BLOCKS; i++) |
+ for (i = n_basic_blocks - NUM_FIXED_BLOCKS - 1; i >= 0; i--) |
{ |
if (TEST_BIT (changed_blocks, postorder[i])) |
{ |
@@ -2395,7 +2591,7 @@ compute_antic (void) |
fprintf (dump_file, "Starting iteration %d\n", num_iterations); |
num_iterations++; |
changed = false; |
- for (i = 0; i < n_basic_blocks - NUM_FIXED_BLOCKS; i++) |
+ for (i = n_basic_blocks - NUM_FIXED_BLOCKS - 1 ; i >= 0; i--) |
{ |
if (TEST_BIT (changed_blocks, postorder[i])) |
{ |
@@ -2429,19 +2625,8 @@ can_value_number_call (gimple stmt) |
return false; |
} |
-/* Return true if OP is an exception handler related operation, such as |
- FILTER_EXPR or EXC_PTR_EXPR. */ |
- |
-static bool |
-is_exception_related (gimple stmt) |
-{ |
- return (is_gimple_assign (stmt) |
- && (gimple_assign_rhs_code (stmt) == FILTER_EXPR |
- || gimple_assign_rhs_code (stmt) == EXC_PTR_EXPR)); |
-} |
- |
-/* Return true if OP is a tree which we can perform PRE on |
- on. This may not match the operations we can value number, but in |
+/* Return true if OP is a tree which we can perform PRE on. |
+ This may not match the operations we can value number, but in |
a perfect world would. */ |
static bool |
@@ -2462,6 +2647,7 @@ can_PRE_operation (tree op) |
for performing quick dead code elimination of insertions we made |
that didn't turn out to be necessary. */ |
static VEC(gimple,heap) *inserted_exprs; |
+static bitmap inserted_phi_names; |
/* Pool allocated fake store expressions are placed onto this |
worklist, which, after performing dead code elimination, is walked |
@@ -2483,32 +2669,77 @@ create_component_ref_by_pieces_1 (basic_block block, vn_reference_t ref, |
{ |
case CALL_EXPR: |
{ |
- tree folded, sc = currop->op1; |
+ tree folded, sc = NULL_TREE; |
unsigned int nargs = 0; |
- tree *args = XNEWVEC (tree, VEC_length (vn_reference_op_s, |
- ref->operands) - 1); |
+ tree fn, *args; |
+ if (TREE_CODE (currop->op0) == FUNCTION_DECL) |
+ fn = currop->op0; |
+ else |
+ { |
+ pre_expr op0 = get_or_alloc_expr_for (currop->op0); |
+ fn = find_or_generate_expression (block, op0, stmts, domstmt); |
+ if (!fn) |
+ return NULL_TREE; |
+ } |
+ if (currop->op1) |
+ { |
+ pre_expr scexpr = get_or_alloc_expr_for (currop->op1); |
+ sc = find_or_generate_expression (block, scexpr, stmts, domstmt); |
+ if (!sc) |
+ return NULL_TREE; |
+ } |
+ args = XNEWVEC (tree, VEC_length (vn_reference_op_s, |
+ ref->operands) - 1); |
while (*operand < VEC_length (vn_reference_op_s, ref->operands)) |
{ |
args[nargs] = create_component_ref_by_pieces_1 (block, ref, |
operand, stmts, |
domstmt); |
+ if (!args[nargs]) |
+ { |
+ free (args); |
+ return NULL_TREE; |
+ } |
nargs++; |
} |
folded = build_call_array (currop->type, |
- TREE_CODE (currop->op0) == FUNCTION_DECL |
- ? build_fold_addr_expr (currop->op0) |
- : currop->op0, |
+ (TREE_CODE (fn) == FUNCTION_DECL |
+ ? build_fold_addr_expr (fn) : fn), |
nargs, args); |
free (args); |
if (sc) |
+ CALL_EXPR_STATIC_CHAIN (folded) = sc; |
+ return folded; |
+ } |
+ break; |
+ case TARGET_MEM_REF: |
+ { |
+ vn_reference_op_t nextop = VEC_index (vn_reference_op_s, ref->operands, |
+ *operand); |
+ pre_expr op0expr; |
+ tree genop0 = NULL_TREE; |
+ tree baseop = create_component_ref_by_pieces_1 (block, ref, operand, |
+ stmts, domstmt); |
+ if (!baseop) |
+ return NULL_TREE; |
+ if (currop->op0) |
{ |
- pre_expr scexpr = get_or_alloc_expr_for (sc); |
- sc = find_or_generate_expression (block, scexpr, stmts, domstmt); |
- if (!sc) |
+ op0expr = get_or_alloc_expr_for (currop->op0); |
+ genop0 = find_or_generate_expression (block, op0expr, |
+ stmts, domstmt); |
+ if (!genop0) |
return NULL_TREE; |
- CALL_EXPR_STATIC_CHAIN (folded) = sc; |
} |
- return folded; |
+ if (DECL_P (baseop)) |
+ return build6 (TARGET_MEM_REF, currop->type, |
+ baseop, NULL_TREE, |
+ genop0, currop->op1, currop->op2, |
+ unshare_expr (nextop->op1)); |
+ else |
+ return build6 (TARGET_MEM_REF, currop->type, |
+ NULL_TREE, baseop, |
+ genop0, currop->op1, currop->op2, |
+ unshare_expr (nextop->op1)); |
} |
break; |
case ADDR_EXPR: |
@@ -2589,7 +2820,8 @@ create_component_ref_by_pieces_1 (basic_block block, vn_reference_t ref, |
pre_expr op1expr; |
tree genop2 = currop->op1; |
pre_expr op2expr; |
- tree genop3; |
+ tree genop3 = currop->op2; |
+ pre_expr op3expr; |
genop0 = create_component_ref_by_pieces_1 (block, ref, operand, |
stmts, domstmt); |
if (!genop0) |
@@ -2600,14 +2832,38 @@ create_component_ref_by_pieces_1 (basic_block block, vn_reference_t ref, |
return NULL_TREE; |
if (genop2) |
{ |
- op2expr = get_or_alloc_expr_for (genop2); |
- genop2 = find_or_generate_expression (block, op2expr, stmts, |
- domstmt); |
- if (!genop2) |
- return NULL_TREE; |
+ /* Drop zero minimum index. */ |
+ if (tree_int_cst_equal (genop2, integer_zero_node)) |
+ genop2 = NULL_TREE; |
+ else |
+ { |
+ op2expr = get_or_alloc_expr_for (genop2); |
+ genop2 = find_or_generate_expression (block, op2expr, stmts, |
+ domstmt); |
+ if (!genop2) |
+ return NULL_TREE; |
+ } |
+ } |
+ if (genop3) |
+ { |
+ tree elmt_type = TREE_TYPE (TREE_TYPE (genop0)); |
+ /* We can't always put a size in units of the element alignment |
+ here as the element alignment may be not visible. See |
+ PR43783. Simply drop the element size for constant |
+ sizes. */ |
+ if (tree_int_cst_equal (genop3, TYPE_SIZE_UNIT (elmt_type))) |
+ genop3 = NULL_TREE; |
+ else |
+ { |
+ genop3 = size_binop (EXACT_DIV_EXPR, genop3, |
+ size_int (TYPE_ALIGN_UNIT (elmt_type))); |
+ op3expr = get_or_alloc_expr_for (genop3); |
+ genop3 = find_or_generate_expression (block, op3expr, stmts, |
+ domstmt); |
+ if (!genop3) |
+ return NULL_TREE; |
+ } |
} |
- |
- genop3 = currop->op2; |
return build4 (currop->opcode, currop->type, genop0, genop1, |
genop2, genop3); |
} |
@@ -2766,8 +3022,8 @@ create_expression_by_pieces (basic_block block, pre_expr expr, |
gimple_seq *stmts, gimple domstmt, tree type) |
{ |
tree temp, name; |
- tree folded, newexpr; |
- gimple_seq forced_stmts; |
+ tree folded; |
+ gimple_seq forced_stmts = NULL; |
unsigned int value_id; |
gimple_stmt_iterator gsi; |
tree exprtype = type ? type : get_expr_type (expr); |
@@ -2805,15 +3061,19 @@ create_expression_by_pieces (basic_block block, pre_expr expr, |
stmts, domstmt); |
if (!genop1 || !genop2) |
return NULL_TREE; |
- genop1 = fold_convert (TREE_TYPE (nary->op[0]), |
- genop1); |
/* Ensure op2 is a sizetype for POINTER_PLUS_EXPR. It |
may be a constant with the wrong type. */ |
if (nary->opcode == POINTER_PLUS_EXPR) |
- genop2 = fold_convert (sizetype, genop2); |
+ { |
+ genop1 = fold_convert (nary->type, genop1); |
+ genop2 = fold_convert (sizetype, genop2); |
+ } |
else |
- genop2 = fold_convert (TREE_TYPE (nary->op[1]), genop2); |
- |
+ { |
+ genop1 = fold_convert (TREE_TYPE (nary->op[0]), genop1); |
+ genop2 = fold_convert (TREE_TYPE (nary->op[1]), genop2); |
+ } |
+ |
folded = fold_build2 (nary->opcode, nary->type, |
genop1, genop2); |
} |
@@ -2839,13 +3099,16 @@ create_expression_by_pieces (basic_block block, pre_expr expr, |
default: |
return NULL_TREE; |
} |
- folded = fold_convert (exprtype, folded); |
+ |
+ if (!useless_type_conversion_p (exprtype, TREE_TYPE (folded))) |
+ folded = fold_convert (exprtype, folded); |
+ |
/* Force the generated expression to be a sequence of GIMPLE |
statements. |
We have to call unshare_expr because force_gimple_operand may |
modify the tree we pass to it. */ |
- newexpr = force_gimple_operand (unshare_expr (folded), &forced_stmts, |
- false, NULL); |
+ folded = force_gimple_operand (unshare_expr (folded), &forced_stmts, |
+ false, NULL); |
/* If we have any intermediate expressions to the value sets, add them |
to the value sets and chain them in the instruction stream. */ |
@@ -2889,7 +3152,7 @@ create_expression_by_pieces (basic_block block, pre_expr expr, |
|| TREE_CODE (exprtype) == VECTOR_TYPE) |
DECL_GIMPLE_REG_P (temp) = 1; |
- newstmt = gimple_build_assign (temp, newexpr); |
+ newstmt = gimple_build_assign (temp, folded); |
name = make_ssa_name (temp, newstmt); |
gimple_assign_set_lhs (newstmt, name); |
gimple_set_plf (newstmt, NECESSARY, false); |
@@ -2926,6 +3189,62 @@ create_expression_by_pieces (basic_block block, pre_expr expr, |
} |
+/* 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, heap) *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 (i = 0; VEC_iterate (vn_reference_op_s, ops, i, op); ++i) |
+ { |
+ switch (op->opcode) |
+ { |
+ 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 |
@@ -2956,8 +3275,7 @@ insert_into_preds_of_block (basic_block block, unsigned int exprnum, |
} |
/* Make sure we aren't creating an induction variable. */ |
- if (block->loop_depth > 0 && EDGE_COUNT (block->preds) == 2 |
- && expr->kind != REFERENCE) |
+ if (block->loop_depth > 0 && EDGE_COUNT (block->preds) == 2) |
{ |
bool firstinsideloop = false; |
bool secondinsideloop = false; |
@@ -2966,7 +3284,9 @@ insert_into_preds_of_block (basic_block block, unsigned int exprnum, |
secondinsideloop = flow_bb_inside_loop_p (block->loop_father, |
EDGE_PRED (block, 1)->src); |
/* Induction variables only have one edge inside the loop. */ |
- if (firstinsideloop ^ secondinsideloop) |
+ if ((firstinsideloop ^ secondinsideloop) |
+ && (expr->kind != REFERENCE |
+ || inhibit_phi_insertion (block, expr))) |
{ |
if (dump_file && (dump_flags & TDF_DETAILS)) |
fprintf (dump_file, "Skipping insertion of phi for partial redundancy: Looks like an induction variable\n"); |
@@ -2974,16 +3294,6 @@ insert_into_preds_of_block (basic_block block, unsigned int exprnum, |
} |
} |
- /* Make sure we are not inserting trapping expressions. */ |
- FOR_EACH_EDGE (pred, ei, block->preds) |
- { |
- bprime = pred->src; |
- eprime = avail[bprime->index]; |
- if (eprime->kind == NARY |
- && vn_nary_may_trap (PRE_EXPR_NARY (eprime))) |
- return false; |
- } |
- |
/* Make the necessary insertions. */ |
FOR_EACH_EDGE (pred, ei, block->preds) |
{ |
@@ -3012,7 +3322,7 @@ insert_into_preds_of_block (basic_block block, unsigned int exprnum, |
if (!useless_type_conversion_p (type, TREE_TYPE (constant))) |
{ |
tree builtexpr = fold_convert (type, constant); |
- if (!is_gimple_min_invariant (builtexpr)) |
+ if (!is_gimple_min_invariant (builtexpr)) |
{ |
tree forcedexpr = force_gimple_operand (builtexpr, |
&stmts, true, |
@@ -3107,15 +3417,18 @@ insert_into_preds_of_block (basic_block block, unsigned int exprnum, |
VN_INFO_GET (gimple_phi_result (phi))->valnum = gimple_phi_result (phi); |
VN_INFO (gimple_phi_result (phi))->value_id = val; |
VEC_safe_push (gimple, heap, inserted_exprs, phi); |
+ bitmap_set_bit (inserted_phi_names, |
+ SSA_NAME_VERSION (gimple_phi_result (phi))); |
FOR_EACH_EDGE (pred, ei, block->preds) |
{ |
pre_expr ae = avail[pred->src->index]; |
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); |
+ add_phi_arg (phi, PRE_EXPR_CONSTANT (ae), pred, UNKNOWN_LOCATION); |
else |
- add_phi_arg (phi, PRE_EXPR_NAME (avail[pred->src->index]), pred); |
+ add_phi_arg (phi, PRE_EXPR_NAME (avail[pred->src->index]), pred, |
+ UNKNOWN_LOCATION); |
} |
newphi = get_or_alloc_expr_for_name (gimple_phi_result (phi)); |
@@ -3194,6 +3507,7 @@ do_regular_insertion (basic_block block, basic_block dom) |
pre_expr eprime = NULL; |
edge_iterator ei; |
pre_expr edoubleprime = NULL; |
+ bool do_insertion = false; |
val = get_expr_value_id (expr); |
if (bitmap_set_contains_value (PHI_GEN (block), val)) |
@@ -3245,6 +3559,10 @@ do_regular_insertion (basic_block block, basic_block dom) |
{ |
avail[bprime->index] = edoubleprime; |
by_some = true; |
+ /* We want to perform insertions to remove a redundancy on |
+ a path in the CFG we want to optimize for speed. */ |
+ if (optimize_edge_for_speed_p (pred)) |
+ do_insertion = true; |
if (first_s == NULL) |
first_s = edoubleprime; |
else if (!pre_expr_eq (first_s, edoubleprime)) |
@@ -3255,7 +3573,8 @@ do_regular_insertion (basic_block block, basic_block dom) |
already existing along every predecessor, and |
it's defined by some predecessor, it is |
partially redundant. */ |
- if (!cant_insert && !all_same && by_some && dbg_cnt (treepre_insert)) |
+ if (!cant_insert && !all_same && by_some && do_insertion |
+ && dbg_cnt (treepre_insert)) |
{ |
if (insert_into_preds_of_block (block, get_expression_id (expr), |
avail)) |
@@ -3530,40 +3849,25 @@ compute_avail (void) |
basic_block block, son; |
basic_block *worklist; |
size_t sp = 0; |
- tree param; |
+ unsigned i; |
- /* For arguments with default definitions, we pretend they are |
- defined in the entry block. */ |
- for (param = DECL_ARGUMENTS (current_function_decl); |
- param; |
- param = TREE_CHAIN (param)) |
+ /* We pretend that default definitions are defined in the entry block. |
+ This includes function arguments and the static chain decl. */ |
+ for (i = 1; i < num_ssa_names; ++i) |
{ |
- if (gimple_default_def (cfun, param) != NULL) |
- { |
- tree def = gimple_default_def (cfun, param); |
- pre_expr e = get_or_alloc_expr_for_name (def); |
- |
- add_to_value (get_expr_value_id (e), e); |
- if (!in_fre) |
- bitmap_insert_into_set (TMP_GEN (ENTRY_BLOCK_PTR), e); |
- bitmap_value_insert_into_set (AVAIL_OUT (ENTRY_BLOCK_PTR), e); |
- } |
- } |
- |
- /* Likewise for the static chain decl. */ |
- if (cfun->static_chain_decl) |
- { |
- param = cfun->static_chain_decl; |
- if (gimple_default_def (cfun, param) != NULL) |
- { |
- tree def = gimple_default_def (cfun, param); |
- pre_expr e = get_or_alloc_expr_for_name (def); |
+ tree name = ssa_name (i); |
+ pre_expr e; |
+ if (!name |
+ || !SSA_NAME_IS_DEFAULT_DEF (name) |
+ || has_zero_uses (name) |
+ || !is_gimple_reg (name)) |
+ continue; |
- add_to_value (get_expr_value_id (e), e); |
- if (!in_fre) |
- bitmap_insert_into_set (TMP_GEN (ENTRY_BLOCK_PTR), e); |
- bitmap_value_insert_into_set (AVAIL_OUT (ENTRY_BLOCK_PTR), e); |
- } |
+ e = get_or_alloc_expr_for_name (name); |
+ add_to_value (get_expr_value_id (e), e); |
+ if (!in_fre) |
+ bitmap_insert_into_set (TMP_GEN (ENTRY_BLOCK_PTR), e); |
+ bitmap_value_insert_into_set (AVAIL_OUT (ENTRY_BLOCK_PTR), e); |
} |
/* Allocate the worklist. */ |
@@ -3597,6 +3901,8 @@ compute_avail (void) |
for (gsi = gsi_start_phis (block); !gsi_end_p (gsi); gsi_next (&gsi)) |
make_values_for_phi (gsi_stmt (gsi), block); |
+ BB_MAY_NOTRETURN (block) = 0; |
+ |
/* 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)) |
@@ -3607,6 +3913,23 @@ compute_avail (void) |
stmt = gsi_stmt (gsi); |
gimple_set_uid (stmt, stmt_uid++); |
+ /* Cache whether the basic-block has any non-visible side-effect |
+ or control flow. |
+ If this isn't a call or it is the last stmt in the |
+ basic-block then the CFG represents things correctly. */ |
+ if (is_gimple_call (stmt) |
+ && !stmt_ends_bb_p (stmt)) |
+ { |
+ /* Non-looping const functions always return normally. |
+ Otherwise the call might not return or have side-effects |
+ that forbids hoisting possibly trapping expressions |
+ before it. */ |
+ int flags = gimple_call_flags (stmt); |
+ if (!(flags & ECF_CONST) |
+ || (flags & ECF_LOOPING_CONST_OR_PURE)) |
+ BB_MAY_NOTRETURN (block) = 1; |
+ } |
+ |
FOR_EACH_SSA_TREE_OPERAND (op, stmt, iter, SSA_OP_DEF) |
{ |
pre_expr e = get_or_alloc_expr_for_name (op); |
@@ -3640,7 +3963,8 @@ compute_avail (void) |
continue; |
copy_reference_ops_from_call (stmt, &ops); |
- vn_reference_lookup_pieces (shared_vuses_from_stmt (stmt), |
+ vn_reference_lookup_pieces (gimple_vuse (stmt), 0, |
+ gimple_expr_type (stmt), |
ops, &ref, false); |
VEC_free (vn_reference_op_s, heap, ops); |
if (!ref) |
@@ -3675,8 +3999,6 @@ compute_avail (void) |
switch (TREE_CODE_CLASS (gimple_assign_rhs_code (stmt))) |
{ |
case tcc_unary: |
- if (is_exception_related (stmt)) |
- continue; |
case tcc_binary: |
case tcc_comparison: |
{ |
@@ -3712,8 +4034,8 @@ compute_avail (void) |
vn_reference_op_t vro; |
vn_reference_lookup (gimple_assign_rhs1 (stmt), |
- shared_vuses_from_stmt (stmt), |
- false, &ref); |
+ gimple_vuse (stmt), |
+ true, &ref); |
if (!ref) |
continue; |
@@ -3803,16 +4125,18 @@ do_SCCVN_insertion (gimple stmt, tree ssa_vn) |
static unsigned int |
eliminate (void) |
{ |
+ VEC (gimple, heap) *to_remove = NULL; |
basic_block b; |
unsigned int todo = 0; |
+ gimple_stmt_iterator gsi; |
+ gimple stmt; |
+ unsigned i; |
FOR_EACH_BB (b) |
{ |
- gimple_stmt_iterator i; |
- |
- for (i = gsi_start_bb (b); !gsi_end_p (i); gsi_next (&i)) |
+ for (gsi = gsi_start_bb (b); !gsi_end_p (gsi); gsi_next (&gsi)) |
{ |
- gimple stmt = gsi_stmt (i); |
+ stmt = gsi_stmt (gsi); |
/* Lookup the RHS of the expression, see if we have an |
available computation for it. If so, replace the RHS with |
@@ -3852,8 +4176,10 @@ eliminate (void) |
value is constant, use that constant. */ |
if (!sprime && is_gimple_min_invariant (VN_INFO (lhs)->valnum)) |
{ |
- sprime = fold_convert (TREE_TYPE (lhs), |
- VN_INFO (lhs)->valnum); |
+ sprime = VN_INFO (lhs)->valnum; |
+ if (!useless_type_conversion_p (TREE_TYPE (lhs), |
+ TREE_TYPE (sprime))) |
+ sprime = fold_convert (TREE_TYPE (lhs), sprime); |
if (dump_file && (dump_flags & TDF_DETAILS)) |
{ |
@@ -3865,8 +4191,8 @@ eliminate (void) |
print_gimple_stmt (dump_file, stmt, 0, 0); |
} |
pre_stats.eliminations++; |
- propagate_tree_value_into_stmt (&i, sprime); |
- stmt = gsi_stmt (i); |
+ propagate_tree_value_into_stmt (&gsi, sprime); |
+ stmt = gsi_stmt (gsi); |
update_stmt (stmt); |
continue; |
} |
@@ -3913,8 +4239,8 @@ eliminate (void) |
sprime = fold_convert (gimple_expr_type (stmt), sprime); |
pre_stats.eliminations++; |
- propagate_tree_value_into_stmt (&i, sprime); |
- stmt = gsi_stmt (i); |
+ propagate_tree_value_into_stmt (&gsi, sprime); |
+ stmt = gsi_stmt (gsi); |
update_stmt (stmt); |
/* If we removed EH side effects from the statement, clean |
@@ -3928,6 +4254,33 @@ eliminate (void) |
} |
} |
} |
+ /* 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) |
+ && !is_gimple_reg (gimple_assign_lhs (stmt)) |
+ && (TREE_CODE (gimple_assign_rhs1 (stmt)) == SSA_NAME |
+ || is_gimple_min_invariant (gimple_assign_rhs1 (stmt)))) |
+ { |
+ tree rhs = gimple_assign_rhs1 (stmt); |
+ tree val; |
+ val = vn_reference_lookup (gimple_assign_lhs (stmt), |
+ gimple_vuse (stmt), true, 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. */ |
+ VEC_safe_push (gimple, heap, to_remove, stmt); |
+ } |
+ } |
/* Visit COND_EXPRs and fold the comparison with the |
available value-numbers. */ |
else if (gimple_code (stmt) == GIMPLE_COND) |
@@ -3952,9 +4305,137 @@ eliminate (void) |
todo = TODO_cleanup_cfg; |
} |
} |
+ /* Visit indirect calls and turn them into direct calls if |
+ possible. */ |
+ if (gimple_code (stmt) == GIMPLE_CALL |
+ && TREE_CODE (gimple_call_fn (stmt)) == SSA_NAME) |
+ { |
+ tree fn = VN_INFO (gimple_call_fn (stmt))->valnum; |
+ if (TREE_CODE (fn) == ADDR_EXPR |
+ && TREE_CODE (TREE_OPERAND (fn, 0)) == FUNCTION_DECL) |
+ { |
+ if (dump_file && (dump_flags & TDF_DETAILS)) |
+ { |
+ 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); |
+ } |
+ |
+ gimple_call_set_fn (stmt, fn); |
+ update_stmt (stmt); |
+ 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"); |
+ } |
+ |
+ /* Changing an indirect call to a direct call may |
+ have exposed different semantics. This may |
+ require an SSA update. */ |
+ todo |= TODO_update_ssa_only_virtuals; |
+ } |
+ } |
+ } |
+ |
+ for (gsi = gsi_start_phis (b); !gsi_end_p (gsi);) |
+ { |
+ gimple stmt, phi = gsi_stmt (gsi); |
+ tree sprime = NULL_TREE, res = PHI_RESULT (phi); |
+ pre_expr sprimeexpr, resexpr; |
+ 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 |
+ || !is_gimple_reg (res) |
+ || bitmap_bit_p (inserted_phi_names, SSA_NAME_VERSION (res))) |
+ { |
+ gsi_next (&gsi); |
+ continue; |
+ } |
+ |
+ resexpr = get_or_alloc_expr_for_name (res); |
+ sprimeexpr = bitmap_find_leader (AVAIL_OUT (b), |
+ get_expr_value_id (resexpr), NULL); |
+ if (sprimeexpr) |
+ { |
+ if (sprimeexpr->kind == CONSTANT) |
+ sprime = PRE_EXPR_CONSTANT (sprimeexpr); |
+ else if (sprimeexpr->kind == NAME) |
+ sprime = PRE_EXPR_NAME (sprimeexpr); |
+ else |
+ gcc_unreachable (); |
+ } |
+ if (!sprimeexpr |
+ || sprime == res) |
+ { |
+ gsi_next (&gsi); |
+ continue; |
+ } |
+ |
+ 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 (!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; |
+ if (TREE_CODE (sprime) == SSA_NAME) |
+ gimple_set_plf (SSA_NAME_DEF_STMT (sprime), |
+ NECESSARY, true); |
+ gsi2 = gsi_after_labels (b); |
+ gsi_insert_before (&gsi2, stmt, GSI_NEW_STMT); |
+ /* Queue the copy for eventual removal. */ |
+ VEC_safe_push (gimple, heap, to_remove, stmt); |
+ pre_stats.eliminations++; |
} |
} |
+ /* We cannot remove stmts during BB walk, especially not release SSA |
+ names there as this confuses the VN machinery. The stmts ending |
+ up in to_remove are either stores or simple copies. */ |
+ for (i = 0; VEC_iterate (gimple, to_remove, i, stmt); ++i) |
+ { |
+ 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)) |
+ { |
+ SET_USE (use_p, gimple_assign_rhs1 (stmt)); |
+ update_stmt (use_stmt); |
+ } |
+ |
+ /* If this is a store or a now unused copy, remove it. */ |
+ if (TREE_CODE (lhs) != SSA_NAME |
+ || has_zero_uses (lhs)) |
+ { |
+ gsi = gsi_for_stmt (stmt); |
+ unlink_stmt_vdef (stmt); |
+ gsi_remove (&gsi, true); |
+ release_defs (stmt); |
+ } |
+ } |
+ VEC_free (gimple, heap, to_remove); |
+ |
return todo; |
} |
@@ -4066,13 +4547,94 @@ remove_dead_inserted_code (void) |
if (gimple_code (t) == GIMPLE_PHI) |
remove_phi_node (&gsi, true); |
else |
- gsi_remove (&gsi, true); |
- release_defs (t); |
+ { |
+ gsi_remove (&gsi, true); |
+ release_defs (t); |
+ } |
} |
} |
VEC_free (gimple, heap, worklist); |
} |
+/* Compute a reverse post-order in *POST_ORDER. If INCLUDE_ENTRY_EXIT is |
+ true, then then ENTRY_BLOCK and EXIT_BLOCK are included. Returns |
+ the number of visited blocks. */ |
+ |
+static int |
+my_rev_post_order_compute (int *post_order, bool include_entry_exit) |
+{ |
+ edge_iterator *stack; |
+ int sp; |
+ int post_order_num = 0; |
+ sbitmap visited; |
+ int count; |
+ |
+ if (include_entry_exit) |
+ post_order[post_order_num++] = EXIT_BLOCK; |
+ |
+ /* Allocate stack for back-tracking up CFG. */ |
+ stack = XNEWVEC (edge_iterator, n_basic_blocks + 1); |
+ sp = 0; |
+ |
+ /* Allocate bitmap to track nodes that have been visited. */ |
+ visited = sbitmap_alloc (last_basic_block); |
+ |
+ /* None of the nodes in the CFG have been visited yet. */ |
+ sbitmap_zero (visited); |
+ |
+ /* Push the last edge on to the stack. */ |
+ stack[sp++] = ei_start (EXIT_BLOCK_PTR->preds); |
+ |
+ while (sp) |
+ { |
+ edge_iterator ei; |
+ basic_block src; |
+ basic_block dest; |
+ |
+ /* Look at the edge on the top of the stack. */ |
+ ei = stack[sp - 1]; |
+ src = ei_edge (ei)->src; |
+ dest = ei_edge (ei)->dest; |
+ |
+ /* Check if the edge destination has been visited yet. */ |
+ if (src != ENTRY_BLOCK_PTR && ! TEST_BIT (visited, src->index)) |
+ { |
+ /* Mark that we have visited the destination. */ |
+ SET_BIT (visited, src->index); |
+ |
+ if (EDGE_COUNT (src->preds) > 0) |
+ /* Since the DEST node has been visited for the first |
+ time, check its successors. */ |
+ stack[sp++] = ei_start (src->preds); |
+ else |
+ post_order[post_order_num++] = src->index; |
+ } |
+ else |
+ { |
+ if (ei_one_before_end_p (ei) && dest != EXIT_BLOCK_PTR) |
+ post_order[post_order_num++] = dest->index; |
+ |
+ if (!ei_one_before_end_p (ei)) |
+ ei_next (&stack[sp - 1]); |
+ else |
+ sp--; |
+ } |
+ } |
+ |
+ if (include_entry_exit) |
+ { |
+ post_order[post_order_num++] = ENTRY_BLOCK; |
+ count = post_order_num; |
+ } |
+ else |
+ count = post_order_num + 2; |
+ |
+ free (stack); |
+ sbitmap_free (visited); |
+ return post_order_num; |
+} |
+ |
+ |
/* Initialize data structures used by PRE. */ |
static void |
@@ -4086,6 +4648,7 @@ init_pre (bool do_fre) |
value_expressions = VEC_alloc (bitmap_set_t, heap, get_max_value_id () + 1); |
VEC_safe_grow_cleared (bitmap_set_t, heap, value_expressions, |
get_max_value_id() + 1); |
+ name_to_id = NULL; |
in_fre = do_fre; |
@@ -4100,7 +4663,7 @@ init_pre (bool do_fre) |
postorder = XNEWVEC (int, n_basic_blocks - NUM_FIXED_BLOCKS); |
- post_order_compute (postorder, false, false); |
+ my_rev_post_order_compute (postorder, false); |
FOR_ALL_BB (bb) |
bb->aux = XCNEWVEC (struct bb_bitmap_sets, 1); |
@@ -4109,6 +4672,7 @@ init_pre (bool do_fre) |
calculate_dominance_info (CDI_DOMINATORS); |
bitmap_obstack_initialize (&grand_bitmap_obstack); |
+ inserted_phi_names = BITMAP_ALLOC (&grand_bitmap_obstack); |
phi_translate_table = htab_create (5110, expr_pred_trans_hash, |
expr_pred_trans_eq, free); |
expression_to_id = htab_create (num_ssa_names * 3, |
@@ -4146,6 +4710,7 @@ fini_pre (bool do_fre) |
free_alloc_pool (pre_expr_pool); |
htab_delete (phi_translate_table); |
htab_delete (expression_to_id); |
+ VEC_free (unsigned, heap, name_to_id); |
FOR_ALL_BB (bb) |
{ |
@@ -4171,11 +4736,11 @@ fini_pre (bool do_fre) |
only wants to do full redundancy elimination. */ |
static unsigned int |
-execute_pre (bool do_fre ATTRIBUTE_UNUSED) |
+execute_pre (bool do_fre) |
{ |
unsigned int todo = 0; |
- do_partial_partial = optimize > 2; |
+ do_partial_partial = optimize > 2 && optimize_function_for_speed_p (cfun); |
/* This has to happen before SCCVN runs because |
loop_optimizer_init may create new phis, etc. */ |
@@ -4189,10 +4754,11 @@ execute_pre (bool do_fre ATTRIBUTE_UNUSED) |
remove_dead_inserted_code (); |
loop_optimizer_finalize (); |
} |
- |
+ |
return 0; |
} |
init_pre (do_fre); |
+ scev_initialize (); |
/* Collect and value number expressions computed in each basic block. */ |
@@ -4242,6 +4808,7 @@ execute_pre (bool do_fre ATTRIBUTE_UNUSED) |
if (!do_fre) |
remove_dead_inserted_code (); |
+ scev_finalize (); |
fini_pre (do_fre); |
return todo; |
@@ -4252,14 +4819,13 @@ execute_pre (bool do_fre ATTRIBUTE_UNUSED) |
static unsigned int |
do_pre (void) |
{ |
- return TODO_rebuild_alias | execute_pre (false); |
+ return execute_pre (false); |
} |
static bool |
gate_pre (void) |
{ |
- /* PRE tends to generate bigger code. */ |
- return flag_tree_pre != 0 && optimize_function_for_speed_p (cfun); |
+ return flag_tree_pre != 0; |
} |
struct gimple_opt_pass pass_pre = |
@@ -4274,10 +4840,10 @@ struct gimple_opt_pass pass_pre = |
0, /* static_pass_number */ |
TV_TREE_PRE, /* tv_id */ |
PROP_no_crit_edges | PROP_cfg |
- | PROP_ssa | PROP_alias, /* properties_required */ |
+ | PROP_ssa, /* properties_required */ |
0, /* properties_provided */ |
0, /* properties_destroyed */ |
- 0, /* todo_flags_start */ |
+ TODO_rebuild_alias, /* todo_flags_start */ |
TODO_update_ssa_only_virtuals | TODO_dump_func | TODO_ggc_collect |
| TODO_verify_ssa /* todo_flags_finish */ |
} |
@@ -4309,7 +4875,7 @@ struct gimple_opt_pass pass_fre = |
NULL, /* next */ |
0, /* static_pass_number */ |
TV_TREE_FRE, /* tv_id */ |
- PROP_cfg | PROP_ssa | PROP_alias, /* properties_required */ |
+ PROP_cfg | PROP_ssa, /* properties_required */ |
0, /* properties_provided */ |
0, /* properties_destroyed */ |
0, /* todo_flags_start */ |