/* 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
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
+<http://www.gnu.org/licenses/>. */
#include "config.h"
#include "system.h"
#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"
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:
+
+ 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);
- cmp = XVECEXP (pattern, 0, 0);
- inc = XVECEXP (pattern, 0, 1);
+ 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)
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. */
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))
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);
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;
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);
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);
}
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 ();
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
sequence = get_insns ();
end_sequence ();
emit_insn_after (sequence, BB_END (set_zero));
-
+
set_immediate_dominator (CDI_DOMINATORS, set_zero,
- recount_dominator (CDI_DOMINATORS,
- set_zero));
+ recompute_dominator (CDI_DOMINATORS,
+ set_zero));
}
set_immediate_dominator (CDI_DOMINATORS, new_preheader,
- recount_dominator (CDI_DOMINATORS,
- new_preheader));
+ recompute_dominator (CDI_DOMINATORS,
+ new_preheader));
}
/* Some targets (eg, C4x) need to initialize special looping
/* 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));
}
}
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);
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,
{
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,
{
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;
}
return false;
}
- doloop_modify (loop, desc, doloop_seq, condition, count);
+ doloop_modify (loop, desc, doloop_seq, condition, count,
+ zero_extend_p, mode);
return true;
}
void
doloop_optimize_loops (void)
{
- unsigned i;
+ loop_iterator li;
struct loop *loop;
- for (i = 1; i < current_loops->num; i++)
+ FOR_EACH_LOOP (li, loop, 0)
{
- loop = current_loops->parray[i];
- if (!loop)
- continue;
-
doloop_optimize (loop);
}