diff options
Diffstat (limited to 'gcc/tree-ssa-pre.c')
-rw-r--r-- | gcc/tree-ssa-pre.c | 277 |
1 files changed, 174 insertions, 103 deletions
diff --git a/gcc/tree-ssa-pre.c b/gcc/tree-ssa-pre.c index 267c2fcfea2..c1cbe0ca650 100644 --- a/gcc/tree-ssa-pre.c +++ b/gcc/tree-ssa-pre.c @@ -377,6 +377,9 @@ 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; @@ -392,7 +395,8 @@ 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 @@ -906,26 +910,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; } @@ -1227,48 +1247,47 @@ 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. */ -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, + tree vuse, + basic_block phiblock, + basic_block block) { - tree oldvuse; - VEC(tree, gc) *result = NULL; - int i; + gimple phi = SSA_NAME_DEF_STMT (vuse); + tree ref; - for (i = 0; VEC_iterate (tree, vuses, i, oldvuse); i++) + if (gimple_bb (phi) != phiblock) + return vuse; + + if (gimple_code (phi) == GIMPLE_PHI) { - gimple phi = SSA_NAME_DEF_STMT (oldvuse); - if (gimple_code (phi) == GIMPLE_PHI - && gimple_bb (phi) == phiblock) - { - 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); - } - } - } + edge e = find_edge (block, phiblock); + 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) + if (!(ref = get_ref_from_reference_ops (operands))) + return NULL_TREE; + + /* 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. */ + while (!stmt_may_clobber_ref_p (phi, ref)) { - sort_vuses (result); - return result; + vuse = gimple_vuse (phi); + phi = SSA_NAME_DEF_STMT (vuse); + if (gimple_bb (phi) != phiblock) + return vuse; + if (gimple_code (phi) == GIMPLE_PHI) + { + edge e = find_edge (block, phiblock); + return PHI_ARG_DEF (phi, e->dest_idx); + } } - return vuses; + return NULL_TREE; } /* Like find_leader, but checks for the value existing in SET1 *or* @@ -1540,8 +1559,8 @@ phi_translate_1 (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; @@ -1632,15 +1651,24 @@ phi_translate_1 (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, + vuse, phiblock, pred); + if (newvuse == NULL_TREE) + { + VEC_free (vn_reference_op_s, heap, newoperands); + return NULL; + } + } + changed |= newvuse != vuse; if (changed) { unsigned int new_val_id; pre_expr constant; - tree result = vn_reference_lookup_pieces (newvuses, + tree result = vn_reference_lookup_pieces (newvuse, newoperands, &newref, true); if (newref) @@ -1671,7 +1699,7 @@ phi_translate_1 (pre_expr expr, bitmap_set_t set1, bitmap_set_t set2, 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, + newref = vn_reference_insert_pieces (newvuse, newoperands, result, new_val_id); newoperands = NULL; @@ -1846,24 +1874,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; + tree ref = NULL_TREE; + gimple_stmt_iterator gsi; + unsigned id = get_expression_id (expr); + bool res = false; - /* 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. */ + 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) + /* Not a memory statement. */ + if (!def_vuse) continue; - if (gimple_code (def) == GIMPLE_PHI) - 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 == NULL_TREE) + { + if (!(ref = get_ref_from_reference_ops (refx->operands))) + { + res = true; + break; + } + } + /* If the statement may clobber expr, it dies. */ + if (stmt_may_clobber_ref_p (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; } @@ -1925,7 +2002,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 @@ -1970,6 +2047,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: @@ -3664,7 +3750,7 @@ 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), ops, &ref, false); VEC_free (vn_reference_op_s, heap, ops); if (!ref) @@ -3740,7 +3826,7 @@ compute_avail (void) vn_reference_op_t vro; vn_reference_lookup (gimple_assign_rhs1 (stmt), - shared_vuses_from_stmt (stmt), + gimple_vuse (stmt), false, &ref); if (!ref) continue; @@ -3834,16 +3920,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);) + 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 @@ -3896,10 +3984,9 @@ 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); - gsi_next (&i); continue; } @@ -3945,8 +4032,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 @@ -3971,45 +4058,20 @@ eliminate (void) tree rhs = gimple_assign_rhs1 (stmt); tree val; val = vn_reference_lookup (gimple_assign_lhs (stmt), - shared_vuses_from_stmt (stmt), - true, NULL); + gimple_vuse (stmt), true, NULL); if (TREE_CODE (rhs) == SSA_NAME) rhs = VN_INFO (rhs)->valnum; if (val && operand_equal_p (val, rhs, 0)) { - def_operand_p def; - use_operand_p use; - vuse_vec_p usevec; - ssa_op_iter oi; - imm_use_iterator ui; - gimple use_stmt; - if (dump_file && (dump_flags & TDF_DETAILS)) { - fprintf (dump_file, "Deleted dead store "); + fprintf (dump_file, "Deleted redundant store "); print_gimple_stmt (dump_file, stmt, 0, 0); } - /* Propagate all may-uses to the uses of their defs. */ - FOR_EACH_SSA_VDEF_OPERAND (def, usevec, stmt, oi) - { - tree vuse = VUSE_ELEMENT_VAR (*usevec, 0); - tree vdef = DEF_FROM_PTR (def); - - /* If the vdef is used in an abnormal PHI node we - have to propagate that flag to the vuse as well. */ - if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (vdef)) - SSA_NAME_OCCURS_IN_ABNORMAL_PHI (vuse) = 1; - - FOR_EACH_IMM_USE_STMT (use_stmt, ui, vdef) - FOR_EACH_IMM_USE_ON_STMT (use, ui) - SET_USE (use, vuse); - } - - gsi_remove (&i, true); - release_defs (stmt); - continue; + /* Queue stmt for removal. */ + VEC_safe_push (gimple, heap, to_remove, stmt); } } /* Visit COND_EXPRs and fold the comparison with the @@ -4036,11 +4098,20 @@ eliminate (void) todo = TODO_cleanup_cfg; } } - - gsi_next (&i); } } + /* We cannot remove stmts during BB walk, especially not release SSA + names there as this confuses the VN machinery. */ + for (i = 0; VEC_iterate (gimple, to_remove, i, stmt); ++i) + { + gsi = gsi_for_stmt (stmt); + unlink_stmt_vdef (stmt); + gsi_remove (&gsi, true); + release_defs (stmt); + } + VEC_free (gimple, heap, to_remove); + return todo; } @@ -4341,7 +4412,7 @@ 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 @@ -4366,7 +4437,7 @@ struct gimple_opt_pass pass_pre = | PROP_ssa | PROP_alias, /* 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 */ } |