summaryrefslogtreecommitdiffstats
path: root/gcc
diff options
context:
space:
mode:
authorrakdver <rakdver@138bc75d-0d04-0410-961f-82ee72b054a4>2004-03-18 16:42:34 +0000
committerrakdver <rakdver@138bc75d-0d04-0410-961f-82ee72b054a4>2004-03-18 16:42:34 +0000
commit2d49f8240d0215badf73b1984dade82a824c2ea0 (patch)
tree245f4992ca85428a919452579f49376b65e76f95 /gcc
parent20ebc48fe6ad018a6aa7f9958b7c46cf7b54e6ab (diff)
downloadppe42-gcc-2d49f8240d0215badf73b1984dade82a824c2ea0.tar.gz
ppe42-gcc-2d49f8240d0215badf73b1984dade82a824c2ea0.zip
* doloop.c: Removed.
* loop-doloop.c: New file. * Makefile.in (doloop.o): Remove. (loop-doloop.o): New. * cfgloop.h (get_loop_level, doloop_optimize_loops): Declare. * cfgloopanal.c (get_loop_level): New function. * loop-iv.c (iv_number_of_iterations): Handle case when loop is leaved immediatelly. * loop.c (strength_reduce): Do not call doloop optimization. * loop.h (LOOP_BCT): Removed. * passes.c (rest_of_handle_loop_optimize): Do not use LOOP_BCT. (rest_of_handle_loop2): Call doloop_optimize_loops. (rest_of_compilation): Test for optimizations moved to rest_of_handle_loop2. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@79625 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog17
-rw-r--r--gcc/Makefile.in8
-rw-r--r--gcc/cfgloop.h2
-rw-r--r--gcc/cfgloopanal.c17
-rw-r--r--gcc/doloop.c883
-rw-r--r--gcc/loop-doloop.c553
-rw-r--r--gcc/loop-iv.c4
-rw-r--r--gcc/loop.c17
-rw-r--r--gcc/loop.h5
-rw-r--r--gcc/passes.c18
10 files changed, 612 insertions, 912 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 6058c6caf6d..94a75a4d74c 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,20 @@
+2004-03-18 Zdenek Dvorak <rakdver@atrey.karlin.mff.cuni.cz>
+
+ * doloop.c: Removed.
+ * loop-doloop.c: New file.
+ * Makefile.in (doloop.o): Remove.
+ (loop-doloop.o): New.
+ * cfgloop.h (get_loop_level, doloop_optimize_loops): Declare.
+ * cfgloopanal.c (get_loop_level): New function.
+ * loop-iv.c (iv_number_of_iterations): Handle case when loop
+ is leaved immediatelly.
+ * loop.c (strength_reduce): Do not call doloop optimization.
+ * loop.h (LOOP_BCT): Removed.
+ * passes.c (rest_of_handle_loop_optimize): Do not use LOOP_BCT.
+ (rest_of_handle_loop2): Call doloop_optimize_loops.
+ (rest_of_compilation): Test for optimizations moved to
+ rest_of_handle_loop2.
+
2004-03-17 Fariborz Jahanian <fjahanian@apple.com>
* config/rs6000/rs6000.c (rs6000_stack_info): correct reg_size
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index e815cf3ecc1..84103f259c7 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -849,7 +849,7 @@ OBJS-common = \
cfg.o cfganal.o cfgbuild.o cfgcleanup.o cfglayout.o cfgloop.o \
cfgloopanal.o cfgloopmanip.o loop-init.o loop-unswitch.o loop-unroll.o \
cfgrtl.o combine.o conflict.o convert.o coverage.o cse.o cselib.o \
- dbxout.o debug.o df.o diagnostic.o dojump.o doloop.o dominance.o \
+ dbxout.o debug.o df.o diagnostic.o dojump.o dominance.o loop-doloop.o \
dwarf2asm.o dwarf2out.o emit-rtl.o except.o explow.o loop-iv.o \
expmed.o expr.o final.o flow.o fold-const.o function.o gcse.o \
genrtl.o ggc-common.o global.o graph.o gtype-desc.o \
@@ -1702,9 +1702,9 @@ loop.o : loop.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) flags.h $(L
insn-config.h $(REGS_H) hard-reg-set.h $(RECOG_H) $(EXPR_H) \
real.h $(PREDICT_H) $(BASIC_BLOCK_H) function.h cfgloop.h \
toplev.h varray.h except.h cselib.h $(OPTABS_H) $(TM_P_H) $(GGC_H)
-doloop.o : doloop.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) flags.h \
- $(LOOP_H) $(EXPR_H) hard-reg-set.h $(BASIC_BLOCK_H) $(TM_P_H) toplev.h \
- cfgloop.h
+loop-doloop.o : loop-doloop.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
+ $(RTL_H) flags.h $(EXPR_H) hard-reg-set.h $(BASIC_BLOCK_H) $(TM_P_H) \
+ toplev.h cfgloop.h output.h $(PARAMS_H)
unroll.o : unroll.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) insn-config.h \
function.h $(INTEGRATE_H) $(REGS_H) $(RECOG_H) flags.h $(EXPR_H) $(LOOP_H) toplev.h \
hard-reg-set.h varray.h $(BASIC_BLOCK_H) $(TM_P_H) $(PREDICT_H) $(PARAMS_H) \
diff --git a/gcc/cfgloop.h b/gcc/cfgloop.h
index 8a24c15f271..b233d2652c6 100644
--- a/gcc/cfgloop.h
+++ b/gcc/cfgloop.h
@@ -247,6 +247,7 @@ extern bool flow_bb_inside_loop_p (const struct loop *, const basic_block);
extern struct loop * find_common_loop (struct loop *, struct loop *);
extern int num_loop_insns (struct loop *);
extern int average_num_loop_insns (struct loop *);
+extern unsigned get_loop_level (const struct loop *);
/* Loops & cfg manipulation. */
extern basic_block *get_loop_body (const struct loop *);
@@ -417,3 +418,4 @@ enum
};
extern void unroll_and_peel_loops (struct loops *, int);
+extern void doloop_optimize_loops (struct loops *);
diff --git a/gcc/cfgloopanal.c b/gcc/cfgloopanal.c
index 9b3ffa0c8ae..63d6f4121b0 100644
--- a/gcc/cfgloopanal.c
+++ b/gcc/cfgloopanal.c
@@ -457,3 +457,20 @@ expected_loop_iterations (const struct loop *loop)
return (freq_latch + freq_in - 1) / freq_in;
}
}
+
+/* Returns the maximum level of nesting of subloops of LOOP. */
+
+unsigned
+get_loop_level (const struct loop *loop)
+{
+ const struct loop *ploop;
+ unsigned mx = 0, l;
+
+ for (ploop = loop->inner; ploop; ploop = ploop->next)
+ {
+ l = get_loop_level (ploop);
+ if (l >= mx)
+ mx = l + 1;
+ }
+ return mx;
+}
diff --git a/gcc/doloop.c b/gcc/doloop.c
deleted file mode 100644
index 6d4840a236c..00000000000
--- a/gcc/doloop.c
+++ /dev/null
@@ -1,883 +0,0 @@
-/* Perform doloop optimizations
- Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004
- Free Software Foundation, Inc.
- Contributed 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
-version.
-
-GCC is distributed in the hope that it will be useful, but WITHOUT ANY
-WARRANTY; without even the implied warranty of MERCHANTABILITY or
-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, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA. */
-
-#include "config.h"
-#include "system.h"
-#include "coretypes.h"
-#include "tm.h"
-#include "rtl.h"
-#include "flags.h"
-#include "expr.h"
-#include "loop.h"
-#include "hard-reg-set.h"
-#include "basic-block.h"
-#include "toplev.h"
-#include "tm_p.h"
-#include "cfgloop.h"
-
-
-/* This module is used to modify loops with a determinable number of
- iterations to use special low-overhead looping instructions.
-
- It first validates whether the loop is well behaved and has a
- determinable number of iterations (either at compile or run-time).
- It then modifies the loop to use a low-overhead looping pattern as
- follows:
-
- 1. A pseudo register is allocated as the loop iteration counter.
-
- 2. The number of loop iterations is calculated and is stored
- in the loop counter.
-
- 3. At the end of the loop, the jump insn is replaced by the
- doloop_end pattern. The compare must remain because it might be
- used elsewhere. If the loop-variable or condition register are
- used elsewhere, they will be eliminated by flow.
-
- 4. An optional doloop_begin pattern is inserted at the top of the
- loop.
-*/
-
-
-#ifdef HAVE_doloop_end
-
-static rtx doloop_condition_get (rtx);
-static unsigned HOST_WIDE_INT doloop_iterations_max (const struct loop_info *,
- enum machine_mode, int);
-static int doloop_valid_p (const struct loop *, rtx);
-static int doloop_modify (const struct loop *, rtx, rtx, rtx, rtx, rtx);
-static int doloop_modify_runtime (const struct loop *, rtx, rtx, rtx,
- enum machine_mode, rtx);
-
-
-/* Return the loop termination condition for PATTERN or zero
- if it is not a decrement and branch jump insn. */
-static rtx
-doloop_condition_get (rtx pattern)
-{
- rtx cmp;
- rtx inc;
- rtx reg;
- rtx condition;
-
- /* The canonical doloop pattern we expect is:
-
- (parallel [(set (pc) (if_then_else (condition)
- (label_ref (label))
- (pc)))
- (set (reg) (plus (reg) (const_int -1)))
- (additional clobbers and uses)])
-
- Some machines (IA-64) make the decrement conditional on
- the condition as well, so we don't bother verifying the
- actual decrement. 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. */
-
- if (GET_CODE (pattern) != PARALLEL)
- return 0;
-
- cmp = XVECEXP (pattern, 0, 0);
- inc = XVECEXP (pattern, 0, 1);
-
- /* Check for (set (reg) (something)). */
- if (GET_CODE (inc) != SET || ! REG_P (SET_DEST (inc)))
- return 0;
-
- /* Extract loop counter register. */
- reg = SET_DEST (inc);
-
- /* Check for (set (pc) (if_then_else (condition)
- (label_ref (label))
- (pc))). */
- if (GET_CODE (cmp) != SET
- || SET_DEST (cmp) != pc_rtx
- || GET_CODE (SET_SRC (cmp)) != IF_THEN_ELSE
- || GET_CODE (XEXP (SET_SRC (cmp), 1)) != LABEL_REF
- || XEXP (SET_SRC (cmp), 2) != pc_rtx)
- return 0;
-
- /* Extract loop termination condition. */
- condition = XEXP (SET_SRC (cmp), 0);
-
- if ((GET_CODE (condition) != GE && GET_CODE (condition) != NE)
- || GET_CODE (XEXP (condition, 1)) != CONST_INT)
- return 0;
-
- if (XEXP (condition, 0) == reg)
- return condition;
-
- if (GET_CODE (XEXP (condition, 0)) == PLUS
- && XEXP (XEXP (condition, 0), 0) == reg)
- return condition;
-
- /* ??? If a machine uses a funny comparison, we could return a
- canonicalised form here. */
-
- return 0;
-}
-
-
-/* Return an estimate of the maximum number of loop iterations for the
- loop specified by LOOP or zero if the loop is not normal.
- MODE is the mode of the iteration count and NONNEG is nonzero if
- the iteration count has been proved to be non-negative. */
-static unsigned HOST_WIDE_INT
-doloop_iterations_max (const struct loop_info *loop_info,
- enum machine_mode mode, int nonneg)
-{
- unsigned HOST_WIDE_INT n_iterations_max;
- enum rtx_code code;
- rtx min_value;
- rtx max_value;
- HOST_WIDE_INT abs_inc;
- int neg_inc;
-
- neg_inc = 0;
- abs_inc = INTVAL (loop_info->increment);
- if (abs_inc < 0)
- {
- abs_inc = -abs_inc;
- neg_inc = 1;
- }
-
- if (neg_inc)
- {
- code = swap_condition (loop_info->comparison_code);
- min_value = loop_info->final_equiv_value;
- max_value = loop_info->initial_equiv_value;
- }
- else
- {
- code = loop_info->comparison_code;
- min_value = loop_info->initial_equiv_value;
- max_value = loop_info->final_equiv_value;
- }
-
- /* Since the loop has a VTOP, we know that the initial test will be
- true and thus the value of max_value should be greater than the
- value of min_value. Thus the difference should always be positive
- and the code must be LT, LE, LTU, LEU, or NE. Otherwise the loop is
- not normal, e.g., `for (i = 0; i < 10; i--)'. */
- switch (code)
- {
- case LTU:
- case LEU:
- {
- unsigned HOST_WIDE_INT umax;
- unsigned HOST_WIDE_INT umin;
-
- if (GET_CODE (min_value) == CONST_INT)
- umin = INTVAL (min_value);
- else
- umin = 0;
-
- if (GET_CODE (max_value) == CONST_INT)
- umax = INTVAL (max_value);
- else
- umax = ((unsigned) 2 << (GET_MODE_BITSIZE (mode) - 1)) - 1;
-
- n_iterations_max = umax - umin;
- break;
- }
-
- case LT:
- case LE:
- {
- HOST_WIDE_INT smax;
- HOST_WIDE_INT smin;
-
- if (GET_CODE (min_value) == CONST_INT)
- smin = INTVAL (min_value);
- else
- smin = -((unsigned) 1 << (GET_MODE_BITSIZE (mode) - 1));
-
- if (GET_CODE (max_value) == CONST_INT)
- smax = INTVAL (max_value);
- else
- smax = ((unsigned) 1 << (GET_MODE_BITSIZE (mode) - 1)) - 1;
-
- n_iterations_max = smax - smin;
- break;
- }
-
- case NE:
- if (GET_CODE (min_value) == CONST_INT
- && GET_CODE (max_value) == CONST_INT)
- n_iterations_max = INTVAL (max_value) - INTVAL (min_value);
- else
- /* We need to conservatively assume that we might have the maximum
- number of iterations without any additional knowledge. */
- n_iterations_max = ((unsigned) 2 << (GET_MODE_BITSIZE (mode) - 1)) - 1;
- break;
-
- default:
- return 0;
- }
-
- n_iterations_max /= abs_inc;
-
- /* If we know that the iteration count is non-negative then adjust
- n_iterations_max if it is so large that it appears negative. */
- if (nonneg
- && n_iterations_max > ((unsigned) 1 << (GET_MODE_BITSIZE (mode) - 1)))
- n_iterations_max = ((unsigned) 1 << (GET_MODE_BITSIZE (mode) - 1)) - 1;
-
- return n_iterations_max;
-}
-
-
-/* Return nonzero if the loop specified by LOOP is suitable for
- the use of special low-overhead looping instructions. */
-static int
-doloop_valid_p (const struct loop *loop, rtx jump_insn)
-{
- const struct loop_info *loop_info = LOOP_INFO (loop);
-
- /* The loop must have a conditional jump at the end. */
- if (! any_condjump_p (jump_insn)
- || ! onlyjump_p (jump_insn))
- {
- if (loop_dump_stream)
- fprintf (loop_dump_stream,
- "Doloop: Invalid jump at loop end.\n");
- return 0;
- }
-
- /* Give up if a loop has been completely unrolled. */
- if (loop_info->n_iterations == loop_info->unroll_number)
- {
- if (loop_dump_stream)
- fprintf (loop_dump_stream,
- "Doloop: Loop completely unrolled.\n");
- return 0;
- }
-
- /* The loop must have a single exit target. A break or return
- statement within a loop will generate multiple loop exits.
- Another example of a loop that currently generates multiple exit
- targets is for (i = 0; i < (foo ? 8 : 4); i++) { }. */
- if (loop_info->has_multiple_exit_targets || loop->exit_count)
- {
- if (loop_dump_stream)
- fprintf (loop_dump_stream,
- "Doloop: Loop has multiple exit targets.\n");
- return 0;
- }
-
- /* An indirect jump may jump out of the loop. */
- if (loop_info->has_indirect_jump)
- {
- if (loop_dump_stream)
- fprintf (loop_dump_stream,
- "Doloop: Indirect jump in function.\n");
- return 0;
- }
-
- /* A called function may clobber any special registers required for
- low-overhead looping. */
- if (loop_info->has_call)
- {
- if (loop_dump_stream)
- fprintf (loop_dump_stream,
- "Doloop: Function call in loop.\n");
- return 0;
- }
-
- /* Some targets (eg, PPC) use the count register for branch on table
- instructions. ??? This should be a target specific check. */
- if (loop_info->has_tablejump)
- {
- if (loop_dump_stream)
- fprintf (loop_dump_stream,
- "Doloop: Computed branch in the loop.\n");
- return 0;
- }
-
- if (! loop_info->increment)
- {
- if (loop_dump_stream)
- fprintf (loop_dump_stream,
- "Doloop: Could not determine iteration info.\n");
- return 0;
- }
-
- if (GET_CODE (loop_info->increment) != CONST_INT)
- {
- if (loop_dump_stream)
- fprintf (loop_dump_stream,
- "Doloop: Increment not an integer constant.\n");
- return 0;
- }
-
- /* There is no guarantee that a NE loop will terminate if the
- absolute increment is not unity. ??? We could compute this
- condition at run-time and have an additional jump around the loop
- to ensure an infinite loop. */
- if (loop_info->comparison_code == NE
- && !loop_info->preconditioned
- && INTVAL (loop_info->increment) != -1
- && INTVAL (loop_info->increment) != 1)
- {
- if (loop_dump_stream)
- fprintf (loop_dump_stream,
- "Doloop: NE loop with non-unity increment.\n");
- return 0;
- }
-
- /* Check for loops that may not terminate under special conditions. */
- if (! loop_info->n_iterations
- && ((loop_info->comparison_code == LEU
- && INTVAL (loop_info->increment) > 0)
- || (loop_info->comparison_code == GEU
- && INTVAL (loop_info->increment) < 0)
- || (loop_info->comparison_code == LTU
- && INTVAL (loop_info->increment) > 1)
- || (loop_info->comparison_code == GTU
- && INTVAL (loop_info->increment) < -1)))
- {
- /* If the comparison is LEU and the comparison value is UINT_MAX
- then the loop will not terminate. Similarly, if the
- comparison code is GEU and the comparison value is 0, the
- loop will not terminate.
-
- If the absolute increment is not 1, the loop can be infinite
- even with LTU/GTU, e.g. for (i = 3; i > 0; i -= 2)
-
- Note that with LE and GE, the loop behavior is undefined
- (C++ standard section 5 clause 5) if an overflow occurs, say
- between INT_MAX and INT_MAX + 1. We thus don't have to worry
- about these two cases.
-
- ??? We could compute these conditions at run-time and have a
- additional jump around the loop to ensure an infinite loop.
- However, it is very unlikely that this is the intended
- behavior of the loop and checking for these rare boundary
- conditions would pessimize all other code.
-
- If the loop is executed only a few times an extra check to
- restart the loop could use up most of the benefits of using a
- count register loop. Note however, that normally, this
- restart branch would never execute, so it could be predicted
- well by the CPU. We should generate the pessimistic code by
- default, and have an option, e.g. -funsafe-loops that would
- enable count-register loops in this case. */
- if (loop_dump_stream)
- fprintf (loop_dump_stream,
- "Doloop: Possible infinite iteration case ignored.\n");
- }
-
- return 1;
-}
-
-
-/* Modify the loop to use the low-overhead looping insn where LOOP
- describes the loop, ITERATIONS is an RTX containing the desired
- number of loop iterations, ITERATIONS_MAX is a CONST_INT specifying
- the maximum number of loop iterations, and DOLOOP_INSN is the
- low-overhead looping insn to emit at the end of the loop. This
- returns nonzero if it was successful. */
-static int
-doloop_modify (const struct loop *loop, rtx iterations, rtx iterations_max,
- rtx doloop_seq, rtx start_label, rtx condition)
-{
- rtx counter_reg;
- rtx count;
- rtx sequence;
- rtx jump_insn;
- int nonneg = 0;
- int decrement_count;
-
- jump_insn = prev_nonnote_insn (loop->end);
-
- if (loop_dump_stream)
- {
- fprintf (loop_dump_stream, "Doloop: Inserting doloop pattern (");
- if (GET_CODE (iterations) == CONST_INT)
- fprintf (loop_dump_stream, HOST_WIDE_INT_PRINT_DEC,
- INTVAL (iterations));
- else
- fputs ("runtime", loop_dump_stream);
- fputs (" iterations).", loop_dump_stream);
- }
-
- /* Emit the label that will delimit the top of the loop.
- This has to be done before the delete_insn call below, to prevent
- delete_insn from deleting too much. */
- emit_label_after (start_label, loop->top ? loop->top : loop->start);
- LABEL_NUSES (start_label)++;
-
- /* Discard original jump to continue loop. The original compare
- result may still be live, so it cannot be discarded explicitly. */
- delete_related_insns (jump_insn);
-
- counter_reg = XEXP (condition, 0);
- if (GET_CODE (counter_reg) == PLUS)
- counter_reg = XEXP (counter_reg, 0);
-
- start_sequence ();
-
- count = iterations;
- decrement_count = 0;
- switch (GET_CODE (condition))
- {
- case NE:
- /* Currently only NE tests against zero and one are supported. */
- if (XEXP (condition, 1) == const0_rtx)
- decrement_count = 1;
- else if (XEXP (condition, 1) != const1_rtx)
- abort ();
- break;
-
- case GE:
- /* Currently only GE tests against zero are supported. */
- if (XEXP (condition, 1) != const0_rtx)
- abort ();
-
- /* The iteration count needs decrementing for a GE test. */
- decrement_count = 1;
-
- /* Determine if the iteration counter will be non-negative.
- Note that the maximum value loaded is iterations_max - 1. */
- if ((unsigned HOST_WIDE_INT) INTVAL (iterations_max)
- <= ((unsigned) 1 << (GET_MODE_BITSIZE (GET_MODE (counter_reg)) - 1)))
- nonneg = 1;
- break;
-
- /* Abort if an invalid doloop pattern has been generated. */
- default:
- abort ();
- }
-
- if (decrement_count)
- {
- if (GET_CODE (count) == CONST_INT)
- count = GEN_INT (INTVAL (count) - 1);
- else
- count = expand_simple_binop (GET_MODE (counter_reg), MINUS,
- count, const1_rtx,
- 0, 0, OPTAB_LIB_WIDEN);
- }
-
- /* Insert initialization of the count register into the loop header. */
- convert_move (counter_reg, count, 1);
- sequence = get_insns ();
- end_sequence ();
- emit_insn_before (sequence, loop->start);
-
- /* Some targets (eg, C4x) need to initialize special looping
- registers. */
-#ifdef HAVE_doloop_begin
- {
- rtx init;
-
- init = gen_doloop_begin (counter_reg,
- GET_CODE (iterations) == CONST_INT
- ? iterations : const0_rtx, iterations_max,
- GEN_INT (loop->level));
- if (init)
- {
- start_sequence ();
- emit_insn (init);
- sequence = get_insns ();
- end_sequence ();
- emit_insn_after (sequence, loop->start);
- }
- }
-#endif
-
- /* Insert the new low-overhead looping insn. */
- emit_jump_insn_before (doloop_seq, loop->end);
- jump_insn = prev_nonnote_insn (loop->end);
- JUMP_LABEL (jump_insn) = start_label;
-
- /* Add a REG_NONNEG note if the actual or estimated maximum number
- of iterations is non-negative. */
- if (nonneg)
- {
- REG_NOTES (jump_insn)
- = gen_rtx_EXPR_LIST (REG_NONNEG, NULL_RTX, REG_NOTES (jump_insn));
- }
- return 1;
-}
-
-
-/* Handle the more complex case, where the bounds are not known at
- compile time. In this case we generate a run_time calculation of
- the number of iterations. We rely on the existence of a run-time
- guard to ensure that the loop executes at least once, i.e.,
- initial_value obeys the loop comparison condition. If a guard is
- not present, we emit one. The loop to modify is described by LOOP.
- ITERATIONS_MAX is a CONST_INT specifying the estimated maximum
- number of loop iterations. DOLOOP_INSN is the low-overhead looping
- insn to insert. Returns nonzero if loop successfully modified. */
-static int
-doloop_modify_runtime (const struct loop *loop, rtx iterations_max,
- rtx doloop_seq, rtx start_label,
- enum machine_mode mode, rtx condition)
-{
- const struct loop_info *loop_info = LOOP_INFO (loop);
- HOST_WIDE_INT abs_inc;
- HOST_WIDE_INT abs_loop_inc;
- int neg_inc;
- rtx diff;
- rtx sequence;
- rtx iterations;
- rtx initial_value;
- rtx final_value;
- rtx increment;
- int unsigned_p;
- enum rtx_code comparison_code;
-
- increment = loop_info->increment;
- initial_value = loop_info->initial_value;
- final_value = loop_info->final_value;
-
- neg_inc = 0;
- abs_inc = INTVAL (increment);
- if (abs_inc < 0)
- {
- abs_inc = -abs_inc;
- neg_inc = 1;
- }
-
- comparison_code = loop_info->comparison_code;
- unsigned_p = (comparison_code == LTU
- || comparison_code == LEU
- || comparison_code == GTU
- || comparison_code == GEU
- || comparison_code == NE);
-
- /* The number of iterations (prior to any loop unrolling) is given by:
-
- n = (abs (final - initial) + abs_inc - 1) / abs_inc.
-
- However, it is possible for the summation to overflow, and a
- safer method is:
-
- n = abs (final - initial) / abs_inc;
- n += (abs (final - initial) % abs_inc) != 0;
-
- But when abs_inc is a power of two, the summation won't overflow
- except in cases where the loop never terminates. So we don't
- need to use this more costly calculation.
-
- If the loop has been unrolled, the full calculation is
-
- t1 = abs_inc * unroll_number; increment per loop
- n = (abs (final - initial) + abs_inc - 1) / t1; full loops
- n += (abs (final - initial) + abs_inc - 1) % t1) >= abs_inc;
- partial loop
- which works out to be equivalent to
-
- n = (abs (final - initial) + t1 - 1) / t1;
-
- In the case where the loop was preconditioned, a few iterations
- may have been executed earlier; but 'initial' was adjusted as they
- were executed, so we don't need anything special for that case here.
- As above, when t1 is a power of two we don't need to worry about
- overflow.
-
- The division and modulo operations can be avoided by requiring
- that the increment is a power of 2 (precondition_loop_p enforces
- this requirement). Nevertheless, the RTX_COSTS should be checked
- to see if a fast divmod is available. */
-
- start_sequence ();
- /* abs (final - initial) */
- diff = expand_simple_binop (mode, MINUS,
- copy_rtx (neg_inc ? initial_value : final_value),
- copy_rtx (neg_inc ? final_value : initial_value),
- NULL_RTX, unsigned_p, OPTAB_LIB_WIDEN);
-
- /* Some code transformations can result in code akin to
-
- tmp = i + 1;
- ...
- goto scan_start;
- top:
- tmp = tmp + 1;
- scan_start:
- i = tmp;
- if (i < n) goto top;
-
- We'll have already detected this form of loop in scan_loop,
- and set loop->top and loop->scan_start appropriately.
-
- In this situation, we skip the increment the first time through
- the loop, which results in an incorrect estimate of the number
- of iterations. Adjust the difference to compensate. */
- /* ??? Logically, it would seem this belongs in loop_iterations.
- However, this causes regressions e.g. on x86 execute/20011008-3.c,
- so I do not believe we've properly characterized the exact nature
- of the problem. In the meantime, this fixes execute/20011126-2.c
- on ia64 and some Ada front end miscompilation on ppc. */
-
- if (loop->scan_start)
- {
- rtx iteration_var = loop_info->iteration_var;
- struct loop_ivs *ivs = LOOP_IVS (loop);
- struct iv_class *bl;
-
- if (REG_IV_TYPE (ivs, REGNO (iteration_var)) == BASIC_INDUCT)
- bl = REG_IV_CLASS (ivs, REGNO (iteration_var));
- else if (REG_IV_TYPE (ivs, REGNO (iteration_var)) == GENERAL_INDUCT)
- {
- struct induction *v = REG_IV_INFO (ivs, REGNO (iteration_var));
- bl = REG_IV_CLASS (ivs, REGNO (v->src_reg));
- }
- else
- /* Iteration var must be an induction variable to get here. */
- abort ();
-
- if (INSN_UID (bl->biv->insn) < max_uid_for_loop
- && INSN_LUID (bl->biv->insn) < INSN_LUID (loop->scan_start))
- {
- if (loop_dump_stream)
- fprintf (loop_dump_stream,
- "Doloop: Basic induction var skips initial incr.\n");
-
- diff = expand_simple_binop (mode, PLUS, diff, GEN_INT (abs_inc),
- diff, unsigned_p, OPTAB_LIB_WIDEN);
- }
- }
-
- abs_loop_inc = abs_inc * loop_info->unroll_number;
- if (abs_loop_inc != 1)
- {
- int shift_count;
-
- shift_count = exact_log2 (abs_loop_inc);
- if (shift_count < 0)
- abort ();
-
- /* (abs (final - initial) + abs_inc * unroll_number - 1) */
- diff = expand_simple_binop (GET_MODE (diff), PLUS,
- diff, GEN_INT (abs_loop_inc - 1),
- diff, 1, OPTAB_LIB_WIDEN);
-
- /* (abs (final - initial) + abs_inc * unroll_number - 1)
- / (abs_inc * unroll_number) */
- diff = expand_simple_binop (GET_MODE (diff), LSHIFTRT,
- diff, GEN_INT (shift_count),
- diff, 1, OPTAB_LIB_WIDEN);
- }
- iterations = diff;
-
- /* If there is a NOTE_INSN_LOOP_VTOP, we have a `for' or `while'
- style loop, with a loop exit test at the start. Thus, we can
- assume that the loop condition was true when the loop was
- entered.
-
- `do-while' loops require special treatment since the exit test is
- not executed before the start of the loop. We need to determine
- if the loop will terminate after the first pass and to limit the
- iteration count to one if necessary. */
- if (! loop->vtop)
- {
- if (loop_dump_stream)
- fprintf (loop_dump_stream, "Doloop: Do-while loop.\n");
-
- /* A `do-while' loop must iterate at least once. For code like
- i = initial; do { ... } while (++i < final);
- we will calculate a bogus iteration count if initial > final.
- So detect this and set the iteration count to 1.
- Note that if the loop has been unrolled, then the loop body
- is guaranteed to execute at least once. Also, when the
- comparison is NE, our calculated count will be OK. */
- if (loop_info->unroll_number == 1 && comparison_code != NE)
- {
- rtx label;
-
- /* Emit insns to test if the loop will immediately
- terminate and to set the iteration count to 1 if true. */
- label = gen_label_rtx();
- emit_cmp_and_jump_insns (copy_rtx (initial_value),
- copy_rtx (loop_info->comparison_value),
- comparison_code, NULL_RTX, mode, 0,
- label);
- JUMP_LABEL (get_last_insn ()) = label;
- LABEL_NUSES (label)++;
- emit_move_insn (iterations, const1_rtx);
- emit_label (label);
- }
- }
-
- sequence = get_insns ();
- end_sequence ();
- emit_insn_before (sequence, loop->start);
-
- return doloop_modify (loop, iterations, iterations_max, doloop_seq,
- start_label, condition);
-}
-
-
-/* This is the main entry point. Process loop described by LOOP
- validating that the loop is suitable for conversion to use a low
- overhead looping instruction, replacing the jump insn where
- suitable. We distinguish between loops with compile-time bounds
- and those with run-time bounds. Information from LOOP is used to
- compute the number of iterations and to determine whether the loop
- is a candidate for this optimization. Returns nonzero if loop
- successfully modified. */
-int
-doloop_optimize (const struct loop *loop)
-{
- struct loop_info *loop_info = LOOP_INFO (loop);
- rtx initial_value;
- rtx final_value;
- rtx increment;
- rtx jump_insn;
- enum machine_mode mode;
- unsigned HOST_WIDE_INT n_iterations;
- unsigned HOST_WIDE_INT n_iterations_max;
- rtx doloop_seq, doloop_pat, doloop_reg;
- rtx iterations;
- rtx iterations_max;
- rtx start_label;
- rtx condition;
-
- if (loop_dump_stream)
- fprintf (loop_dump_stream,
- "Doloop: Processing loop %d, enclosed levels %d.\n",
- loop->num, loop->level);
-
- jump_insn = prev_nonnote_insn (loop->end);
-
- /* Check that loop is a candidate for a low-overhead looping insn. */
- if (! doloop_valid_p (loop, jump_insn))
- return 0;
-
- /* Determine if the loop can be safely, and profitably,
- preconditioned. While we don't precondition the loop in a loop
- unrolling sense, this test ensures that the loop is well behaved
- and that the increment is a constant integer. */
- if (! precondition_loop_p (loop, &initial_value, &final_value,
- &increment, &mode))
- {
- if (loop_dump_stream)
- fprintf (loop_dump_stream,
- "Doloop: Cannot precondition loop.\n");
- return 0;
- }
-
- /* Determine or estimate the maximum number of loop iterations. */
- n_iterations = loop_info->n_iterations;
- if (n_iterations)
- {
- /* This is the simple case where the initial and final loop
- values are constants. */
- n_iterations_max = n_iterations;
- }
- else
- {
- int nonneg = find_reg_note (jump_insn, REG_NONNEG, 0) != 0;
-
- /* This is the harder case where the initial and final loop
- values may not be constants. */
- n_iterations_max = doloop_iterations_max (loop_info, mode, nonneg);
-
- if (! n_iterations_max)
- {
- /* We have something like `for (i = 0; i < 10; i--)'. */
- if (loop_dump_stream)
- fprintf (loop_dump_stream,
- "Doloop: Not normal loop.\n");
- return 0;
- }
- }
-
- /* Account for loop unrolling in the iteration count. This will
- have no effect if loop_iterations could not determine the number
- of iterations. */
- n_iterations /= loop_info->unroll_number;
- n_iterations_max /= loop_info->unroll_number;
-
- if (n_iterations && n_iterations < 3)
- {
- if (loop_dump_stream)
- fprintf (loop_dump_stream,
- "Doloop: Too few iterations (%ld) to be profitable.\n",
- (long int) n_iterations);
- return 0;
- }
-
- iterations = GEN_INT (n_iterations);
- iterations_max = GEN_INT (n_iterations_max);
-
- /* Generate looping insn. If the pattern FAILs then give up trying
- to modify the loop since there is some aspect the back-end does
- not like. */
- start_label = gen_label_rtx ();
- doloop_reg = gen_reg_rtx (mode);
- doloop_seq = gen_doloop_end (doloop_reg, iterations, iterations_max,
- GEN_INT (loop->level), start_label);
- if (! doloop_seq && mode != word_mode)
- {
- PUT_MODE (doloop_reg, word_mode);
- doloop_seq = gen_doloop_end (doloop_reg, iterations, iterations_max,
- GEN_INT (loop->level), start_label);
- }
- if (! doloop_seq)
- {
- if (loop_dump_stream)
- fprintf (loop_dump_stream,
- "Doloop: Target unwilling to use doloop pattern!\n");
- return 0;
- }
-
- /* If multiple instructions were created, the last must be the
- jump instruction. Also, a raw define_insn may yield a plain
- pattern. */
- doloop_pat = doloop_seq;
- if (INSN_P (doloop_pat))
- {
- while (NEXT_INSN (doloop_pat) != NULL_RTX)
- doloop_pat = NEXT_INSN (doloop_pat);
- if (GET_CODE (doloop_pat) == JUMP_INSN)
- doloop_pat = PATTERN (doloop_pat);
- else
- doloop_pat = NULL_RTX;
- }
-
- if (! doloop_pat
- || ! (condition = doloop_condition_get (doloop_pat)))
- {
- if (loop_dump_stream)
- fprintf (loop_dump_stream,
- "Doloop: Unrecognizable doloop pattern!\n");
- return 0;
- }
-
- if (n_iterations != 0)
- /* Handle the simpler case, where we know the iteration count at
- compile time. */
- return doloop_modify (loop, iterations, iterations_max, doloop_seq,
- start_label, condition);
- else
- /* Handle the harder case, where we must add additional runtime tests. */
- return doloop_modify_runtime (loop, iterations_max, doloop_seq,
- start_label, mode, condition);
-}
-
-#endif /* HAVE_doloop_end */
diff --git a/gcc/loop-doloop.c b/gcc/loop-doloop.c
new file mode 100644
index 00000000000..b75b9dc03a6
--- /dev/null
+++ b/gcc/loop-doloop.c
@@ -0,0 +1,553 @@
+/* Perform doloop optimizations
+ Copyright (C) 2004 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
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+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, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "rtl.h"
+#include "flags.h"
+#include "expr.h"
+#include "hard-reg-set.h"
+#include "basic-block.h"
+#include "toplev.h"
+#include "tm_p.h"
+#include "cfgloop.h"
+#include "output.h"
+#include "params.h"
+
+/* This module is used to modify loops with a determinable number of
+ iterations to use special low-overhead looping instructions.
+
+ It first validates whether the loop is well behaved and has a
+ determinable number of iterations (either at compile or run-time).
+ It then modifies the loop to use a low-overhead looping pattern as
+ follows:
+
+ 1. A pseudo register is allocated as the loop iteration counter.
+
+ 2. The number of loop iterations is calculated and is stored
+ in the loop counter.
+
+ 3. At the end of the loop, the jump insn is replaced by the
+ doloop_end pattern. The compare must remain because it might be
+ used elsewhere. If the loop-variable or condition register are
+ used elsewhere, they will be eliminated by flow.
+
+ 4. An optional doloop_begin pattern is inserted at the top of the
+ loop.
+
+ TODO The optimization should only performed when either the biv used for exit
+ condition is unused at all except for the exit test, or if we do not have to
+ change its value, since otherwise we have to add a new induction variable,
+ which usually will not pay up (unless the cost of the doloop pattern is
+ somehow extremely lower than the cost of compare & jump, or unless the bct
+ register cannot be used for anything else but doloop -- ??? detect these
+ cases). */
+
+#ifdef HAVE_doloop_end
+
+/* Return the loop termination condition for PATTERN or zero
+ if it is not a decrement and branch jump insn. */
+
+static rtx
+doloop_condition_get (rtx pattern)
+{
+ rtx cmp;
+ rtx inc;
+ rtx reg;
+ rtx condition;
+
+ /* The canonical doloop pattern we expect is:
+
+ (parallel [(set (pc) (if_then_else (condition)
+ (label_ref (label))
+ (pc)))
+ (set (reg) (plus (reg) (const_int -1)))
+ (additional clobbers and uses)])
+
+ Some machines (IA-64) make the decrement conditional on
+ the condition as well, so we don't bother verifying the
+ actual decrement. 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. */
+
+ if (GET_CODE (pattern) != PARALLEL)
+ return 0;
+
+ cmp = XVECEXP (pattern, 0, 0);
+ inc = XVECEXP (pattern, 0, 1);
+
+ /* Check for (set (reg) (something)). */
+ if (GET_CODE (inc) != SET || ! REG_P (SET_DEST (inc)))
+ return 0;
+
+ /* Extract loop counter register. */
+ reg = SET_DEST (inc);
+
+ /* Check for (set (pc) (if_then_else (condition)
+ (label_ref (label))
+ (pc))). */
+ if (GET_CODE (cmp) != SET
+ || SET_DEST (cmp) != pc_rtx
+ || GET_CODE (SET_SRC (cmp)) != IF_THEN_ELSE
+ || GET_CODE (XEXP (SET_SRC (cmp), 1)) != LABEL_REF
+ || XEXP (SET_SRC (cmp), 2) != pc_rtx)
+ return 0;
+
+ /* Extract loop termination condition. */
+ condition = XEXP (SET_SRC (cmp), 0);
+
+ if ((GET_CODE (condition) != GE && GET_CODE (condition) != NE)
+ || GET_CODE (XEXP (condition, 1)) != CONST_INT)
+ return 0;
+
+ if (XEXP (condition, 0) == reg)
+ return condition;
+
+ if (GET_CODE (XEXP (condition, 0)) == PLUS
+ && XEXP (XEXP (condition, 0), 0) == reg)
+ return condition;
+
+ /* ??? If a machine uses a funny comparison, we could return a
+ canonicalised form here. */
+
+ return 0;
+}
+
+/* Return nonzero if the loop specified by LOOP is suitable for
+ the use of special low-overhead looping instructions. DESC
+ describes the number of iterations of the loop. */
+
+static bool
+doloop_valid_p (struct loop *loop, struct niter_desc *desc)
+{
+ basic_block *body = get_loop_body (loop), bb;
+ rtx insn;
+ unsigned i;
+
+ /* Check for loops that may not terminate under special conditions. */
+ if (!desc->simple_p
+ || desc->assumptions
+ || desc->infinite)
+ {
+ /* There are some cases that would require a special attention.
+ For example if the comparison is LEU and the comparison value
+ is UINT_MAX then the loop will not terminate. Similarly, if the
+ comparison code is GEU and the comparison value is 0, the
+ loop will not terminate.
+
+ If the absolute increment is not 1, the loop can be infinite
+ even with LTU/GTU, e.g. for (i = 3; i > 0; i -= 2)
+
+ ??? We could compute these conditions at run-time and have a
+ additional jump around the loop to ensure an infinite loop.
+ However, it is very unlikely that this is the intended
+ behavior of the loop and checking for these rare boundary
+ conditions would pessimize all other code.
+
+ If the loop is executed only a few times an extra check to
+ restart the loop could use up most of the benefits of using a
+ count register loop. Note however, that normally, this
+ restart branch would never execute, so it could be predicted
+ well by the CPU. We should generate the pessimistic code by
+ default, and have an option, e.g. -funsafe-loops that would
+ enable count-register loops in this case. */
+ if (dump_file)
+ fprintf (dump_file, "Doloop: Possible infinite iteration case.\n");
+ return false;
+ }
+
+ for (i = 0; i < loop->num_nodes; i++)
+ {
+ bb = body[i];
+
+ for (insn = BB_HEAD (bb);
+ insn != NEXT_INSN (BB_END (bb));
+ insn = NEXT_INSN (insn))
+ {
+ /* A called function may clobber any special registers required for
+ low-overhead looping. */
+ if (GET_CODE (insn) == CALL_INSN)
+ {
+ if (dump_file)
+ fprintf (dump_file, "Doloop: Function call in loop.\n");
+ return false;
+ }
+
+ /* Some targets (eg, PPC) use the count register for branch on table
+ instructions. ??? This should be a target specific check. */
+ if (GET_CODE (insn) == JUMP_INSN
+ && (GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC
+ || GET_CODE (PATTERN (insn)) == ADDR_VEC))
+ {
+ if (dump_file)
+ fprintf (dump_file, "Doloop: Computed branch in the loop.\n");
+ return false;
+ }
+ }
+ }
+ free (body);
+
+ return true;
+}
+
+/* Adds test of COND jumping to DEST to the end of BB. */
+
+static void
+add_test (rtx cond, basic_block bb, basic_block dest)
+{
+ rtx seq, jump, label;
+ enum machine_mode mode;
+ rtx op0 = XEXP (cond, 0), op1 = XEXP (cond, 1);
+ enum rtx_code code = GET_CODE (cond);
+
+ mode = GET_MODE (XEXP (cond, 0));
+ if (mode == VOIDmode)
+ mode = GET_MODE (XEXP (cond, 1));
+
+ start_sequence ();
+ 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);
+
+ jump = get_last_insn ();
+ JUMP_LABEL (jump) = label;
+
+ /* The jump is supposed to handle an unlikely special case. */
+ REG_NOTES (jump)
+ = gen_rtx_EXPR_LIST (REG_BR_PROB,
+ GEN_INT (0), REG_NOTES (jump));
+
+ LABEL_NUSES (label)++;
+
+ seq = get_insns ();
+ end_sequence ();
+ emit_insn_after (seq, BB_END (bb));
+}
+
+/* Modify the loop to use the low-overhead looping insn where LOOP
+ 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. */
+
+static void
+doloop_modify (struct loop *loop, struct niter_desc *desc,
+ rtx doloop_seq, rtx condition)
+{
+ rtx counter_reg;
+ rtx count, tmp, noloop = NULL_RTX;
+ rtx sequence;
+ rtx jump_insn;
+ rtx jump_label;
+ int nonneg = 0, irr;
+ bool increment_count;
+ basic_block loop_end = desc->out_edge->src;
+
+ jump_insn = BB_END (loop_end);
+
+ if (dump_file)
+ {
+ fprintf (dump_file, "Doloop: Inserting doloop pattern (");
+ if (desc->const_iter)
+ fprintf (dump_file, HOST_WIDEST_INT_PRINT_DEC, desc->niter);
+ else
+ fputs ("runtime", dump_file);
+ fputs (" iterations).\n", dump_file);
+ }
+
+ /* Discard original jump to continue loop. The original compare
+ result may still be live, so it cannot be discarded explicitly. */
+ delete_insn (jump_insn);
+
+ counter_reg = XEXP (condition, 0);
+ if (GET_CODE (counter_reg) == PLUS)
+ counter_reg = XEXP (counter_reg, 0);
+
+ count = desc->niter_expr;
+ increment_count = false;
+ switch (GET_CODE (condition))
+ {
+ case NE:
+ /* Currently only NE tests against zero and one are supported. */
+ if (XEXP (condition, 1) == const1_rtx)
+ {
+ increment_count = true;
+ noloop = const1_rtx;
+ }
+ else if (XEXP (condition, 1) == const0_rtx)
+ noloop = const0_rtx;
+ else
+ abort ();
+ break;
+
+ case GE:
+ /* Currently only GE tests against zero are supported. */
+ if (XEXP (condition, 1) != const0_rtx)
+ abort ();
+
+ noloop = constm1_rtx;
+
+ /* The iteration count does not need incrementing for a GE test. */
+ increment_count = false;
+
+ /* Determine if the iteration counter will be non-negative.
+ Note that the maximum value loaded is iterations_max - 1. */
+ if (desc->niter_max
+ <= ((unsigned HOST_WIDEST_INT) 1
+ << (GET_MODE_BITSIZE (GET_MODE (counter_reg)) - 1)))
+ nonneg = 1;
+ break;
+
+ /* Abort if an invalid doloop pattern has been generated. */
+ default:
+ abort ();
+ }
+
+ if (increment_count)
+ count = simplify_gen_binary (PLUS, desc->mode, count, const1_rtx);
+
+ /* Insert initialization of the count register into the loop header. */
+ start_sequence ();
+ tmp = force_operand (count, counter_reg);
+ convert_move (counter_reg, tmp, 1);
+ sequence = get_insns ();
+ end_sequence ();
+ emit_insn_after (sequence, BB_END (loop_preheader_edge (loop)->src));
+
+ if (desc->noloop_assumptions)
+ {
+ rtx ass = desc->noloop_assumptions;
+ basic_block preheader = loop_preheader_edge (loop)->src;
+ basic_block set_zero
+ = loop_split_edge_with (loop_preheader_edge (loop), NULL_RTX);
+ basic_block new_preheader
+ = loop_split_edge_with (loop_preheader_edge (loop), NULL_RTX);
+ basic_block bb;
+ edge te;
+ gcov_type cnt;
+
+ /* Expand the condition testing the assumptions and if it does not pass,
+ reset the count register to 0. */
+ add_test (XEXP (ass, 0), preheader, set_zero);
+ preheader->succ->flags &= ~EDGE_FALLTHRU;
+ cnt = preheader->succ->count;
+ preheader->succ->probability = 0;
+ preheader->succ->count = 0;
+ irr = preheader->succ->flags & EDGE_IRREDUCIBLE_LOOP;
+ te = make_edge (preheader, new_preheader, EDGE_FALLTHRU | irr);
+ te->probability = REG_BR_PROB_BASE;
+ te->count = cnt;
+ set_immediate_dominator (CDI_DOMINATORS, new_preheader, preheader);
+
+ set_zero->count = 0;
+ set_zero->frequency = 0;
+
+ for (ass = XEXP (ass, 1); ass; ass = XEXP (ass, 1))
+ {
+ bb = loop_split_edge_with (te, NULL_RTX);
+ te = bb->succ;
+ add_test (XEXP (ass, 0), bb, set_zero);
+ make_edge (bb, set_zero, irr);
+ }
+
+ start_sequence ();
+ convert_move (counter_reg, noloop, 0);
+ sequence = get_insns ();
+ end_sequence ();
+ emit_insn_after (sequence, BB_END (set_zero));
+ }
+
+ /* Some targets (eg, C4x) need to initialize special looping
+ registers. */
+#ifdef HAVE_doloop_begin
+ {
+ rtx init;
+ unsigned level = get_loop_level (loop) + 1;
+ init = gen_doloop_begin (counter_reg,
+ desc->const_iter ? desc->niter_expr : const0_rtx,
+ desc->niter_max,
+ GEN_INT (level));
+ if (init)
+ {
+ start_sequence ();
+ emit_insn (init);
+ sequence = get_insns ();
+ end_sequence ();
+ emit_insn_after (sequence, BB_END (loop_preheader_edge (loop)->src));
+ }
+ }
+#endif
+
+ /* Insert the new low-overhead looping insn. */
+ emit_jump_insn_after (doloop_seq, BB_END (loop_end));
+ jump_insn = BB_END (loop_end);
+ jump_label = block_label (desc->in_edge->dest);
+ JUMP_LABEL (jump_insn) = jump_label;
+ LABEL_NUSES (jump_label)++;
+
+ /* Ensure the right fallthru edge is marked, for case we have reversed
+ the condition. */
+ desc->in_edge->flags &= ~EDGE_FALLTHRU;
+ desc->out_edge->flags |= EDGE_FALLTHRU;
+
+ /* Add a REG_NONNEG note if the actual or estimated maximum number
+ of iterations is non-negative. */
+ if (nonneg)
+ {
+ REG_NOTES (jump_insn)
+ = gen_rtx_EXPR_LIST (REG_NONNEG, NULL_RTX, REG_NOTES (jump_insn));
+ }
+}
+
+/* Process loop described by LOOP validating that the loop is suitable for
+ conversion to use a low overhead looping instruction, replacing the jump
+ insn where suitable. Returns true if the loop was successfully
+ modified. */
+
+static bool
+doloop_optimize (struct loop *loop)
+{
+ enum machine_mode mode;
+ rtx doloop_seq, doloop_pat, doloop_reg;
+ rtx iterations;
+ rtx iterations_max;
+ rtx start_label;
+ rtx condition;
+ unsigned level, est_niter;
+ struct niter_desc *desc;
+
+ if (dump_file)
+ fprintf (dump_file, "Doloop: Processing loop %d.\n", loop->num);
+
+ iv_analysis_loop_init (loop);
+
+ /* Find the simple exit of a LOOP. */
+ desc = get_simple_loop_desc (loop);
+
+ /* Check that loop is a candidate for a low-overhead looping insn. */
+ if (!doloop_valid_p (loop, desc))
+ {
+ if (dump_file)
+ fprintf (dump_file,
+ "Doloop: The loop is not suitable.\n");
+ return false;
+ }
+ mode = desc->mode;
+
+ est_niter = 3;
+ if (desc->const_iter)
+ est_niter = desc->niter;
+ /* If the estimate on number of iterations is reliable (comes from profile
+ feedback), use it. Do not use it normally, since the expected number
+ of iterations of an unrolled loop is 2. */
+ if (loop->header->count)
+ est_niter = expected_loop_iterations (loop);
+
+ if (est_niter < 3)
+ {
+ if (dump_file)
+ fprintf (dump_file,
+ "Doloop: Too few iterations (%u) to be profitable.\n",
+ est_niter);
+ return false;
+ }
+
+ iterations = desc->const_iter ? desc->niter_expr : const0_rtx;
+ iterations_max = GEN_INT (desc->niter_max);
+ level = get_loop_level (loop) + 1;
+
+ /* Generate looping insn. If the pattern FAILs then give up trying
+ to modify the loop since there is some aspect the back-end does
+ not like. */
+ start_label = block_label (desc->in_edge->dest);
+ doloop_reg = gen_reg_rtx (mode);
+ doloop_seq = gen_doloop_end (doloop_reg, iterations, iterations_max,
+ GEN_INT (level), start_label);
+ if (! doloop_seq && mode != word_mode)
+ {
+ PUT_MODE (doloop_reg, word_mode);
+ doloop_seq = gen_doloop_end (doloop_reg, iterations, iterations_max,
+ GEN_INT (level), start_label);
+ }
+ if (! doloop_seq)
+ {
+ if (dump_file)
+ fprintf (dump_file,
+ "Doloop: Target unwilling to use doloop pattern!\n");
+ return false;
+ }
+
+ /* If multiple instructions were created, the last must be the
+ jump instruction. Also, a raw define_insn may yield a plain
+ pattern. */
+ doloop_pat = doloop_seq;
+ if (INSN_P (doloop_pat))
+ {
+ while (NEXT_INSN (doloop_pat) != NULL_RTX)
+ doloop_pat = NEXT_INSN (doloop_pat);
+ if (GET_CODE (doloop_pat) == JUMP_INSN)
+ doloop_pat = PATTERN (doloop_pat);
+ else
+ doloop_pat = NULL_RTX;
+ }
+
+ if (! doloop_pat
+ || ! (condition = doloop_condition_get (doloop_pat)))
+ {
+ if (dump_file)
+ fprintf (dump_file, "Doloop: Unrecognizable doloop pattern!\n");
+ return false;
+ }
+
+ doloop_modify (loop, desc, doloop_seq, condition);
+ return true;
+}
+
+/* This is the main entry point. Process all LOOPS using doloop_optimize. */
+
+void
+doloop_optimize_loops (struct loops *loops)
+{
+ unsigned i;
+ struct loop *loop;
+
+ for (i = 1; i < loops->num; i++)
+ {
+ loop = loops->parray[i];
+ if (!loop)
+ continue;
+
+ doloop_optimize (loop);
+ }
+
+ iv_analysis_done ();
+
+#ifdef ENABLE_CHECKING
+ verify_dominators (CDI_DOMINATORS);
+ verify_loop_structure (loops);
+#endif
+}
+#endif /* HAVE_doloop_end */
+
diff --git a/gcc/loop-iv.c b/gcc/loop-iv.c
index 97cfdf7c07e..face41d3f32 100644
--- a/gcc/loop-iv.c
+++ b/gcc/loop-iv.c
@@ -2281,6 +2281,10 @@ iv_number_of_iterations (struct loop *loop, rtx insn, rtx condition,
simplify_using_initial_values (loop, IOR, &desc->infinite);
simplify_using_initial_values (loop, NIL, &desc->niter_expr);
+ if (desc->noloop_assumptions
+ && XEXP (desc->noloop_assumptions, 0) == const_true_rtx)
+ goto zero_iter;
+
if (GET_CODE (desc->niter_expr) == CONST_INT)
{
unsigned HOST_WIDEST_INT val = INTVAL (desc->niter_expr);
diff --git a/gcc/loop.c b/gcc/loop.c
index 5d458cbabc8..1b488fe5dbc 100644
--- a/gcc/loop.c
+++ b/gcc/loop.c
@@ -5352,23 +5352,6 @@ strength_reduce (struct loop *loop, int flags)
&& unrolled_insn_copies <= insn_count))
unroll_loop (loop, insn_count, 1);
-#ifdef HAVE_doloop_end
- if (HAVE_doloop_end && (flags & LOOP_BCT) && flag_branch_on_count_reg)
- doloop_optimize (loop);
-#endif /* HAVE_doloop_end */
-
- /* In case number of iterations is known, drop branch prediction note
- in the branch. Do that only in second loop pass, as loop unrolling
- may change the number of iterations performed. */
- if (flags & LOOP_BCT)
- {
- unsigned HOST_WIDE_INT n
- = loop_info->n_iterations / loop_info->unroll_number;
- if (n > 1)
- predict_insn (prev_nonnote_insn (loop->end), PRED_LOOP_ITERATIONS,
- REG_BR_PROB_BASE - REG_BR_PROB_BASE / n);
- }
-
if (loop_dump_stream)
fprintf (loop_dump_stream, "\n");
diff --git a/gcc/loop.h b/gcc/loop.h
index 2a7f3ec816e..bd88bb8c90e 100644
--- a/gcc/loop.h
+++ b/gcc/loop.h
@@ -26,9 +26,8 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
/* Flags passed to loop_optimize. */
#define LOOP_UNROLL 1
-#define LOOP_BCT 2
-#define LOOP_PREFETCH 4
-#define LOOP_AUTO_UNROLL 8
+#define LOOP_PREFETCH 2
+#define LOOP_AUTO_UNROLL 4
/* Get the loop info pointer of a loop. */
#define LOOP_INFO(LOOP) ((struct loop_info *) (LOOP)->aux)
diff --git a/gcc/passes.c b/gcc/passes.c
index c730949bcf9..24a2d232080 100644
--- a/gcc/passes.c
+++ b/gcc/passes.c
@@ -1456,7 +1456,7 @@ rest_of_handle_loop_optimize (tree decl, rtx insns)
reg_scan (insns, max_reg_num (), 1);
}
cleanup_barriers ();
- loop_optimize (insns, dump_file, do_unroll | LOOP_BCT | do_prefetch);
+ loop_optimize (insns, dump_file, do_unroll | do_prefetch);
/* Loop can create trivially dead instructions. */
delete_trivially_dead_insns (insns, max_reg_num ());
@@ -1476,6 +1476,12 @@ rest_of_handle_loop2 (tree decl, rtx insns)
struct loops *loops;
basic_block bb;
+ if (!flag_unswitch_loops
+ && !flag_peel_loops
+ && !flag_unroll_loops
+ && !flag_branch_on_count_reg)
+ return;
+
timevar_push (TV_LOOP);
open_dump_file (DFI_loop2, decl);
if (dump_file)
@@ -1498,6 +1504,11 @@ rest_of_handle_loop2 (tree decl, rtx insns)
(flag_unroll_loops ? UAP_UNROLL : 0) |
(flag_unroll_all_loops ? UAP_UNROLL_ALL : 0));
+#ifdef HAVE_doloop_end
+ if (flag_branch_on_count_reg && HAVE_doloop_end)
+ doloop_optimize_loops (loops);
+#endif /* HAVE_doloop_end */
+
loop_optimizer_finalize (loops, dump_file);
}
@@ -1776,10 +1787,7 @@ rest_of_compilation (tree decl)
if (flag_tracer)
rest_of_handle_tracer (decl, insns);
- if (optimize > 0
- && (flag_unswitch_loops
- || flag_peel_loops
- || flag_unroll_loops))
+ if (optimize > 0)
rest_of_handle_loop2 (decl, insns);
if (flag_web)
OpenPOWER on IntegriCloud