Mercurial > hg > CbC > CbC_gcc
diff gcc/tree-ssa-pre.c @ 55:77e2b8dfacca gcc-4.4.5
update it from 4.4.3 to 4.5.0
author | ryoma <e075725@ie.u-ryukyu.ac.jp> |
---|---|
date | Fri, 12 Feb 2010 23:39:51 +0900 |
parents | 3bfb6c00c1e0 |
children | b7f97abdc517 |
line wrap: on
line diff
--- a/gcc/tree-ssa-pre.c Sun Feb 07 18:28:00 2010 +0900 +++ b/gcc/tree-ssa-pre.c Fri Feb 12 23:39:51 2010 +0900 @@ -45,6 +45,7 @@ #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 @@ /* 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. */ @@ -377,6 +378,9 @@ 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 +396,8 @@ #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 @@ -899,26 +904,42 @@ 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; } @@ -1132,7 +1153,7 @@ } 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 +1239,81 @@ 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. */ - -static VEC(tree, gc) * -translate_vuses_through_block (VEC (tree, gc) *vuses, - basic_block phiblock, - basic_block 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 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; - - for (i = 0; VEC_iterate (tree, vuses, i, oldvuse); 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; + + 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 +1340,7 @@ 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; } @@ -1519,15 +1554,16 @@ { 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 +1608,9 @@ 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 +1627,9 @@ 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 +1641,13 @@ 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 +1656,26 @@ return NULL; } - newvuses = translate_vuses_through_block (vuses, phiblock, pred); - changed |= newvuses != vuses; - - if (changed) + 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 || 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 +1703,17 @@ } 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; @@ -1718,7 +1784,7 @@ pre_expr expr; int i; - if (gimple_seq_empty_p (phi_nodes (phiblock))) + if (!phi_nodes (phiblock)) { bitmap_set_copy (dest, set); return; @@ -1808,24 +1874,73 @@ 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; - - /* 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++) + 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; + + 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); - - if (gimple_bb (def) != block) + tree def_vuse, def_vdef; + def = gsi_stmt (gsi); + def_vuse = gimple_vuse (def); + def_vdef = gimple_vdef (def); + + /* 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.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 +2002,7 @@ 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, @@ -1932,6 +2046,15 @@ 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: @@ -2100,14 +2223,14 @@ goto maybe_dump_sets; } - if (!gimple_seq_empty_p (phi_nodes (first))) + if (phi_nodes (first)) phi_translate_set (ANTIC_OUT, ANTIC_IN (first), block, first); else bitmap_set_copy (ANTIC_OUT, ANTIC_IN (first)); for (i = 0; VEC_iterate (basic_block, worklist, i, bprime); i++) { - if (!gimple_seq_empty_p (phi_nodes (bprime))) + if (phi_nodes (bprime)) { bitmap_set_t tmp = bitmap_set_new (); phi_translate_set (tmp, ANTIC_IN (bprime), block, bprime); @@ -2257,7 +2380,7 @@ FOR_EACH_EXPR_ID_IN_SET (ANTIC_IN (bprime), i, bi) bitmap_value_insert_into_set (PA_OUT, expression_for_id (i)); - if (!gimple_seq_empty_p (phi_nodes (bprime))) + if (phi_nodes (bprime)) { bitmap_set_t pa_in = bitmap_set_new (); phi_translate_set (pa_in, PA_IN (bprime), block, bprime); @@ -2429,19 +2552,8 @@ 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 +2574,7 @@ 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 @@ -2511,6 +2624,36 @@ 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) + { + op0expr = get_or_alloc_expr_for (currop->op0); + genop0 = find_or_generate_expression (block, op0expr, + stmts, domstmt); + if (!genop0) + return NULL_TREE; + } + 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: if (currop->op0) { @@ -2589,7 +2732,8 @@ 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) @@ -2606,8 +2750,17 @@ if (!genop2) return NULL_TREE; } - - genop3 = currop->op2; + if (genop3) + { + tree elmt_type = TREE_TYPE (TREE_TYPE (genop0)); + 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; + } return build4 (currop->opcode, currop->type, genop0, genop1, genop2, genop3); } @@ -2766,8 +2919,8 @@ 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); @@ -2813,7 +2966,7 @@ genop2 = fold_convert (sizetype, genop2); else genop2 = fold_convert (TREE_TYPE (nary->op[1]), genop2); - + folded = fold_build2 (nary->opcode, nary->type, genop1, genop2); } @@ -2839,13 +2992,16 @@ 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 +3045,7 @@ || 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 +3082,62 @@ } +/* 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 +3168,7 @@ } /* 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 +3177,9 @@ 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"); @@ -3012,7 +3225,7 @@ 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 +3320,18 @@ 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 +3410,7 @@ 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 +3462,10 @@ { 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 +3476,8 @@ 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 +3752,25 @@ basic_block block, son; basic_block *worklist; size_t sp = 0; - tree param; - - /* 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)) + unsigned i; + + /* 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); - - 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); - } + 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; + + 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. */ @@ -3640,7 +3847,8 @@ 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 +3883,6 @@ 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 +3918,8 @@ 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 +4009,18 @@ 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 +4060,10 @@ 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 +4075,8 @@ 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 +4123,8 @@ 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 +4138,33 @@ } } } + /* 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 +4189,136 @@ 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); + 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 + && single_imm_use (lhs, &use_p, &use_stmt) + && may_propagate_copy (USE_FROM_PTR (use_p), + gimple_assign_rhs1 (stmt))) + { + 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,8 +4430,10 @@ 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); @@ -4109,6 +4475,7 @@ 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, @@ -4171,11 +4538,11 @@ 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 +4556,11 @@ 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 +4610,7 @@ if (!do_fre) remove_dead_inserted_code (); + scev_finalize (); fini_pre (do_fre); return todo; @@ -4252,14 +4621,13 @@ 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 +4642,10 @@ 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 +4677,7 @@ 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 */