X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Floop-doloop.c;h=560d49a32f98440d316aa4622f6c9f654afde0c8;hb=eb65953e5fb04b26d1fdb09340cee6e262d601b7;hp=f59feae78adc90de84bff7947e3f6a5d04cdcfdb;hpb=3f9439d71f45a5eb2d699fb5b6d819143031b5db;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/loop-doloop.c b/gcc/loop-doloop.c index f59feae78ad..560d49a32f9 100644 --- a/gcc/loop-doloop.c +++ b/gcc/loop-doloop.c @@ -1,12 +1,13 @@ /* Perform doloop optimizations - Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc. + Copyright (C) 2004, 2005, 2006, 2007, 2008, 2010 + Free Software Foundation, Inc. Based on code by Michael P. Hayes (m.hayes@elec.canterbury.ac.nz) This file is part of GCC. GCC is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free -Software Foundation; either version 2, or (at your option) any later +Software Foundation; either version 3, or (at your option) any later version. GCC is distributed in the hope that it will be useful, but WITHOUT ANY @@ -15,9 +16,8 @@ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License -along with GCC; see the file COPYING. If not, write to the Free -Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301, USA. */ +along with GCC; see the file COPYING3. If not see +. */ #include "config.h" #include "system.h" @@ -28,7 +28,7 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA #include "expr.h" #include "hard-reg-set.h" #include "basic-block.h" -#include "toplev.h" +#include "diagnostic-core.h" #include "tm_p.h" #include "cfgloop.h" #include "output.h" @@ -70,35 +70,98 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA if it is not a decrement and branch jump insn. */ rtx -doloop_condition_get (rtx pattern) +doloop_condition_get (rtx doloop_pat) { rtx cmp; rtx inc; rtx reg; rtx inc_src; rtx condition; + rtx pattern; + rtx cc_reg = NULL_RTX; + rtx reg_orig = NULL_RTX; - /* The canonical doloop pattern we expect is: + /* The canonical doloop pattern we expect has one of the following + forms: - (parallel [(set (pc) (if_then_else (condition) - (label_ref (label)) - (pc))) - (set (reg) (plus (reg) (const_int -1))) - (additional clobbers and uses)]) + 1) (parallel [(set (pc) (if_then_else (condition) + (label_ref (label)) + (pc))) + (set (reg) (plus (reg) (const_int -1))) + (additional clobbers and uses)]) - Some targets (IA-64) wrap the set of the loop counter in - an if_then_else too. + The branch must be the first entry of the parallel (also required + by jump.c), and the second entry of the parallel must be a set of + the loop counter register. Some targets (IA-64) wrap the set of + the loop counter in an if_then_else too. - In summary, the branch must be the first entry of the - parallel (also required by jump.c), and the second - entry of the parallel must be a set of the loop counter - register. */ + 2) (set (reg) (plus (reg) (const_int -1)) + (set (pc) (if_then_else (reg != 0) + (label_ref (label)) + (pc))). - if (GET_CODE (pattern) != PARALLEL) - return 0; + Some targets (ARM) do the comparison before the branch, as in the + following form: - cmp = XVECEXP (pattern, 0, 0); - inc = XVECEXP (pattern, 0, 1); + 3) (parallel [(set (cc) (compare ((plus (reg) (const_int -1), 0))) + (set (reg) (plus (reg) (const_int -1)))]) + (set (pc) (if_then_else (cc == NE) + (label_ref (label)) + (pc))) */ + + pattern = PATTERN (doloop_pat); + + if (GET_CODE (pattern) != PARALLEL) + { + rtx cond; + rtx prev_insn = prev_nondebug_insn (doloop_pat); + rtx cmp_arg1, cmp_arg2; + rtx cmp_orig; + + /* In case the pattern is not PARALLEL we expect two forms + of doloop which are cases 2) and 3) above: in case 2) the + decrement immediately precedes the branch, while in case 3) + the compare and decrement instructions immediately precede + the branch. */ + + if (prev_insn == NULL_RTX || !INSN_P (prev_insn)) + return 0; + + cmp = pattern; + if (GET_CODE (PATTERN (prev_insn)) == PARALLEL) + { + /* The third case: the compare and decrement instructions + immediately precede the branch. */ + cmp_orig = XVECEXP (PATTERN (prev_insn), 0, 0); + if (GET_CODE (cmp_orig) != SET) + return 0; + if (GET_CODE (SET_SRC (cmp_orig)) != COMPARE) + return 0; + cmp_arg1 = XEXP (SET_SRC (cmp_orig), 0); + cmp_arg2 = XEXP (SET_SRC (cmp_orig), 1); + if (cmp_arg2 != const0_rtx + || GET_CODE (cmp_arg1) != PLUS) + return 0; + reg_orig = XEXP (cmp_arg1, 0); + if (XEXP (cmp_arg1, 1) != GEN_INT (-1) + || !REG_P (reg_orig)) + return 0; + cc_reg = SET_DEST (cmp_orig); + + inc = XVECEXP (PATTERN (prev_insn), 0, 1); + } + else + inc = PATTERN (prev_insn); + /* We expect the condition to be of the form (reg != 0) */ + cond = XEXP (SET_SRC (cmp), 0); + if (GET_CODE (cond) != NE || XEXP (cond, 1) != const0_rtx) + return 0; + } + else + { + cmp = XVECEXP (pattern, 0, 0); + inc = XVECEXP (pattern, 0, 1); + } /* Check for (set (reg) (something)). */ if (GET_CODE (inc) != SET) @@ -138,9 +201,52 @@ doloop_condition_get (rtx pattern) return 0; if ((XEXP (condition, 0) == reg) + /* For the third case: */ + || ((cc_reg != NULL_RTX) + && (XEXP (condition, 0) == cc_reg) + && (reg_orig == reg)) || (GET_CODE (XEXP (condition, 0)) == PLUS - && XEXP (XEXP (condition, 0), 0) == reg)) + && XEXP (XEXP (condition, 0), 0) == reg)) + { + if (GET_CODE (pattern) != PARALLEL) + /* For the second form we expect: + + (set (reg) (plus (reg) (const_int -1)) + (set (pc) (if_then_else (reg != 0) + (label_ref (label)) + (pc))). + + is equivalent to the following: + + (parallel [(set (pc) (if_then_else (reg != 1) + (label_ref (label)) + (pc))) + (set (reg) (plus (reg) (const_int -1))) + (additional clobbers and uses)]) + + For the third form we expect: + + (parallel [(set (cc) (compare ((plus (reg) (const_int -1)), 0)) + (set (reg) (plus (reg) (const_int -1)))]) + (set (pc) (if_then_else (cc == NE) + (label_ref (label)) + (pc))) + + which is equivalent to the following: + + (parallel [(set (cc) (compare (reg, 1)) + (set (reg) (plus (reg) (const_int -1))) + (set (pc) (if_then_else (NE == cc) + (label_ref (label)) + (pc))))]) + + So we return the second form instead for the two cases. + + */ + condition = gen_rtx_fmt_ee (NE, VOIDmode, inc_src, const1_rtx); + return condition; + } /* ??? If a machine uses a funny comparison, we could return a canonicalized form here. */ @@ -245,7 +351,8 @@ add_test (rtx cond, edge *e, basic_block dest) op0 = force_operand (op0, NULL_RTX); op1 = force_operand (op1, NULL_RTX); label = block_label (dest); - do_compare_rtx_and_jump (op0, op1, code, 0, mode, NULL_RTX, NULL_RTX, label); + do_compare_rtx_and_jump (op0, op1, code, 0, mode, NULL_RTX, + NULL_RTX, label, -1); jump = get_last_insn (); if (!jump || !JUMP_P (jump)) @@ -271,13 +378,12 @@ add_test (rtx cond, edge *e, basic_block dest) redirect_edge_and_branch_force (*e, dest); return false; } - + JUMP_LABEL (jump) = label; /* The jump is supposed to handle an unlikely special case. */ - REG_NOTES (jump) - = gen_rtx_EXPR_LIST (REG_BR_PROB, - const0_rtx, REG_NOTES (jump)); + add_reg_note (jump, REG_BR_PROB, const0_rtx); + LABEL_NUSES (label)++; make_edge (bb, dest, (*e)->flags & ~EDGE_FALLTHRU); @@ -288,11 +394,14 @@ add_test (rtx cond, edge *e, basic_block dest) describes the loop, DESC describes the number of iterations of the loop, and DOLOOP_INSN is the low-overhead looping insn to emit at the end of the loop. CONDITION is the condition separated from the - DOLOOP_SEQ. COUNT is the number of iterations of the LOOP. */ + DOLOOP_SEQ. COUNT is the number of iterations of the LOOP. + ZERO_EXTEND_P says to zero extend COUNT after the increment of it to + word_mode from FROM_MODE. */ static void doloop_modify (struct loop *loop, struct niter_desc *desc, - rtx doloop_seq, rtx condition, rtx count) + rtx doloop_seq, rtx condition, rtx count, + bool zero_extend_p, enum machine_mode from_mode) { rtx counter_reg; rtx tmp, noloop = NULL_RTX; @@ -303,6 +412,7 @@ doloop_modify (struct loop *loop, struct niter_desc *desc, bool increment_count; basic_block loop_end = desc->out_edge->src; enum machine_mode mode; + rtx true_prob_val; jump_insn = BB_END (loop_end); @@ -316,6 +426,10 @@ doloop_modify (struct loop *loop, struct niter_desc *desc, fputs (" iterations).\n", dump_file); } + /* Get the probability of the original branch. If it exists we would + need to update REG_BR_PROB of the new jump_insn. */ + true_prob_val = find_reg_note (jump_insn, REG_BR_PROB, NULL_RTX); + /* Discard original jump to continue loop. The original compare result may still be live, so it cannot be discarded explicitly. */ delete_insn (jump_insn); @@ -361,7 +475,11 @@ doloop_modify (struct loop *loop, struct niter_desc *desc, } if (increment_count) - count = simplify_gen_binary (PLUS, mode, count, const1_rtx); + count = simplify_gen_binary (PLUS, from_mode, count, const1_rtx); + + if (zero_extend_p) + count = simplify_gen_unary (ZERO_EXTEND, word_mode, + count, from_mode); /* Insert initialization of the count register into the loop header. */ start_sequence (); @@ -405,7 +523,7 @@ doloop_modify (struct loop *loop, struct niter_desc *desc, set_zero->count = preheader->count; set_zero->frequency = preheader->frequency; } - + if (EDGE_COUNT (set_zero->preds) == 0) { /* All the conditions were simplified to false, remove the @@ -420,7 +538,7 @@ doloop_modify (struct loop *loop, struct niter_desc *desc, sequence = get_insns (); end_sequence (); emit_insn_after (sequence, BB_END (set_zero)); - + set_immediate_dominator (CDI_DOMINATORS, set_zero, recompute_dominator (CDI_DOMINATORS, set_zero)); @@ -467,9 +585,14 @@ doloop_modify (struct loop *loop, struct niter_desc *desc, /* Add a REG_NONNEG note if the actual or estimated maximum number of iterations is non-negative. */ if (nonneg) + add_reg_note (jump_insn, REG_NONNEG, NULL_RTX); + + /* Update the REG_BR_PROB note. */ + if (true_prob_val) { - REG_NOTES (jump_insn) - = gen_rtx_EXPR_LIST (REG_NONNEG, NULL_RTX, REG_NOTES (jump_insn)); + /* Seems safer to use the branch probability. */ + add_reg_note (jump_insn, REG_BR_PROB, + GEN_INT (desc->in_edge->probability)); } } @@ -492,6 +615,7 @@ doloop_optimize (struct loop *loop) struct niter_desc *desc; unsigned word_mode_size; unsigned HOST_WIDE_INT word_mode_max; + bool zero_extend_p = false; if (dump_file) fprintf (dump_file, "Doloop: Processing loop %d.\n", loop->num); @@ -531,7 +655,8 @@ doloop_optimize (struct loop *loop) max_cost = COSTS_N_INSNS (PARAM_VALUE (PARAM_MAX_ITERATIONS_COMPUTATION_COST)); - if (rtx_cost (desc->niter_expr, SET) > max_cost) + if (rtx_cost (desc->niter_expr, SET, optimize_loop_for_speed_p (loop)) + > max_cost) { if (dump_file) fprintf (dump_file, @@ -565,8 +690,7 @@ doloop_optimize (struct loop *loop) { if (word_mode_size > GET_MODE_BITSIZE (mode)) { - count = simplify_gen_unary (ZERO_EXTEND, word_mode, - count, mode); + zero_extend_p = true; iterations = simplify_gen_unary (ZERO_EXTEND, word_mode, iterations, mode); iterations_max = simplify_gen_unary (ZERO_EXTEND, word_mode, @@ -598,9 +722,7 @@ doloop_optimize (struct loop *loop) { while (NEXT_INSN (doloop_pat) != NULL_RTX) doloop_pat = NEXT_INSN (doloop_pat); - if (JUMP_P (doloop_pat)) - doloop_pat = PATTERN (doloop_pat); - else + if (!JUMP_P (doloop_pat)) doloop_pat = NULL_RTX; } @@ -612,7 +734,8 @@ doloop_optimize (struct loop *loop) return false; } - doloop_modify (loop, desc, doloop_seq, condition, count); + doloop_modify (loop, desc, doloop_seq, condition, count, + zero_extend_p, mode); return true; }