X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Ftree-ssa-reassoc.c;h=197591e330f919f5936d0618d2a1af7458f2e56b;hb=22f7168e83bec47d92c5530b64befbc781f2d49a;hp=aa080855e5be3f92dbc3cf9b76084c586e39bcfb;hpb=50fa62c69940ddea294ac7656ec7c04ffa990221;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/tree-ssa-reassoc.c b/gcc/tree-ssa-reassoc.c index aa080855e5b..197591e330f 100644 --- a/gcc/tree-ssa-reassoc.c +++ b/gcc/tree-ssa-reassoc.c @@ -22,17 +22,16 @@ along with GCC; see the file COPYING3. If not see #include "system.h" #include "coretypes.h" #include "tm.h" -#include "ggc.h" #include "tree.h" #include "basic-block.h" -#include "diagnostic.h" +#include "tree-pretty-print.h" +#include "gimple-pretty-print.h" #include "tree-inline.h" #include "tree-flow.h" #include "gimple.h" #include "tree-dump.h" #include "timevar.h" #include "tree-iterator.h" -#include "real.h" #include "tree-pass.h" #include "alloc-pool.h" #include "vec.h" @@ -468,8 +467,7 @@ eliminate_duplicate_pair (enum tree_code opcode, { VEC_free (operand_entry_t, heap, *ops); *ops = NULL; - add_to_ops_vec (ops, fold_convert (TREE_TYPE (last->op), - integer_zero_node)); + add_to_ops_vec (ops, build_zero_cst (TREE_TYPE (last->op))); *all_done = true; } else @@ -536,8 +534,7 @@ eliminate_plus_minus_pair (enum tree_code opcode, } VEC_ordered_remove (operand_entry_t, *ops, i); - add_to_ops_vec (ops, fold_convert(TREE_TYPE (oe->op), - integer_zero_node)); + add_to_ops_vec (ops, build_zero_cst (TREE_TYPE (oe->op))); VEC_ordered_remove (operand_entry_t, *ops, currindex); reassociate_stats.ops_eliminated ++; @@ -624,7 +621,7 @@ eliminate_not_pairs (enum tree_code opcode, } if (opcode == BIT_AND_EXPR) - oe->op = fold_convert (TREE_TYPE (oe->op), integer_zero_node); + oe->op = build_zero_cst (TREE_TYPE (oe->op)); else if (opcode == BIT_IOR_EXPR) oe->op = build_low_bits_mask (TREE_TYPE (oe->op), TYPE_PRECISION (TREE_TYPE (oe->op))); @@ -1017,7 +1014,7 @@ undistribute_ops_list (enum tree_code opcode, candidates = sbitmap_alloc (length); sbitmap_zero (candidates); nr_candidates = 0; - for (i = 0; VEC_iterate (operand_entry_t, *ops, i, oe1); ++i) + FOR_EACH_VEC_ELT (operand_entry_t, *ops, i, oe1) { enum tree_code dcode; gimple oe1def; @@ -1068,7 +1065,7 @@ undistribute_ops_list (enum tree_code opcode, linearize_expr_tree (&subops[i], oedef, associative_tree_code (oecode), false); - for (j = 0; VEC_iterate (operand_entry_t, subops[i], j, oe1); ++j) + FOR_EACH_VEC_ELT (operand_entry_t, subops[i], j, oe1) { oecount c; void **slot; @@ -1094,14 +1091,13 @@ undistribute_ops_list (enum tree_code opcode, htab_delete (ctable); /* Sort the counting table. */ - qsort (VEC_address (oecount, cvec), VEC_length (oecount, cvec), - sizeof (oecount), oecount_cmp); + VEC_qsort (oecount, cvec, oecount_cmp); if (dump_file && (dump_flags & TDF_DETAILS)) { oecount *c; fprintf (dump_file, "Candidates:\n"); - for (j = 0; VEC_iterate (oecount, cvec, j, c); ++j) + FOR_EACH_VEC_ELT (oecount, cvec, j, c) { fprintf (dump_file, " %u %s: ", c->cnt, c->oecode == MULT_EXPR @@ -1140,7 +1136,7 @@ undistribute_ops_list (enum tree_code opcode, if (oecode != c->oecode) continue; - for (j = 0; VEC_iterate (operand_entry_t, subops[i], j, oe1); ++j) + FOR_EACH_VEC_ELT (operand_entry_t, subops[i], j, oe1) { if (oe1->op == c->op) { @@ -1165,7 +1161,7 @@ undistribute_ops_list (enum tree_code opcode, fprintf (dump_file, "Building ("); print_generic_expr (dump_file, oe1->op, 0); } - tmpvar = create_tmp_var (TREE_TYPE (oe1->op), NULL); + tmpvar = create_tmp_reg (TREE_TYPE (oe1->op), NULL); add_referenced_var (tmpvar); zero_one_operation (&oe1->op, c->oecode, c->op); EXECUTE_IF_SET_IN_SBITMAP (candidates2, first+1, i, sbi0) @@ -1179,7 +1175,7 @@ undistribute_ops_list (enum tree_code opcode, } zero_one_operation (&oe2->op, c->oecode, c->op); sum = build_and_add_sum (tmpvar, oe1->op, oe2->op, opcode); - oe2->op = fold_convert (TREE_TYPE (oe2->op), integer_zero_node); + oe2->op = build_zero_cst (TREE_TYPE (oe2->op)); oe2->rank = 0; oe1->op = gimple_get_lhs (sum); } @@ -1215,6 +1211,122 @@ undistribute_ops_list (enum tree_code opcode, return changed; } +/* If OPCODE is BIT_IOR_EXPR or BIT_AND_EXPR and CURR is a comparison + expression, examine the other OPS to see if any of them are comparisons + of the same values, which we may be able to combine or eliminate. + For example, we can rewrite (a < b) | (a == b) as (a <= b). */ + +static bool +eliminate_redundant_comparison (enum tree_code opcode, + VEC (operand_entry_t, heap) **ops, + unsigned int currindex, + operand_entry_t curr) +{ + tree op1, op2; + enum tree_code lcode, rcode; + gimple def1, def2; + int i; + operand_entry_t oe; + + if (opcode != BIT_IOR_EXPR && opcode != BIT_AND_EXPR) + return false; + + /* Check that CURR is a comparison. */ + if (TREE_CODE (curr->op) != SSA_NAME) + return false; + def1 = SSA_NAME_DEF_STMT (curr->op); + if (!is_gimple_assign (def1)) + return false; + lcode = gimple_assign_rhs_code (def1); + if (TREE_CODE_CLASS (lcode) != tcc_comparison) + return false; + op1 = gimple_assign_rhs1 (def1); + op2 = gimple_assign_rhs2 (def1); + + /* Now look for a similar comparison in the remaining OPS. */ + for (i = currindex + 1; + VEC_iterate (operand_entry_t, *ops, i, oe); + i++) + { + tree t; + + if (TREE_CODE (oe->op) != SSA_NAME) + continue; + def2 = SSA_NAME_DEF_STMT (oe->op); + if (!is_gimple_assign (def2)) + continue; + rcode = gimple_assign_rhs_code (def2); + if (TREE_CODE_CLASS (rcode) != tcc_comparison) + continue; + + /* If we got here, we have a match. See if we can combine the + two comparisons. */ + if (opcode == BIT_IOR_EXPR) + t = maybe_fold_or_comparisons (lcode, op1, op2, + rcode, gimple_assign_rhs1 (def2), + gimple_assign_rhs2 (def2)); + else + t = maybe_fold_and_comparisons (lcode, op1, op2, + rcode, gimple_assign_rhs1 (def2), + gimple_assign_rhs2 (def2)); + if (!t) + continue; + + /* maybe_fold_and_comparisons and maybe_fold_or_comparisons + always give us a boolean_type_node value back. If the original + BIT_AND_EXPR or BIT_IOR_EXPR was of a wider integer type, + we need to convert. */ + if (!useless_type_conversion_p (TREE_TYPE (curr->op), TREE_TYPE (t))) + t = fold_convert (TREE_TYPE (curr->op), t); + + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "Equivalence: "); + print_generic_expr (dump_file, curr->op, 0); + fprintf (dump_file, " %s ", op_symbol_code (opcode)); + print_generic_expr (dump_file, oe->op, 0); + fprintf (dump_file, " -> "); + print_generic_expr (dump_file, t, 0); + fprintf (dump_file, "\n"); + } + + /* Now we can delete oe, as it has been subsumed by the new combined + expression t. */ + VEC_ordered_remove (operand_entry_t, *ops, i); + reassociate_stats.ops_eliminated ++; + + /* If t is the same as curr->op, we're done. Otherwise we must + replace curr->op with t. Special case is if we got a constant + back, in which case we add it to the end instead of in place of + the current entry. */ + if (TREE_CODE (t) == INTEGER_CST) + { + VEC_ordered_remove (operand_entry_t, *ops, currindex); + add_to_ops_vec (ops, t); + } + else if (!operand_equal_p (t, curr->op, 0)) + { + tree tmpvar; + gimple sum; + enum tree_code subcode; + tree newop1; + tree newop2; + gcc_assert (COMPARISON_CLASS_P (t)); + tmpvar = create_tmp_var (TREE_TYPE (t), NULL); + add_referenced_var (tmpvar); + extract_ops_from_tree (t, &subcode, &newop1, &newop2); + STRIP_USELESS_TYPE_CONVERSION (newop1); + STRIP_USELESS_TYPE_CONVERSION (newop2); + gcc_checking_assert (is_gimple_val (newop1) + && is_gimple_val (newop2)); + sum = build_and_add_sum (tmpvar, newop1, newop2, subcode); + curr->op = gimple_get_lhs (sum); + } + return true; + } + + return false; +} /* Perform various identities and other optimizations on the list of operand entries, stored in OPS. The tree code for the binary @@ -1276,7 +1388,8 @@ optimize_ops_list (enum tree_code opcode, if (eliminate_not_pairs (opcode, ops, i, oe)) return; if (eliminate_duplicate_pair (opcode, ops, &done, i, oe, oelast) - || (!done && eliminate_plus_minus_pair (opcode, ops, i, oe))) + || (!done && eliminate_plus_minus_pair (opcode, ops, i, oe)) + || (!done && eliminate_redundant_comparison (opcode, ops, i, oe))) { if (done) return; @@ -1673,13 +1786,15 @@ linearize_expr_tree (VEC(operand_entry_t, heap) **ops, gimple stmt, if (TREE_CODE (binlhs) == SSA_NAME) { binlhsdef = SSA_NAME_DEF_STMT (binlhs); - binlhsisreassoc = is_reassociable_op (binlhsdef, rhscode, loop); + binlhsisreassoc = (is_reassociable_op (binlhsdef, rhscode, loop) + && !stmt_could_throw_p (binlhsdef)); } if (TREE_CODE (binrhs) == SSA_NAME) { binrhsdef = SSA_NAME_DEF_STMT (binrhs); - binrhsisreassoc = is_reassociable_op (binrhsdef, rhscode, loop); + binrhsisreassoc = (is_reassociable_op (binrhsdef, rhscode, loop) + && !stmt_could_throw_p (binrhsdef)); } /* If the LHS is not reassociable, but the RHS is, we need to swap @@ -1753,7 +1868,7 @@ repropagate_negates (void) unsigned int i = 0; tree negate; - for (i = 0; VEC_iterate (tree, plus_negates, i, negate); i++) + FOR_EACH_VEC_ELT (tree, plus_negates, i, negate) { gimple user = get_single_immediate_use (negate); @@ -1838,9 +1953,9 @@ static bool can_reassociate_p (tree op) { tree type = TREE_TYPE (op); - if (INTEGRAL_TYPE_P (type) + if ((INTEGRAL_TYPE_P (type) && TYPE_OVERFLOW_WRAPS (type)) || NON_SAT_FIXED_POINT_TYPE_P (type) - || (flag_associative_math && SCALAR_FLOAT_TYPE_P (type))) + || (flag_associative_math && FLOAT_TYPE_P (type))) return true; return false; } @@ -1914,7 +2029,8 @@ reassociate_bb (basic_block bb) { gimple stmt = gsi_stmt (gsi); - if (is_gimple_assign (stmt)) + if (is_gimple_assign (stmt) + && !stmt_could_throw_p (stmt)) { tree lhs, rhs1, rhs2; enum tree_code rhs_code = gimple_assign_rhs_code (stmt); @@ -1954,9 +2070,16 @@ reassociate_bb (basic_block bb) rhs1 = gimple_assign_rhs1 (stmt); rhs2 = gimple_assign_rhs2 (stmt); - if (!can_reassociate_p (lhs) - || !can_reassociate_p (rhs1) - || !can_reassociate_p (rhs2)) + /* For non-bit or min/max operations we can't associate + all types. Verify that here. */ + if (rhs_code != BIT_IOR_EXPR + && rhs_code != BIT_AND_EXPR + && rhs_code != BIT_XOR_EXPR + && rhs_code != MIN_EXPR + && rhs_code != MAX_EXPR + && (!can_reassociate_p (lhs) + || !can_reassociate_p (rhs1) + || !can_reassociate_p (rhs2))) continue; if (associative_tree_code (rhs_code)) @@ -1970,18 +2093,12 @@ reassociate_bb (basic_block bb) gimple_set_visited (stmt, true); linearize_expr_tree (&ops, stmt, true, true); - qsort (VEC_address (operand_entry_t, ops), - VEC_length (operand_entry_t, ops), - sizeof (operand_entry_t), - sort_by_operand_rank); + VEC_qsort (operand_entry_t, ops, sort_by_operand_rank); optimize_ops_list (rhs_code, &ops); if (undistribute_ops_list (rhs_code, &ops, loop_containing_stmt (stmt))) { - qsort (VEC_address (operand_entry_t, ops), - VEC_length (operand_entry_t, ops), - sizeof (operand_entry_t), - sort_by_operand_rank); + VEC_qsort (operand_entry_t, ops, sort_by_operand_rank); optimize_ops_list (rhs_code, &ops); } @@ -2030,7 +2147,7 @@ dump_ops_vector (FILE *file, VEC (operand_entry_t, heap) *ops) operand_entry_t oe; unsigned int i; - for (i = 0; VEC_iterate (operand_entry_t, ops, i, oe); i++) + FOR_EACH_VEC_ELT (operand_entry_t, ops, i, oe) { fprintf (file, "Op %d -> rank: %d, tree: ", i, oe->rank); print_generic_expr (file, oe->op, 0); @@ -2039,7 +2156,7 @@ dump_ops_vector (FILE *file, VEC (operand_entry_t, heap) *ops) /* Dump the operand entry vector OPS to STDERR. */ -void +DEBUG_FUNCTION void debug_ops_vector (VEC (operand_entry_t, heap) *ops) { dump_ops_vector (stderr, ops); @@ -2081,7 +2198,7 @@ init_reassoc (void) /* Give each argument a distinct rank. */ for (param = DECL_ARGUMENTS (current_function_decl); param; - param = TREE_CHAIN (param)) + param = DECL_CHAIN (param)) { if (gimple_default_def (cfun, param) != NULL) {