diff mbox

Rework doloop interface

Message ID 8738nbdwh7.fsf@talisman.default
State New
Headers show

Commit Message

Richard Sandiford Nov. 5, 2013, 9:33 a.m. UTC
Following on from:

    http://gcc.gnu.org/ml/gcc-patches/2013-11/msg00092.html

it looks like I'll have to "fix" the doloop_begin/end interface after all.
The current code goes on to do some rtx arithmetic on invalid CONST_INTs.
(FWIW, the arithmetic seems unnecessary and I think we could simply drop it,
but the weirdness of the interface would remain.)

So: doloop_end has 6 parameters, of which 4 are really just information
about the loop.  These 4 parameters never end up in the instruction
stream on current targets and aren't IMO really rtxes.  But because
expanders can only take rtx arguments, we still need to wrap them in
some kind of rtx container.

This causes problems because once you start representing something as
an rtx, you need to start thinking about modes.  One of the parameters
is the maximum number of iterations, and it isn't obvious what its mode
should be; the mode of the loop counter is too small to hold an iteration
count of 1 << GET_MODE_PRECISION.  Another of the parameters is the loop
level, which has no obvious mode at all.  One is a boolean, which could
be represented as BImode, but then we enter STORE_FLAG_VALUE territory.

So this patch adds a new target hook, can_use_doloop_p, that takes
these parameters as normal C arguments.  The default returns true,
but there's also a canned alternative for targets that can only handle
innermost loops.

This should also be slightly more efficient, since we can avoid creating
the loop counter register and label if the loop "obviously" isn't suitable.
It also avoids creating garbage rtl for the 4 not-really-rtx parameters.

Tested by building C and C++ for:

	arc-elf
	arm-linux-gnueabi
	bfin-elf
	c6x-elf
	ia64-linux-gnu
	mep-elf
	powerpc-linux-gnu
	s390-linux-gnu
	sh-linux-gnu
	spu-elf
	tilegx-elf
	tilepro-elf
	v850-elf

and comparing the -O2 assembly output of gcc.c-torture, gcc.dg and g++.dg
from before and after the patch (as far as possible without target headers).
For this I moved the can_use_doloop_p test to just before the gen_doloop_end
so that register and label numbers stayed the same.  There were two
differences:

- gcc.c-torture/compile/pr44030.c for arc-elf, where we now use the doloop
  instruction and didn't previously.  This is because arc-elf checked:

    /* Setting up the loop with two sr isntructions costs 6 cycles.  */
    if (TARGET_ARC700 && !INTVAL (operands[5])
        && INTVAL (operands[1]) && INTVAL (operands[1]) <= (flag_pic ? 6 : 3))
      FAIL;

  where operands[1] is the constant number of iterations.  Unlike the
  maximum number of iterations (operands[2]), this value has the same
  mode as the counter register and is properly sign-extended.  So a large
  positive iteration count appears negative and unintentionally triggered
  the FAIL.  So I think this counts as a bug fix.

- gcc.dg/graphite/id-9.c for bfin-elf.  In this testcase the maximum number
  of iterations is calculated as the double_int { high = 0, low = -1 },
  which doesn't fit in a signed HWI, so the maximum number of iterations
  was previously treated as 0.  And the bfin code doesn't handle the
  0/unknown case, which might be a bug:

    /* Due to limitations in the hardware (an initial loop count of 0
       does not loop 2^32 times) we must avoid to generate a hardware
       loops when we cannot rule out this case.  */
    if (!flag_unsafe_loop_optimizations
        && (unsigned HOST_WIDE_INT) INTVAL (operands[2]) >= 0xFFFFFFFF)
      FAIL;

  So the old code allowed the doloop to be used here, which I don't
  think was intentional.  Now the bfin code sees the original double_int
  and rejects it as too big.

  That said, it might also be a bug that we have { 0, -1 } rather than
  { 0, 0xffffffff } or { 0, 0x100000000 } (or even { -1, -1 }) for an
  SImode loop, but this has got to stop somewhere...

Also bootstrapped & regression-tested on powerpc64-linux-gnu.  OK to install?

Thanks,
Richard


gcc/
	* target.def (can_use_doloop_p): New hook.
	* doc/tm.texi.in (TARGET_CAN_USE_DOLOOP_P): Add.
	* doc/tm.texi: Regenerate.
	* doc/md.texi (doloop_begin, doloop_end): Update documentation.
	* hooks.h (hook_bool_dint_dint_uint_true): Declare.
	* hooks.c (hook_bool_dint_dint_uint_true): New function.
	* targhooks.h (can_use_doloop_if_innermost): Declare.
	* targhooks.c (can_use_doloop_if_innermost): New function.
	* target.h: Include double-int.h.
	* loop-doloop.c (doloop_optimize): Call targetm.can_use_doloop_p.
	Remove iteration count, maximum iteration count, loop depth and
	enter-at-top inputs from doloop_begin and doloop_end.
	* config/arc/arc.md (doloop_begin, doloop_end): Update for new
	interface.
	* config/arc/arc.c (arc_can_use_doloop_p): New function.
	(TARGET_CAN_USE_DOLOOP_P): Define.
	* config/arm/thumb2.md (doloop_end): Update for new interface.
	* config/arm/arm.c (TARGET_CAN_USE_DOLOOP_P): Define.
	* config/bfin/bfin.md (doloop_end): Update for new interface.
	* config/bfin/bfin.c (bfin_can_use_doloop_p): New function.
	(TARGET_CAN_USE_DOLOOP_P): Define.
	* config/c6x/c6x.md (doloop_end): Update for new interface.
	* config/ia64/ia64.md (doloop_end): Update for new interface.
	* config/ia64/ia64.c (TARGET_CAN_USE_DOLOOP_P): Define.
	* config/mep/mep.md (doloop_begin, doloop_end): Update for new
	interface.
	* config/mep/mep.c (mep_emit_doloop): Likewise.
	(TARGET_CAN_USE_DOLOOP_P): Define.
	* config/rs6000/rs6000.md (doloop_end): Update for new interface.
	* config/rs6000/rs6000.c (TARGET_CAN_USE_DOLOOP_P): Define.
	* config/s390/s390.md (doloop_end): Update for new interface.
	* config/sh/sh.md (doloop_end): Likewise.
	* config/spu/spu.md (doloop_end): Likewise.
	* config/spu/spu.c (TARGET_CAN_USE_DOLOOP_P): Define.
	* config/tilegx/tilegx.md (doloop_end): Update for new interface.
	* config/tilegx/tilegx.c (TARGET_CAN_USE_DOLOOP_P): Define.
	* config/tilepro/tilepro.md (doloop_end): Update for new interface.
	* config/tilepro/tilepro.c (TARGET_CAN_USE_DOLOOP_P): Define.
	* config/v850/v850.md (doloop_begin, doloop_end): Update for new
	interface.
	* config/v850/v850.c (TARGET_CAN_USE_DOLOOP_P): Define.

Comments

Richard Biener Nov. 5, 2013, noon UTC | #1
On Tue, Nov 5, 2013 at 10:33 AM, Richard Sandiford
<rdsandiford@googlemail.com> wrote:
> Following on from:
>
>     http://gcc.gnu.org/ml/gcc-patches/2013-11/msg00092.html
>
> it looks like I'll have to "fix" the doloop_begin/end interface after all.
> The current code goes on to do some rtx arithmetic on invalid CONST_INTs.
> (FWIW, the arithmetic seems unnecessary and I think we could simply drop it,
> but the weirdness of the interface would remain.)
>
> So: doloop_end has 6 parameters, of which 4 are really just information
> about the loop.  These 4 parameters never end up in the instruction
> stream on current targets and aren't IMO really rtxes.  But because
> expanders can only take rtx arguments, we still need to wrap them in
> some kind of rtx container.
>
> This causes problems because once you start representing something as
> an rtx, you need to start thinking about modes.  One of the parameters
> is the maximum number of iterations, and it isn't obvious what its mode
> should be; the mode of the loop counter is too small to hold an iteration
> count of 1 << GET_MODE_PRECISION.  Another of the parameters is the loop
> level, which has no obvious mode at all.  One is a boolean, which could
> be represented as BImode, but then we enter STORE_FLAG_VALUE territory.
>
> So this patch adds a new target hook, can_use_doloop_p, that takes
> these parameters as normal C arguments.  The default returns true,
> but there's also a canned alternative for targets that can only handle
> innermost loops.
>
> This should also be slightly more efficient, since we can avoid creating
> the loop counter register and label if the loop "obviously" isn't suitable.
> It also avoids creating garbage rtl for the 4 not-really-rtx parameters.
>
> Tested by building C and C++ for:
>
>         arc-elf
>         arm-linux-gnueabi
>         bfin-elf
>         c6x-elf
>         ia64-linux-gnu
>         mep-elf
>         powerpc-linux-gnu
>         s390-linux-gnu
>         sh-linux-gnu
>         spu-elf
>         tilegx-elf
>         tilepro-elf
>         v850-elf
>
> and comparing the -O2 assembly output of gcc.c-torture, gcc.dg and g++.dg
> from before and after the patch (as far as possible without target headers).
> For this I moved the can_use_doloop_p test to just before the gen_doloop_end
> so that register and label numbers stayed the same.  There were two
> differences:
>
> - gcc.c-torture/compile/pr44030.c for arc-elf, where we now use the doloop
>   instruction and didn't previously.  This is because arc-elf checked:
>
>     /* Setting up the loop with two sr isntructions costs 6 cycles.  */
>     if (TARGET_ARC700 && !INTVAL (operands[5])
>         && INTVAL (operands[1]) && INTVAL (operands[1]) <= (flag_pic ? 6 : 3))
>       FAIL;
>
>   where operands[1] is the constant number of iterations.  Unlike the
>   maximum number of iterations (operands[2]), this value has the same
>   mode as the counter register and is properly sign-extended.  So a large
>   positive iteration count appears negative and unintentionally triggered
>   the FAIL.  So I think this counts as a bug fix.
>
> - gcc.dg/graphite/id-9.c for bfin-elf.  In this testcase the maximum number
>   of iterations is calculated as the double_int { high = 0, low = -1 },
>   which doesn't fit in a signed HWI, so the maximum number of iterations
>   was previously treated as 0.  And the bfin code doesn't handle the
>   0/unknown case, which might be a bug:
>
>     /* Due to limitations in the hardware (an initial loop count of 0
>        does not loop 2^32 times) we must avoid to generate a hardware
>        loops when we cannot rule out this case.  */
>     if (!flag_unsafe_loop_optimizations
>         && (unsigned HOST_WIDE_INT) INTVAL (operands[2]) >= 0xFFFFFFFF)
>       FAIL;
>
>   So the old code allowed the doloop to be used here, which I don't
>   think was intentional.  Now the bfin code sees the original double_int
>   and rejects it as too big.
>
>   That said, it might also be a bug that we have { 0, -1 } rather than
>   { 0, 0xffffffff } or { 0, 0x100000000 } (or even { -1, -1 }) for an
>   SImode loop, but this has got to stop somewhere...
>
> Also bootstrapped & regression-tested on powerpc64-linux-gnu.  OK to install?

Ok.  Please leave target maintainers a second to comment.

Thanks,
Richard.

> Thanks,
> Richard
>
>
> gcc/
>         * target.def (can_use_doloop_p): New hook.
>         * doc/tm.texi.in (TARGET_CAN_USE_DOLOOP_P): Add.
>         * doc/tm.texi: Regenerate.
>         * doc/md.texi (doloop_begin, doloop_end): Update documentation.
>         * hooks.h (hook_bool_dint_dint_uint_true): Declare.
>         * hooks.c (hook_bool_dint_dint_uint_true): New function.
>         * targhooks.h (can_use_doloop_if_innermost): Declare.
>         * targhooks.c (can_use_doloop_if_innermost): New function.
>         * target.h: Include double-int.h.
>         * loop-doloop.c (doloop_optimize): Call targetm.can_use_doloop_p.
>         Remove iteration count, maximum iteration count, loop depth and
>         enter-at-top inputs from doloop_begin and doloop_end.
>         * config/arc/arc.md (doloop_begin, doloop_end): Update for new
>         interface.
>         * config/arc/arc.c (arc_can_use_doloop_p): New function.
>         (TARGET_CAN_USE_DOLOOP_P): Define.
>         * config/arm/thumb2.md (doloop_end): Update for new interface.
>         * config/arm/arm.c (TARGET_CAN_USE_DOLOOP_P): Define.
>         * config/bfin/bfin.md (doloop_end): Update for new interface.
>         * config/bfin/bfin.c (bfin_can_use_doloop_p): New function.
>         (TARGET_CAN_USE_DOLOOP_P): Define.
>         * config/c6x/c6x.md (doloop_end): Update for new interface.
>         * config/ia64/ia64.md (doloop_end): Update for new interface.
>         * config/ia64/ia64.c (TARGET_CAN_USE_DOLOOP_P): Define.
>         * config/mep/mep.md (doloop_begin, doloop_end): Update for new
>         interface.
>         * config/mep/mep.c (mep_emit_doloop): Likewise.
>         (TARGET_CAN_USE_DOLOOP_P): Define.
>         * config/rs6000/rs6000.md (doloop_end): Update for new interface.
>         * config/rs6000/rs6000.c (TARGET_CAN_USE_DOLOOP_P): Define.
>         * config/s390/s390.md (doloop_end): Update for new interface.
>         * config/sh/sh.md (doloop_end): Likewise.
>         * config/spu/spu.md (doloop_end): Likewise.
>         * config/spu/spu.c (TARGET_CAN_USE_DOLOOP_P): Define.
>         * config/tilegx/tilegx.md (doloop_end): Update for new interface.
>         * config/tilegx/tilegx.c (TARGET_CAN_USE_DOLOOP_P): Define.
>         * config/tilepro/tilepro.md (doloop_end): Update for new interface.
>         * config/tilepro/tilepro.c (TARGET_CAN_USE_DOLOOP_P): Define.
>         * config/v850/v850.md (doloop_begin, doloop_end): Update for new
>         interface.
>         * config/v850/v850.c (TARGET_CAN_USE_DOLOOP_P): Define.
>
> Index: gcc/target.def
> ===================================================================
> --- gcc/target.def      2013-11-05 08:55:57.423644646 +0000
> +++ gcc/target.def      2013-11-05 08:56:11.617792832 +0000
> @@ -3572,6 +3572,23 @@ normally defined in @file{libgcc2.c}.",
>   tree, (void),
>   default_external_stack_protect_fail)
>
> +DEFHOOK
> +(can_use_doloop_p,
> + "Return true if it is possible to use low-overhead loops (@code{doloop_end}\n\
> +and @code{doloop_begin}) for a particular loop.  @var{iterations} gives the\n\
> +exact number of iterations, or 0 if not known.  @var{iterations_max} gives\n\
> +the maximum number of iterations, or 0 if not known.  @var{loop_depth} is\n\
> +the nesting depth of the loop, with 1 for innermost loops, 2 for loops that\n\
> +contain innermost loops, and so on.  @var{entered_at_top} is true if the\n\
> +loop is only entered from the top.\n\
> +\n\
> +This hook is only used if @code{doloop_end} is available.  The default\n\
> +implementation returns true.  You can use @code{can_use_doloop_if_innermost}\n\
> +if the loop must be the innermost, and if there are no other restrictions.",
> + bool, (double_int iterations, double_int iterations_max,
> +       unsigned int loop_depth, bool entered_at_top),
> + hook_bool_dint_dint_uint_bool_true)
> +
>  /* Returns NULL if target supports the insn within a doloop block,
>     otherwise it returns an error message.  */
>  DEFHOOK
> Index: gcc/doc/tm.texi.in
> ===================================================================
> --- gcc/doc/tm.texi.in  2013-11-05 08:55:57.423644646 +0000
> +++ gcc/doc/tm.texi.in  2013-11-05 08:56:11.616792820 +0000
> @@ -8206,6 +8206,8 @@ to by @var{ce_info}.
>
>  @hook TARGET_GENERATE_VERSION_DISPATCHER_BODY
>
> +@hook TARGET_CAN_USE_DOLOOP_P
> +
>  @hook TARGET_INVALID_WITHIN_DOLOOP
>
>  @hook TARGET_LEGITIMATE_COMBINED_INSN
> Index: gcc/doc/tm.texi
> ===================================================================
> --- gcc/doc/tm.texi     2013-11-05 08:55:57.423644646 +0000
> +++ gcc/doc/tm.texi     2013-11-05 08:56:11.614792799 +0000
> @@ -11076,6 +11076,20 @@ function version at run-time for a given
>  body must be generated.
>  @end deftypefn
>
> +@deftypefn {Target Hook} bool TARGET_CAN_USE_DOLOOP_P (double_int @var{iterations}, double_int @var{iterations_max}, unsigned int @var{loop_depth}, bool @var{entered_at_top})
> +Return true if it is possible to use low-overhead loops (@code{doloop_end}
> +and @code{doloop_begin}) for a particular loop.  @var{iterations} gives the
> +exact number of iterations, or 0 if not known.  @var{iterations_max} gives
> +the maximum number of iterations, or 0 if not known.  @var{loop_depth} is
> +the nesting depth of the loop, with 1 for innermost loops, 2 for loops that
> +contain innermost loops, and so on.  @var{entered_at_top} is true if the
> +loop is only entered from the top.
> +
> +This hook is only used if @code{doloop_end} is available.  The default
> +implementation returns true.  You can use @code{can_use_doloop_if_innermost}
> +if the loop must be the innermost, and if there are no other restrictions.
> +@end deftypefn
> +
>  @deftypefn {Target Hook} {const char *} TARGET_INVALID_WITHIN_DOLOOP (const_rtx @var{insn})
>
>  Take an instruction in @var{insn} and return NULL if it is valid within a
> Index: gcc/doc/md.texi
> ===================================================================
> --- gcc/doc/md.texi     2013-11-05 08:55:57.423644646 +0000
> +++ gcc/doc/md.texi     2013-11-05 08:56:11.612792780 +0000
> @@ -5856,34 +5856,27 @@ reduction is enabled.
>
>  @cindex @code{doloop_end} instruction pattern
>  @item @samp{doloop_end}
> -Conditional branch instruction that decrements a register and jumps if
> -the register is nonzero.  This instruction takes five operands: Operand
> -0 is the register to decrement and test; operand 1 is the number of loop
> -iterations as a @code{const_int} or @code{const0_rtx} if this cannot be
> -determined until run-time; operand 2 is the actual or estimated maximum
> -number of iterations as a @code{const_int}; operand 3 is the number of
> -enclosed loops as a @code{const_int} (an innermost loop has a value of
> -1); operand 4 is the label to jump to if the register is nonzero;
> -operand 5 is const1_rtx if the loop in entered at its top, const0_rtx
> -otherwise.
> +Conditional branch instruction that decrements a register and
> +jumps if the register is nonzero.  Operand 0 is the register to
> +decrement and test; operand 1 is the label to jump to if the
> +register is nonzero.
>  @xref{Looping Patterns}.
>
>  This optional instruction pattern should be defined for machines with
>  low-overhead looping instructions as the loop optimizer will try to
> -modify suitable loops to utilize it.  If nested low-overhead looping is
> -not supported, use a @code{define_expand} (@pxref{Expander Definitions})
> -and make the pattern fail if operand 3 is not @code{const1_rtx}.
> -Similarly, if the actual or estimated maximum number of iterations is
> -too large for this instruction, make it fail.
> +modify suitable loops to utilize it.  The target hook
> +@code{TARGET_CAN_USE_DOLOOP_P} controls the conditions under which
> +low-overhead loops can be used.
>
>  @cindex @code{doloop_begin} instruction pattern
>  @item @samp{doloop_begin}
>  Companion instruction to @code{doloop_end} required for machines that
> -need to perform some initialization, such as loading special registers
> -used by a low-overhead looping instruction.  If initialization insns do
> -not always need to be emitted, use a @code{define_expand}
> -(@pxref{Expander Definitions}) and make it fail.
> +need to perform some initialization, such as loading a special counter
> +register.  Operand 1 is the associated @code{doloop_end} pattern and
> +operand 0 is the register that it decrements.
>
> +If initialization insns do not always need to be emitted, use a
> +@code{define_expand} (@pxref{Expander Definitions}) and make it fail.
>
>  @cindex @code{canonicalize_funcptr_for_compare} instruction pattern
>  @item @samp{canonicalize_funcptr_for_compare}
> Index: gcc/hooks.h
> ===================================================================
> --- gcc/hooks.h 2013-11-05 08:55:57.423644646 +0000
> +++ gcc/hooks.h 2013-11-05 08:56:11.616792820 +0000
> @@ -23,6 +23,7 @@
>  #define GCC_HOOKS_H
>
>  #include "machmode.h"
> +#include "double-int.h"
>
>  extern bool hook_bool_void_false (void);
>  extern bool hook_bool_void_true (void);
> @@ -60,6 +61,8 @@ extern bool hook_bool_rtx_int_int_int_in
>  extern bool hook_bool_tree_tree_false (tree, tree);
>  extern bool hook_bool_tree_tree_true (tree, tree);
>  extern bool hook_bool_tree_bool_false (tree, bool);
> +extern bool hook_bool_dint_dint_uint_bool_true (double_int, double_int,
> +                                               unsigned int, bool);
>
>  extern void hook_void_void (void);
>  extern void hook_void_constcharptr (const char *);
> Index: gcc/hooks.c
> ===================================================================
> --- gcc/hooks.c 2013-11-05 08:55:57.423644646 +0000
> +++ gcc/hooks.c 2013-11-05 08:56:11.616792820 +0000
> @@ -331,6 +331,12 @@ hook_bool_rtx_int_int_int_intp_bool_fals
>    return false;
>  }
>
> +bool
> +hook_bool_dint_dint_uint_bool_true (double_int, double_int, unsigned int, bool)
> +{
> +  return true;
> +}
> +
>  /* Generic hook that takes an rtx and returns it.  */
>  rtx
>  hook_rtx_rtx_identity (rtx x)
> Index: gcc/targhooks.h
> ===================================================================
> --- gcc/targhooks.h     2013-11-05 08:55:57.423644646 +0000
> +++ gcc/targhooks.h     2013-11-05 08:56:11.618792842 +0000
> @@ -211,3 +211,5 @@ extern tree default_fn_abi_va_list_bound
>  extern tree default_chkp_bound_type (void);
>  extern enum machine_mode default_chkp_bound_mode (void);
>  extern tree default_builtin_chkp_function (unsigned int);
> +extern bool can_use_doloop_if_innermost (double_int, double_int,
> +                                        unsigned int, bool);
> Index: gcc/targhooks.c
> ===================================================================
> --- gcc/targhooks.c     2013-11-05 08:55:57.423644646 +0000
> +++ gcc/targhooks.c     2013-11-05 08:56:11.618792842 +0000
> @@ -1718,5 +1718,14 @@ default_builtin_chkp_function (unsigned
>    return NULL_TREE;
>  }
>
> +/* An implementation of TARGET_CAN_USE_DOLOOP_P for targets that do
> +   not support nested low-overhead loops.  */
> +
> +bool
> +can_use_doloop_if_innermost (double_int, double_int,
> +                            unsigned int loop_depth, bool)
> +{
> +  return loop_depth == 1;
> +}
>
>  #include "gt-targhooks.h"
> Index: gcc/target.h
> ===================================================================
> --- gcc/target.h        2013-11-05 08:55:57.423644646 +0000
> +++ gcc/target.h        2013-11-05 08:56:11.618792842 +0000
> @@ -50,6 +50,7 @@ #define GCC_TARGET_H
>
>  #include "insn-modes.h"
>  #include "insn-codes.h"
> +#include "double-int.h"
>
>  #ifdef ENABLE_CHECKING
>
> Index: gcc/loop-doloop.c
> ===================================================================
> --- gcc/loop-doloop.c   2013-11-05 08:55:57.422644636 +0000
> +++ gcc/loop-doloop.c   2013-11-05 08:56:11.616792820 +0000
> @@ -548,20 +548,8 @@ doloop_modify (struct loop *loop, struct
>  #ifdef HAVE_doloop_begin
>    {
>      rtx init;
> -    unsigned level = get_loop_level (loop) + 1;
> -    double_int iter;
> -    rtx iter_rtx;
> -
> -    if (!get_max_loop_iterations (loop, &iter)
> -       || !iter.fits_shwi ())
> -      iter_rtx = const0_rtx;
> -    else
> -      iter_rtx = GEN_INT (iter.to_shwi ());
> -    init = gen_doloop_begin (counter_reg,
> -                            desc->const_iter ? desc->niter_expr : const0_rtx,
> -                            iter_rtx,
> -                            GEN_INT (level),
> -                            doloop_seq);
> +
> +    init = gen_doloop_begin (counter_reg, doloop_seq);
>      if (init)
>        {
>         start_sequence ();
> @@ -608,8 +596,8 @@ doloop_optimize (struct loop *loop)
>  {
>    enum machine_mode mode;
>    rtx doloop_seq, doloop_pat, doloop_reg;
> -  rtx iterations, count;
> -  rtx iterations_max;
> +  rtx count;
> +  double_int iterations, iterations_max;
>    rtx start_label;
>    rtx condition;
>    unsigned level, est_niter;
> @@ -617,7 +605,6 @@ doloop_optimize (struct loop *loop)
>    struct niter_desc *desc;
>    unsigned word_mode_size;
>    unsigned HOST_WIDE_INT word_mode_max;
> -  double_int iter;
>    int entered_at_top;
>
>    if (dump_file)
> @@ -667,25 +654,30 @@ doloop_optimize (struct loop *loop)
>        return false;
>      }
>
> -  count = copy_rtx (desc->niter_expr);
> -  iterations = desc->const_iter ? desc->niter_expr : const0_rtx;
> -  if (!get_max_loop_iterations (loop, &iter)
> -      || !iter.fits_shwi ())
> -    iterations_max = const0_rtx;
> +  if (desc->const_iter)
> +    iterations = rtx_to_double_int (desc->niter_expr);
>    else
> -    iterations_max = GEN_INT (iter.to_shwi ());
> +    iterations = double_int_zero;
> +  if (!get_max_loop_iterations (loop, &iterations_max))
> +    iterations_max = double_int_zero;
>    level = get_loop_level (loop) + 1;
> +  entered_at_top = (loop->latch == desc->in_edge->dest
> +                   && contains_no_active_insn_p (loop->latch));
> +  if (!targetm.can_use_doloop_p (iterations, iterations_max, level,
> +                                entered_at_top))
> +    {
> +      if (dump_file)
> +       fprintf (dump_file, "Loop rejected by can_use_doloop_p.\n");
> +      return false;
> +    }
>
>    /* 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.  */
> +  count = copy_rtx (desc->niter_expr);
>    start_label = block_label (desc->in_edge->dest);
>    doloop_reg = gen_reg_rtx (mode);
> -  entered_at_top = (loop->latch == desc->in_edge->dest
> -                   && contains_no_active_insn_p (loop->latch));
> -  doloop_seq = gen_doloop_end (doloop_reg, iterations, iterations_max,
> -                              GEN_INT (level), start_label,
> -                              GEN_INT (entered_at_top));
> +  doloop_seq = gen_doloop_end (doloop_reg, start_label);
>
>    word_mode_size = GET_MODE_PRECISION (word_mode);
>    word_mode_max
> @@ -696,27 +688,14 @@ doloop_optimize (struct loop *loop)
>          computed, we must be sure that the number of iterations fits into
>          the new mode.  */
>        && (word_mode_size >= GET_MODE_PRECISION (mode)
> -         || iter.ule (double_int::from_shwi (word_mode_max))))
> +         || iterations_max.ule (double_int::from_shwi (word_mode_max))))
>      {
>        if (word_mode_size > GET_MODE_PRECISION (mode))
> -       {
> -         count = simplify_gen_unary (ZERO_EXTEND, word_mode,
> -                                     count, mode);
> -         iterations = simplify_gen_unary (ZERO_EXTEND, word_mode,
> -                                          iterations, mode);
> -         iterations_max = simplify_gen_unary (ZERO_EXTEND, word_mode,
> -                                              iterations_max, mode);
> -       }
> +       count = simplify_gen_unary (ZERO_EXTEND, word_mode, count, mode);
>        else
> -       {
> -         count = lowpart_subreg (word_mode, count, mode);
> -         iterations = lowpart_subreg (word_mode, iterations, mode);
> -         iterations_max = lowpart_subreg (word_mode, iterations_max, mode);
> -       }
> +       count = lowpart_subreg (word_mode, count, mode);
>        PUT_MODE (doloop_reg, word_mode);
> -      doloop_seq = gen_doloop_end (doloop_reg, iterations, iterations_max,
> -                                  GEN_INT (level), start_label,
> -                                  GEN_INT (entered_at_top));
> +      doloop_seq = gen_doloop_end (doloop_reg, start_label);
>      }
>    if (! doloop_seq)
>      {
> Index: gcc/config/arc/arc.md
> ===================================================================
> --- gcc/config/arc/arc.md       2013-11-05 08:55:57.423644646 +0000
> +++ gcc/config/arc/arc.md       2013-11-05 08:56:11.069787126 +0000
> @@ -4706,16 +4706,10 @@ (define_insn_and_split "*bbit_di"
>  })
>
>  ; operand 0 is the loop count pseudo register
> -; operand 1 is the number of loop iterations or 0 if it is unknown
> -; operand 2 is the maximum number of loop iterations
> -; operand 3 is the number of levels of enclosed loops
> -; operand 4 is the loop end pattern
> +; operand 1 is the loop end pattern
>  (define_expand "doloop_begin"
>    [(use (match_operand 0 "register_operand" ""))
> -   (use (match_operand:QI 1 "const_int_operand" ""))
> -   (use (match_operand:QI 2 "const_int_operand" ""))
> -   (use (match_operand:QI 3 "const_int_operand" ""))
> -   (use (match_operand 4 "" ""))]
> +   (use (match_operand 1 "" ""))]
>    ""
>  {
>    /* Using the INSN_UID of the loop end pattern to identify it causes
> @@ -4725,10 +4719,8 @@ (define_expand "doloop_begin"
>       still be able to tell what kind of number this is.  */
>    static HOST_WIDE_INT loop_end_id = 0;
>
> -  if (INTVAL (operands[3]) > 1)
> -    FAIL;
>    rtx id = GEN_INT (--loop_end_id);
> -  XEXP (XVECEXP (PATTERN (operands[4]), 0, 4), 0) = id;
> +  XEXP (XVECEXP (PATTERN (operands[1]), 0, 4), 0) = id;
>    emit_insn (gen_doloop_begin_i (operands[0], const0_rtx, id,
>                                  const0_rtx, const0_rtx));
>    DONE;
> @@ -4907,11 +4899,7 @@ (define_insn "doloop_begin_i"
>  )
>
>  ; operand 0 is the loop count pseudo register
> -; operand 1 is the number of loop iterations or 0 if it is unknown
> -; operand 2 is the maximum number of loop iterations
> -; operand 3 is the number of levels of enclosed loops
> -; operand 4 is the label to jump to at the top of the loop
> -; operand 5 is nonzero if the loop is entered at its top.
> +; operand 1 is the label to jump to at the top of the loop
>  ; Use this for the ARC600 and ARC700.  For ARCtangent-A5, this is unsafe
>  ; without further checking for nearby branches etc., and without proper
>  ; annotation of shift patterns that clobber lp_count
> @@ -4919,24 +4907,14 @@ (define_insn "doloop_begin_i"
>  ; single insn - loop setup is expensive then.
>  (define_expand "doloop_end"
>    [(use (match_operand 0 "register_operand" ""))
> -   (use (match_operand:QI 1 "const_int_operand" ""))
> -   (use (match_operand:QI 2 "const_int_operand" ""))
> -   (use (match_operand:QI 3 "const_int_operand" ""))
> -   (use (label_ref (match_operand 4 "" "")))
> -   (use (match_operand:QI 5 "const_int_operand" ""))]
> +   (use (label_ref (match_operand 1 "" "")))]
>    "TARGET_ARC600 || TARGET_ARC700"
>  {
> -  if (INTVAL (operands[3]) > 1)
> -    FAIL;
> -  /* Setting up the loop with two sr isntructions costs 6 cycles.  */
> -  if (TARGET_ARC700 && !INTVAL (operands[5])
> -      && INTVAL (operands[1]) && INTVAL (operands[1]) <= (flag_pic ? 6 : 3))
> -    FAIL;
>    /* We could do smaller bivs with biv widening, and wider bivs by having
>       a high-word counter in an outer loop - but punt on this for now.  */
>    if (GET_MODE (operands[0]) != SImode)
>      FAIL;
> -  emit_jump_insn (gen_doloop_end_i (operands[0], operands[4], const0_rtx));
> +  emit_jump_insn (gen_doloop_end_i (operands[0], operands[1], const0_rtx));
>    DONE;
>  })
>
> Index: gcc/config/arc/arc.c
> ===================================================================
> --- gcc/config/arc/arc.c        2013-11-05 08:55:57.423644646 +0000
> +++ gcc/config/arc/arc.c        2013-11-05 08:56:11.045786876 +0000
> @@ -388,6 +388,7 @@ static bool arc_return_in_memory (const_
>  static void arc_init_simd_builtins (void);
>  static bool arc_vector_mode_supported_p (enum machine_mode);
>
> +static bool arc_can_use_doloop_p (double_int, double_int, unsigned int, bool);
>  static const char *arc_invalid_within_doloop (const_rtx);
>
>  static void output_short_suffix (FILE *file);
> @@ -493,6 +494,9 @@ #define TARGET_SCHED_ADJUST_PRIORITY arc
>  #undef TARGET_VECTOR_MODE_SUPPORTED_P
>  #define TARGET_VECTOR_MODE_SUPPORTED_P arc_vector_mode_supported_p
>
> +#undef TARGET_CAN_USE_DOLOOP_P
> +#define TARGET_CAN_USE_DOLOOP_P arc_can_use_doloop_p
> +
>  #undef TARGET_INVALID_WITHIN_DOLOOP
>  #define TARGET_INVALID_WITHIN_DOLOOP arc_invalid_within_doloop
>
> @@ -5638,6 +5642,23 @@ arc_pass_by_reference (cumulative_args_t
>               || TREE_ADDRESSABLE (type)));
>  }
>
> +/* Implement TARGET_CAN_USE_DOLOOP_P.  */
> +
> +static bool
> +arc_can_use_doloop_p (double_int iterations, double_int,
> +                     unsigned int loop_depth, bool entered_at_top)
> +{
> +  if (loop_depth > 1)
> +    return false;
> +  /* Setting up the loop with two sr instructions costs 6 cycles.  */
> +  if (TARGET_ARC700
> +      && !entered_at_top
> +      && iterations.high == 0
> +      && iterations.low > 0
> +      && iterations.low <= (flag_pic ? 6 : 3))
> +    return false;
> +  return true;
> +}
>
>  /* NULL if INSN insn is valid within a low-overhead loop.
>     Otherwise return why doloop cannot be applied.  */
> Index: gcc/config/arm/thumb2.md
> ===================================================================
> --- gcc/config/arm/thumb2.md    2013-11-05 08:55:57.423644646 +0000
> +++ gcc/config/arm/thumb2.md    2013-11-05 08:56:11.212788615 +0000
> @@ -1449,11 +1449,7 @@ (define_peephole2
>  ;; knows what to generate.
>  (define_expand "doloop_end"
>    [(use (match_operand 0 "" ""))      ; loop pseudo
> -   (use (match_operand 1 "" ""))      ; iterations; zero if unknown
> -   (use (match_operand 2 "" ""))      ; max iterations
> -   (use (match_operand 3 "" ""))      ; loop level
> -   (use (match_operand 4 "" ""))      ; label
> -   (use (match_operand 5 "" ""))]     ; flag: 1 if loop entered at top, else 0
> +   (use (match_operand 1 "" ""))]     ; label
>    "TARGET_32BIT"
>    "
>   {
> @@ -1472,10 +1468,6 @@ (define_expand "doloop_end"
>       rtx insn;
>       rtx cmp;
>
> -     /* Only use this on innermost loops.  */
> -     if (INTVAL (operands[3]) > 1)
> -       FAIL;
> -
>       if (GET_MODE (operands[0]) != SImode)
>         FAIL;
>
> @@ -1488,7 +1480,7 @@ (define_expand "doloop_end"
>       cmp = XVECEXP (PATTERN (insn), 0, 0);
>       cc_reg = SET_DEST (cmp);
>       bcomp = gen_rtx_NE (VOIDmode, cc_reg, const0_rtx);
> -     loc_ref = gen_rtx_LABEL_REF (VOIDmode, operands [4]);
> +     loc_ref = gen_rtx_LABEL_REF (VOIDmode, operands [1]);
>       emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx,
>                                    gen_rtx_IF_THEN_ELSE (VOIDmode, bcomp,
>                                                          loc_ref, pc_rtx)));
> Index: gcc/config/arm/arm.c
> ===================================================================
> --- gcc/config/arm/arm.c        2013-11-05 08:55:57.423644646 +0000
> +++ gcc/config/arm/arm.c        2013-11-05 08:56:11.211788604 +0000
> @@ -669,6 +669,8 @@ #define TARGET_ASAN_SHADOW_OFFSET arm_as
>  #undef MAX_INSN_PER_IT_BLOCK
>  #define MAX_INSN_PER_IT_BLOCK (arm_restrict_it ? 1 : 4)
>
> +#undef TARGET_CAN_USE_DOLOOP_P
> +#define TARGET_CAN_USE_DOLOOP_P can_use_doloop_if_innermost
>
>  struct gcc_target targetm = TARGET_INITIALIZER;
>
> Index: gcc/config/bfin/bfin.md
> ===================================================================
> --- gcc/config/bfin/bfin.md     2013-11-05 08:55:57.423644646 +0000
> +++ gcc/config/bfin/bfin.md     2013-11-05 08:56:11.619792853 +0000
> @@ -1929,35 +1929,25 @@ (define_insn "*tablejump_internal"
>  ;;  Hardware loop
>
>  ; operand 0 is the loop count pseudo register
> -; operand 1 is the number of loop iterations or 0 if it is unknown
> -; operand 2 is the maximum number of loop iterations
> -; operand 3 is the number of levels of enclosed loops
> -; operand 4 is the label to jump to at the top of the loop
> -; operand 5 indicates if the loop is entered at the top
> +; operand 1 is the label to jump to at the top of the loop
>  (define_expand "doloop_end"
>    [(parallel [(set (pc) (if_then_else
>                           (ne (match_operand:SI 0 "" "")
>                               (const_int 1))
> -                         (label_ref (match_operand 4 "" ""))
> +                         (label_ref (match_operand 1 "" ""))
>                           (pc)))
>               (set (match_dup 0)
>                    (plus:SI (match_dup 0)
>                             (const_int -1)))
>               (unspec [(const_int 0)] UNSPEC_LSETUP_END)
> -             (clobber (match_operand 5 ""))])] ; match_scratch
> +             (clobber (match_dup 2))])] ; match_scratch
>    ""
>  {
>    /* The loop optimizer doesn't check the predicates... */
>    if (GET_MODE (operands[0]) != SImode)
>      FAIL;
> -  /* Due to limitations in the hardware (an initial loop count of 0
> -     does not loop 2^32 times) we must avoid to generate a hardware
> -     loops when we cannot rule out this case.  */
> -  if (!flag_unsafe_loop_optimizations
> -      && (unsigned HOST_WIDE_INT) INTVAL (operands[2]) >= 0xFFFFFFFF)
> -    FAIL;
>    bfin_hardware_loop ();
> -  operands[5] = gen_rtx_SCRATCH (SImode);
> +  operands[2] = gen_rtx_SCRATCH (SImode);
>  })
>
>  (define_insn "loop_end"
> Index: gcc/config/bfin/bfin.c
> ===================================================================
> --- gcc/config/bfin/bfin.c      2013-11-05 08:55:57.423644646 +0000
> +++ gcc/config/bfin/bfin.c      2013-11-05 08:56:11.367790231 +0000
> @@ -3366,6 +3366,22 @@ find_prev_insn_start (rtx insn)
>    return insn;
>  }
>
> +/* Implement TARGET_CAN_USE_DOLOOP_P.  */
> +
> +static bool
> +bfin_can_use_doloop_p (double_int, double_int iterations_max,
> +                      unsigned int, bool)
> +{
> +  /* Due to limitations in the hardware (an initial loop count of 0
> +     does not loop 2^32 times) we must avoid to generate a hardware
> +     loops when we cannot rule out this case.  */
> +  if (!flag_unsafe_loop_optimizations
> +      && (iterations_max.high != 0
> +         || iterations_max.low >= 0xFFFFFFFF))
> +    return false;
> +  return true;
> +}
> +
>  /* Increment the counter for the number of loop instructions in the
>     current function.  */
>
> @@ -5810,4 +5826,7 @@ #define TARGET_DELAY_SCHED2 true
>  #undef TARGET_DELAY_VARTRACK
>  #define TARGET_DELAY_VARTRACK true
>
> +#undef TARGET_CAN_USE_DOLOOP_P
> +#define TARGET_CAN_USE_DOLOOP_P bfin_can_use_doloop_p
> +
>  struct gcc_target targetm = TARGET_INITIALIZER;
> Index: gcc/config/c6x/c6x.md
> ===================================================================
> --- gcc/config/c6x/c6x.md       2013-11-05 08:55:57.423644646 +0000
> +++ gcc/config/c6x/c6x.md       2013-11-05 08:56:11.384790405 +0000
> @@ -1421,27 +1421,23 @@ (define_insn_and_split "eh_return"
>  ;; -------------------------------------------------------------------------
>
>  ; operand 0 is the loop count pseudo register
> -; operand 1 is the number of loop iterations or 0 if it is unknown
> -; operand 2 is the maximum number of loop iterations
> -; operand 3 is the number of levels of enclosed loops
> -; operand 4 is the label to jump to at the top of the loop
> -; operand 5 indicates if the loop is entered at the top
> +; operand 1 is the label to jump to at the top of the loop
>  (define_expand "doloop_end"
>    [(parallel [(set (pc) (if_then_else
>                           (ne (match_operand:SI 0 "" "")
>                               (const_int 1))
> -                         (label_ref (match_operand 4 "" ""))
> +                         (label_ref (match_operand 1 "" ""))
>                           (pc)))
>               (set (match_dup 0)
>                    (plus:SI (match_dup 0)
>                             (const_int -1)))
> -             (clobber (match_operand 5 ""))])] ; match_scratch
> +             (clobber (match_dup 2))])] ; match_scratch
>    "TARGET_INSNS_64PLUS && optimize"
>  {
>    /* The loop optimizer doesn't check the predicates... */
>    if (GET_MODE (operands[0]) != SImode)
>      FAIL;
> -  operands[5] = gen_rtx_SCRATCH (SImode);
> +  operands[2] = gen_rtx_SCRATCH (SImode);
>  })
>
>  (define_insn "mvilc"
> Index: gcc/config/ia64/ia64.md
> ===================================================================
> --- gcc/config/ia64/ia64.md     2013-11-05 08:55:57.423644646 +0000
> +++ gcc/config/ia64/ia64.md     2013-11-05 08:56:11.389790457 +0000
> @@ -3956,18 +3956,11 @@ (define_insn "*br_false"
>
>  (define_expand "doloop_end"
>    [(use (match_operand 0 "" ""))       ; loop pseudo
> -   (use (match_operand 1 "" ""))       ; iterations; zero if unknown
> -   (use (match_operand 2 "" ""))       ; max iterations
> -   (use (match_operand 3 "" ""))       ; loop level
> -   (use (match_operand 4 "" ""))       ; label
> -   (use (match_operand 5 "" ""))]      ; flag: 1 if loop entered at top, else 0
> +   (use (match_operand 1 "" ""))]      ; label
>    ""
>  {
> -  /* Only use cloop on innermost loops.  */
> -  if (INTVAL (operands[3]) > 1)
> -    FAIL;
>    emit_jump_insn (gen_doloop_end_internal (gen_rtx_REG (DImode, AR_LC_REGNUM),
> -                                          operands[4]));
> +                                          operands[1]));
>    DONE;
>  })
>
> Index: gcc/config/ia64/ia64.c
> ===================================================================
> --- gcc/config/ia64/ia64.c      2013-11-05 08:55:57.423644646 +0000
> +++ gcc/config/ia64/ia64.c      2013-11-05 08:56:11.387790438 +0000
> @@ -620,6 +620,8 @@ #define TARGET_CAN_ELIMINATE ia64_can_el
>  #undef TARGET_TRAMPOLINE_INIT
>  #define TARGET_TRAMPOLINE_INIT ia64_trampoline_init
>
> +#undef TARGET_CAN_USE_DOLOOP_P
> +#define TARGET_CAN_USE_DOLOOP_P can_use_doloop_if_innermost
>  #undef TARGET_INVALID_WITHIN_DOLOOP
>  #define TARGET_INVALID_WITHIN_DOLOOP hook_constcharptr_const_rtx_null
>
> Index: gcc/config/mep/mep.md
> ===================================================================
> --- gcc/config/mep/mep.md       2013-11-05 08:55:57.423644646 +0000
> +++ gcc/config/mep/mep.md       2013-11-05 08:56:11.391790478 +0000
> @@ -2076,14 +2076,9 @@ (define_insn "doloop_begin_internal"
>
>  (define_expand "doloop_begin"
>    [(use (match_operand 0 "register_operand" ""))
> -   (use (match_operand:QI 1 "const_int_operand" ""))
> -   (use (match_operand:QI 2 "const_int_operand" ""))
> -   (use (match_operand:QI 3 "const_int_operand" ""))
> -   (use (match_operand 4 "" ""))]
> +   (use (match_operand 1 "" ""))]
>    "!profile_arc_flag && TARGET_OPT_REPEAT"
> -  "if (INTVAL (operands[3]) > 1)
> -     FAIL;
> -   mep_emit_doloop (operands, 0);
> +  "mep_emit_doloop (operands, 0);
>     DONE;
>    ")
>
> @@ -2112,15 +2107,9 @@ (define_insn "doloop_end_internal"
>
>  (define_expand "doloop_end"
>    [(use (match_operand 0 "nonimmediate_operand" ""))
> -   (use (match_operand:QI 1 "const_int_operand" ""))
> -   (use (match_operand:QI 2 "const_int_operand" ""))
> -   (use (match_operand:QI 3 "const_int_operand" ""))
> -   (use (label_ref (match_operand 4 "" "")))
> -   (use (match_operand 5 "" ""))]
> +   (use (label_ref (match_operand 1 "" "")))]
>    "!profile_arc_flag && TARGET_OPT_REPEAT"
> -  "if (INTVAL (operands[3]) > 1)
> -     FAIL;
> -   if (GET_CODE (operands[0]) == REG && GET_MODE (operands[0]) != SImode)
> +  "if (GET_CODE (operands[0]) == REG && GET_MODE (operands[0]) != SImode)
>       FAIL;
>     mep_emit_doloop (operands, 1);
>     DONE;
> Index: gcc/config/mep/mep.c
> ===================================================================
> --- gcc/config/mep/mep.c        2013-11-05 08:55:57.423644646 +0000
> +++ gcc/config/mep/mep.c        2013-11-05 08:56:11.390790467 +0000
> @@ -5103,7 +5103,7 @@ mep_emit_doloop (rtx *operands, int is_e
>
>    tag = GEN_INT (cfun->machine->doloop_tags - 1);
>    if (is_end)
> -    emit_jump_insn (gen_doloop_end_internal (operands[0], operands[4], tag));
> +    emit_jump_insn (gen_doloop_end_internal (operands[0], operands[1], tag));
>    else
>      emit_insn (gen_doloop_begin_internal (operands[0], operands[0], tag));
>  }
> @@ -7280,6 +7280,8 @@ #define TARGET_CONDITIONAL_REGISTER_USAG
>  #define TARGET_TRAMPOLINE_INIT         mep_trampoline_init
>  #undef  TARGET_LEGITIMATE_CONSTANT_P
>  #define TARGET_LEGITIMATE_CONSTANT_P   mep_legitimate_constant_p
> +#undef  TARGET_CAN_USE_DOLOOP_P
> +#define TARGET_CAN_USE_DOLOOP_P                can_use_doloop_if_innermost
>
>  struct gcc_target targetm = TARGET_INITIALIZER;
>
> Index: gcc/config/rs6000/rs6000.md
> ===================================================================
> --- gcc/config/rs6000/rs6000.md 2013-11-05 08:55:57.423644646 +0000
> +++ gcc/config/rs6000/rs6000.md 2013-11-05 08:56:11.430790883 +0000
> @@ -14791,28 +14791,21 @@ (define_insn "group_ending_nop"
>
>  (define_expand "doloop_end"
>    [(use (match_operand 0 "" ""))       ; loop pseudo
> -   (use (match_operand 1 "" ""))       ; iterations; zero if unknown
> -   (use (match_operand 2 "" ""))       ; max iterations
> -   (use (match_operand 3 "" ""))       ; loop level
> -   (use (match_operand 4 "" ""))       ; label
> -   (use (match_operand 5 "" ""))]      ; flag: 1 if loop entered at top, else 0
> +   (use (match_operand 1 "" ""))]      ; label
>    ""
>    "
>  {
> -  /* Only use this on innermost loops.  */
> -  if (INTVAL (operands[3]) > 1)
> -    FAIL;
>    if (TARGET_64BIT)
>      {
>        if (GET_MODE (operands[0]) != DImode)
>         FAIL;
> -      emit_jump_insn (gen_ctrdi (operands[0], operands[4]));
> +      emit_jump_insn (gen_ctrdi (operands[0], operands[1]));
>      }
>    else
>      {
>        if (GET_MODE (operands[0]) != SImode)
>         FAIL;
> -      emit_jump_insn (gen_ctrsi (operands[0], operands[4]));
> +      emit_jump_insn (gen_ctrsi (operands[0], operands[1]));
>      }
>    DONE;
>  }")
> Index: gcc/config/rs6000/rs6000.c
> ===================================================================
> --- gcc/config/rs6000/rs6000.c  2013-11-05 08:55:57.423644646 +0000
> +++ gcc/config/rs6000/rs6000.c  2013-11-05 08:56:11.397790540 +0000
> @@ -1593,6 +1593,9 @@ #define TARGET_LEGITIMATE_CONSTANT_P rs6
>
>  #undef TARGET_VECTORIZE_VEC_PERM_CONST_OK
>  #define TARGET_VECTORIZE_VEC_PERM_CONST_OK rs6000_vectorize_vec_perm_const_ok
> +
> +#undef TARGET_CAN_USE_DOLOOP_P
> +#define TARGET_CAN_USE_DOLOOP_P can_use_doloop_if_innermost
>
>
>  /* Processor table.  */
> Index: gcc/config/s390/s390.md
> ===================================================================
> --- gcc/config/s390/s390.md     2013-11-05 08:55:57.423644646 +0000
> +++ gcc/config/s390/s390.md     2013-11-05 08:56:11.551792144 +0000
> @@ -8412,19 +8412,15 @@ (define_insn_and_split "*brx_31bit"
>
>  (define_expand "doloop_end"
>    [(use (match_operand 0 "" ""))        ; loop pseudo
> -   (use (match_operand 1 "" ""))        ; iterations; zero if unknown
> -   (use (match_operand 2 "" ""))        ; max iterations
> -   (use (match_operand 3 "" ""))        ; loop level
> -   (use (match_operand 4 "" ""))        ; label
> -   (use (match_operand 5 "" ""))]       ; flag: 1 if loop entered at top, else 0
> +   (use (match_operand 1 "" ""))]       ; label
>    ""
>  {
>    if (GET_MODE (operands[0]) == SImode && !TARGET_CPU_ZARCH)
> -    emit_jump_insn (gen_doloop_si31 (operands[4], operands[0], operands[0]));
> +    emit_jump_insn (gen_doloop_si31 (operands[1], operands[0], operands[0]));
>    else if (GET_MODE (operands[0]) == SImode && TARGET_CPU_ZARCH)
> -    emit_jump_insn (gen_doloop_si64 (operands[4], operands[0], operands[0]));
> +    emit_jump_insn (gen_doloop_si64 (operands[1], operands[0], operands[0]));
>    else if (GET_MODE (operands[0]) == DImode && TARGET_ZARCH)
> -    emit_jump_insn (gen_doloop_di (operands[4], operands[0], operands[0]));
> +    emit_jump_insn (gen_doloop_di (operands[1], operands[0], operands[0]));
>    else
>      FAIL;
>
> Index: gcc/config/sh/sh.md
> ===================================================================
> --- gcc/config/sh/sh.md 2013-11-05 08:55:57.423644646 +0000
> +++ gcc/config/sh/sh.md 2013-11-05 08:56:11.554792175 +0000
> @@ -8775,25 +8775,21 @@ (define_split
>  })
>
>  ; operand 0 is the loop count pseudo register
> -; operand 1 is the number of loop iterations or 0 if it is unknown
> -; operand 2 is the maximum number of loop iterations
> -; operand 3 is the number of levels of enclosed loops
> -; operand 4 is the label to jump to at the top of the loop
> +; operand 1 is the label to jump to at the top of the loop
>  (define_expand "doloop_end"
>    [(parallel [(set (pc)
>                    (if_then_else (ne:SI (match_operand:SI 0 "" "")
>                                         (const_int 1))
> -                                (label_ref (match_operand 4 "" ""))
> +                                (label_ref (match_operand 1 "" ""))
>                                  (pc)))
>               (set (match_dup 0)
>                    (plus:SI (match_dup 0) (const_int -1)))
> -             (clobber (reg:SI T_REG))])
> -   (match_operand 5 "" "")]
> +             (clobber (reg:SI T_REG))])]
>    "TARGET_SH2"
>  {
>    if (GET_MODE (operands[0]) != SImode)
>      FAIL;
> -  emit_jump_insn (gen_doloop_end_split (operands[0], operands[4], operands[0]));
> +  emit_jump_insn (gen_doloop_end_split (operands[0], operands[1], operands[0]));
>    DONE;
>  })
>
> Index: gcc/config/spu/spu.md
> ===================================================================
> --- gcc/config/spu/spu.md       2013-11-05 08:55:57.423644646 +0000
> +++ gcc/config/spu/spu.md       2013-11-05 08:56:11.593792586 +0000
> @@ -4487,11 +4487,7 @@ (define_insn "dsync"
>   ;; knows what to generate.
>   (define_expand "doloop_end"
>     [(use (match_operand 0 "" ""))      ; loop pseudo
> -    (use (match_operand 1 "" ""))      ; iterations; zero if unknown
> -    (use (match_operand 2 "" ""))      ; max iterations
> -    (use (match_operand 3 "" ""))      ; loop level
> -    (use (match_operand 4 "" ""))      ; label
> -    (match_operand 5 "" "")]
> +    (use (match_operand 1 "" ""))]     ; label
>     ""
>     "
>   {
> @@ -4507,16 +4503,13 @@ (define_insn "dsync"
>       rtx bcomp;
>       rtx loc_ref;
>
> -     /* Only use this on innermost loops.  */
> -     if (INTVAL (operands[3]) > 1)
> -       FAIL;
>       if (GET_MODE (operands[0]) != SImode)
>         FAIL;
>
>       s0 = operands [0];
>       emit_move_insn (s0, gen_rtx_PLUS (SImode, s0, GEN_INT (-1)));
>       bcomp = gen_rtx_NE(SImode, s0, const0_rtx);
> -     loc_ref = gen_rtx_LABEL_REF (VOIDmode, operands [4]);
> +     loc_ref = gen_rtx_LABEL_REF (VOIDmode, operands [1]);
>       emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx,
>                                    gen_rtx_IF_THEN_ELSE (VOIDmode, bcomp,
>                                                          loc_ref, pc_rtx)));
> Index: gcc/config/spu/spu.c
> ===================================================================
> --- gcc/config/spu/spu.c        2013-11-05 08:55:57.423644646 +0000
> +++ gcc/config/spu/spu.c        2013-11-05 08:56:11.592792578 +0000
> @@ -7328,6 +7328,9 @@ #define TARGET_DELAY_VARTRACK true
>  #undef TARGET_CANONICALIZE_COMPARISON
>  #define TARGET_CANONICALIZE_COMPARISON spu_canonicalize_comparison
>
> +#undef TARGET_CAN_USE_DOLOOP_P
> +#define TARGET_CAN_USE_DOLOOP_P can_use_doloop_if_innermost
> +
>  struct gcc_target targetm = TARGET_INITIALIZER;
>
>  #include "gt-spu.h"
> Index: gcc/config/tilegx/tilegx.md
> ===================================================================
> --- gcc/config/tilegx/tilegx.md 2013-11-05 08:55:57.423644646 +0000
> +++ gcc/config/tilegx/tilegx.md 2013-11-05 08:56:11.595792600 +0000
> @@ -2414,11 +2414,7 @@ (define_expand "udivsi3"
>  ;; generate.
>  (define_expand "doloop_end"
>    [(use (match_operand 0 "" ""))    ;; loop pseudo
> -   (use (match_operand 1 "" ""))    ;; iterations; zero if unknown
> -   (use (match_operand 2 "" ""))    ;; max iterations
> -   (use (match_operand 3 "" ""))    ;; loop level
> -   (use (match_operand 4 "" ""))    ;; label
> -   (use (match_operand 5 "" ""))]   ;; flag: 1 if loop entered at top, else 0
> +   (use (match_operand 1 "" ""))]   ;; label
>     ""
>  {
>    if (optimize > 0 && flag_modulo_sched)
> @@ -2428,9 +2424,6 @@ (define_expand "doloop_end"
>       rtx loc_ref;
>       enum machine_mode mode = GET_MODE (operands[0]);
>
> -     /* only do inner loop  */
> -     if (INTVAL (operands[3]) > 1)
> -       FAIL;
>       /* only deal with loop counters in SImode or DImode  */
>       if (mode != SImode && mode != DImode)
>         FAIL;
> @@ -2438,7 +2431,7 @@ (define_expand "doloop_end"
>       s0 = operands [0];
>       emit_move_insn (s0, gen_rtx_PLUS (mode, s0, GEN_INT (-1)));
>       bcomp = gen_rtx_NE(mode, s0, const0_rtx);
> -     loc_ref = gen_rtx_LABEL_REF (VOIDmode, operands [4]);
> +     loc_ref = gen_rtx_LABEL_REF (VOIDmode, operands [1]);
>       emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx,
>                                    gen_rtx_IF_THEN_ELSE (VOIDmode, bcomp,
>                                                          loc_ref, pc_rtx)));
> Index: gcc/config/tilegx/tilegx.c
> ===================================================================
> --- gcc/config/tilegx/tilegx.c  2013-11-05 08:55:57.423644646 +0000
> +++ gcc/config/tilegx/tilegx.c  2013-11-05 08:56:11.594792593 +0000
> @@ -5578,6 +5578,8 @@ #define TARGET_ASM_FILE_END tilegx_file_
>  #undef  TARGET_ASM_ALIGNED_DI_OP
>  #define TARGET_ASM_ALIGNED_DI_OP "\t.quad\t"
>
> +#undef  TARGET_CAN_USE_DOLOOP_P
> +#define TARGET_CAN_USE_DOLOOP_P can_use_doloop_if_innermost
>
>  struct gcc_target targetm = TARGET_INITIALIZER;
>
> Index: gcc/config/tilepro/tilepro.md
> ===================================================================
> --- gcc/config/tilepro/tilepro.md       2013-11-05 08:55:57.423644646 +0000
> +++ gcc/config/tilepro/tilepro.md       2013-11-05 08:56:11.597792621 +0000
> @@ -1318,11 +1318,7 @@ (define_expand "umulsi3_highpart"
>  ;; generate.
>  (define_expand "doloop_end"
>    [(use (match_operand 0 "" ""))    ;; loop pseudo
> -   (use (match_operand 1 "" ""))    ;; iterations; zero if unknown
> -   (use (match_operand 2 "" ""))    ;; max iterations
> -   (use (match_operand 3 "" ""))    ;; loop level
> -   (use (match_operand 4 "" ""))    ;; label
> -   (use (match_operand 5 "" ""))]   ;; flag: 1 if loop entered at top, else 0
> +   (use (match_operand 1 "" ""))]   ;; label
>     ""
>  {
>    if (optimize > 0)
> @@ -1331,9 +1327,6 @@ (define_expand "doloop_end"
>       rtx bcomp;
>       rtx loc_ref;
>
> -     /* only do inner loop  */
> -     if (INTVAL (operands[3]) > 1)
> -       FAIL;
>       /* only deal with loop counters in SImode  */
>       if (GET_MODE (operands[0]) != SImode)
>         FAIL;
> @@ -1342,7 +1335,7 @@ (define_expand "doloop_end"
>
>       emit_move_insn (s0, gen_rtx_PLUS (SImode, s0, GEN_INT (-1)));
>       bcomp = gen_rtx_NE(SImode, s0, const0_rtx);
> -     loc_ref = gen_rtx_LABEL_REF (VOIDmode, operands [4]);
> +     loc_ref = gen_rtx_LABEL_REF (VOIDmode, operands [1]);
>       emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx,
>                                    gen_rtx_IF_THEN_ELSE (VOIDmode, bcomp,
>                                                          loc_ref, pc_rtx)));
> Index: gcc/config/tilepro/tilepro.c
> ===================================================================
> --- gcc/config/tilepro/tilepro.c        2013-11-05 08:55:57.423644646 +0000
> +++ gcc/config/tilepro/tilepro.c        2013-11-05 08:56:11.596792609 +0000
> @@ -5067,6 +5067,8 @@ #define TARGET_PRINT_OPERAND_ADDRESS til
>  #undef  TARGET_ASM_FILE_END
>  #define TARGET_ASM_FILE_END tilepro_file_end
>
> +#undef  TARGET_CAN_USE_DOLOOP_P
> +#define TARGET_CAN_USE_DOLOOP_P can_use_doloop_if_innermost
>
>  struct gcc_target targetm = TARGET_INITIALIZER;
>
> Index: gcc/config/v850/v850.md
> ===================================================================
> --- gcc/config/v850/v850.md     2013-11-05 08:55:57.423644646 +0000
> +++ gcc/config/v850/v850.md     2013-11-05 08:56:11.599792647 +0000
> @@ -1357,20 +1357,11 @@ (define_insn "*rotlsi3_16"
>
>  (define_expand "doloop_begin"
>   [(use (match_operand 0 "" ""))        ; loop pseudo
> -  (use (match_operand 1 "" ""))        ; iterations; zero if unknown
> -  (use (match_operand 2 "" ""))        ; max iterations
> -  (use (match_operand 3 "" ""))        ; loop level
> -  (use (match_operand 4 "" ""))]       ; condition
> +  (use (match_operand 1 "" ""))]       ; doloop_end pattern
>    "TARGET_V850E3V5_UP && TARGET_LOOP"
>    {
> -    rtx loop_cnt   = operands[0];
> -    rtx loop_level = operands[3];
> -
> -    if (INTVAL (loop_level) > 1)
> -      FAIL;
> -    if (GET_MODE (loop_cnt) != SImode)
> -      FAIL;
> -
> +    rtx loop_cnt = operands[0];
> +    gcc_assert (GET_MODE (loop_cnt) == SImode);
>      emit_insn (gen_fix_loop_counter (loop_cnt));
>      DONE;
>    }
> @@ -1394,19 +1385,12 @@ (define_insn "fix_loop_counter"
>
>  (define_expand "doloop_end"
>   [(use (match_operand 0 "" ""))        ; loop pseudo
> -  (use (match_operand 1 "" ""))        ; iterations; zero if unknown
> -  (use (match_operand 2 "" ""))        ; max iterations
> -  (use (match_operand 3 "" ""))        ; loop level
> -  (use (match_operand 4 "" ""))        ; label
> -  (use (match_operand 5 "" ""))]       ; entered at top
> +  (use (match_operand 1 "" ""))]       ; label
>    "TARGET_V850E3V5_UP && TARGET_LOOP"
>    {
> -    rtx loop_cnt   = operands[0];
> -    rtx loop_level = operands[3];
> -    rtx label      = operands[4];
> +    rtx loop_cnt = operands[0];
> +    rtx label    = operands[1];
>
> -    if (INTVAL (loop_level) > 1)
> -      FAIL;
>      if (GET_MODE (loop_cnt) != SImode)
>        FAIL;
>
> Index: gcc/config/v850/v850.c
> ===================================================================
> --- gcc/config/v850/v850.c      2013-11-05 08:55:57.423644646 +0000
> +++ gcc/config/v850/v850.c      2013-11-05 08:56:11.598792634 +0000
> @@ -3269,6 +3269,9 @@ #define TARGET_TRAMPOLINE_INIT v850_tram
>  #undef  TARGET_LEGITIMATE_CONSTANT_P
>  #define TARGET_LEGITIMATE_CONSTANT_P v850_legitimate_constant_p
>
> +#undef  TARGET_CAN_USE_DOLOOP_P
> +#define TARGET_CAN_USE_DOLOOP_P can_use_doloop_if_innermost
> +
>  struct gcc_target targetm = TARGET_INITIALIZER;
>
>  #include "gt-v850.h"
diff mbox

Patch

Index: gcc/target.def
===================================================================
--- gcc/target.def	2013-11-05 08:55:57.423644646 +0000
+++ gcc/target.def	2013-11-05 08:56:11.617792832 +0000
@@ -3572,6 +3572,23 @@  normally defined in @file{libgcc2.c}.",
  tree, (void),
  default_external_stack_protect_fail)
 
+DEFHOOK
+(can_use_doloop_p,
+ "Return true if it is possible to use low-overhead loops (@code{doloop_end}\n\
+and @code{doloop_begin}) for a particular loop.  @var{iterations} gives the\n\
+exact number of iterations, or 0 if not known.  @var{iterations_max} gives\n\
+the maximum number of iterations, or 0 if not known.  @var{loop_depth} is\n\
+the nesting depth of the loop, with 1 for innermost loops, 2 for loops that\n\
+contain innermost loops, and so on.  @var{entered_at_top} is true if the\n\
+loop is only entered from the top.\n\
+\n\
+This hook is only used if @code{doloop_end} is available.  The default\n\
+implementation returns true.  You can use @code{can_use_doloop_if_innermost}\n\
+if the loop must be the innermost, and if there are no other restrictions.",
+ bool, (double_int iterations, double_int iterations_max,
+	unsigned int loop_depth, bool entered_at_top),
+ hook_bool_dint_dint_uint_bool_true)
+
 /* Returns NULL if target supports the insn within a doloop block,
    otherwise it returns an error message.  */
 DEFHOOK
Index: gcc/doc/tm.texi.in
===================================================================
--- gcc/doc/tm.texi.in	2013-11-05 08:55:57.423644646 +0000
+++ gcc/doc/tm.texi.in	2013-11-05 08:56:11.616792820 +0000
@@ -8206,6 +8206,8 @@  to by @var{ce_info}.
 
 @hook TARGET_GENERATE_VERSION_DISPATCHER_BODY
 
+@hook TARGET_CAN_USE_DOLOOP_P
+
 @hook TARGET_INVALID_WITHIN_DOLOOP
 
 @hook TARGET_LEGITIMATE_COMBINED_INSN
Index: gcc/doc/tm.texi
===================================================================
--- gcc/doc/tm.texi	2013-11-05 08:55:57.423644646 +0000
+++ gcc/doc/tm.texi	2013-11-05 08:56:11.614792799 +0000
@@ -11076,6 +11076,20 @@  function version at run-time for a given
 body must be generated.
 @end deftypefn
 
+@deftypefn {Target Hook} bool TARGET_CAN_USE_DOLOOP_P (double_int @var{iterations}, double_int @var{iterations_max}, unsigned int @var{loop_depth}, bool @var{entered_at_top})
+Return true if it is possible to use low-overhead loops (@code{doloop_end}
+and @code{doloop_begin}) for a particular loop.  @var{iterations} gives the
+exact number of iterations, or 0 if not known.  @var{iterations_max} gives
+the maximum number of iterations, or 0 if not known.  @var{loop_depth} is
+the nesting depth of the loop, with 1 for innermost loops, 2 for loops that
+contain innermost loops, and so on.  @var{entered_at_top} is true if the
+loop is only entered from the top.
+
+This hook is only used if @code{doloop_end} is available.  The default
+implementation returns true.  You can use @code{can_use_doloop_if_innermost}
+if the loop must be the innermost, and if there are no other restrictions.
+@end deftypefn
+
 @deftypefn {Target Hook} {const char *} TARGET_INVALID_WITHIN_DOLOOP (const_rtx @var{insn})
 
 Take an instruction in @var{insn} and return NULL if it is valid within a
Index: gcc/doc/md.texi
===================================================================
--- gcc/doc/md.texi	2013-11-05 08:55:57.423644646 +0000
+++ gcc/doc/md.texi	2013-11-05 08:56:11.612792780 +0000
@@ -5856,34 +5856,27 @@  reduction is enabled.
 
 @cindex @code{doloop_end} instruction pattern
 @item @samp{doloop_end}
-Conditional branch instruction that decrements a register and jumps if
-the register is nonzero.  This instruction takes five operands: Operand
-0 is the register to decrement and test; operand 1 is the number of loop
-iterations as a @code{const_int} or @code{const0_rtx} if this cannot be
-determined until run-time; operand 2 is the actual or estimated maximum
-number of iterations as a @code{const_int}; operand 3 is the number of
-enclosed loops as a @code{const_int} (an innermost loop has a value of
-1); operand 4 is the label to jump to if the register is nonzero;
-operand 5 is const1_rtx if the loop in entered at its top, const0_rtx
-otherwise.
+Conditional branch instruction that decrements a register and
+jumps if the register is nonzero.  Operand 0 is the register to
+decrement and test; operand 1 is the label to jump to if the
+register is nonzero.
 @xref{Looping Patterns}.
 
 This optional instruction pattern should be defined for machines with
 low-overhead looping instructions as the loop optimizer will try to
-modify suitable loops to utilize it.  If nested low-overhead looping is
-not supported, use a @code{define_expand} (@pxref{Expander Definitions})
-and make the pattern fail if operand 3 is not @code{const1_rtx}.
-Similarly, if the actual or estimated maximum number of iterations is
-too large for this instruction, make it fail.
+modify suitable loops to utilize it.  The target hook
+@code{TARGET_CAN_USE_DOLOOP_P} controls the conditions under which
+low-overhead loops can be used.
 
 @cindex @code{doloop_begin} instruction pattern
 @item @samp{doloop_begin}
 Companion instruction to @code{doloop_end} required for machines that
-need to perform some initialization, such as loading special registers
-used by a low-overhead looping instruction.  If initialization insns do
-not always need to be emitted, use a @code{define_expand}
-(@pxref{Expander Definitions}) and make it fail.
+need to perform some initialization, such as loading a special counter
+register.  Operand 1 is the associated @code{doloop_end} pattern and
+operand 0 is the register that it decrements.
 
+If initialization insns do not always need to be emitted, use a
+@code{define_expand} (@pxref{Expander Definitions}) and make it fail.
 
 @cindex @code{canonicalize_funcptr_for_compare} instruction pattern
 @item @samp{canonicalize_funcptr_for_compare}
Index: gcc/hooks.h
===================================================================
--- gcc/hooks.h	2013-11-05 08:55:57.423644646 +0000
+++ gcc/hooks.h	2013-11-05 08:56:11.616792820 +0000
@@ -23,6 +23,7 @@ 
 #define GCC_HOOKS_H
 
 #include "machmode.h"
+#include "double-int.h"
 
 extern bool hook_bool_void_false (void);
 extern bool hook_bool_void_true (void);
@@ -60,6 +61,8 @@  extern bool hook_bool_rtx_int_int_int_in
 extern bool hook_bool_tree_tree_false (tree, tree);
 extern bool hook_bool_tree_tree_true (tree, tree);
 extern bool hook_bool_tree_bool_false (tree, bool);
+extern bool hook_bool_dint_dint_uint_bool_true (double_int, double_int,
+						unsigned int, bool);
 
 extern void hook_void_void (void);
 extern void hook_void_constcharptr (const char *);
Index: gcc/hooks.c
===================================================================
--- gcc/hooks.c	2013-11-05 08:55:57.423644646 +0000
+++ gcc/hooks.c	2013-11-05 08:56:11.616792820 +0000
@@ -331,6 +331,12 @@  hook_bool_rtx_int_int_int_intp_bool_fals
   return false;
 }
 
+bool
+hook_bool_dint_dint_uint_bool_true (double_int, double_int, unsigned int, bool)
+{
+  return true;
+}
+
 /* Generic hook that takes an rtx and returns it.  */
 rtx
 hook_rtx_rtx_identity (rtx x)
Index: gcc/targhooks.h
===================================================================
--- gcc/targhooks.h	2013-11-05 08:55:57.423644646 +0000
+++ gcc/targhooks.h	2013-11-05 08:56:11.618792842 +0000
@@ -211,3 +211,5 @@  extern tree default_fn_abi_va_list_bound
 extern tree default_chkp_bound_type (void);
 extern enum machine_mode default_chkp_bound_mode (void);
 extern tree default_builtin_chkp_function (unsigned int);
+extern bool can_use_doloop_if_innermost (double_int, double_int,
+					 unsigned int, bool);
Index: gcc/targhooks.c
===================================================================
--- gcc/targhooks.c	2013-11-05 08:55:57.423644646 +0000
+++ gcc/targhooks.c	2013-11-05 08:56:11.618792842 +0000
@@ -1718,5 +1718,14 @@  default_builtin_chkp_function (unsigned
   return NULL_TREE;
 }
 
+/* An implementation of TARGET_CAN_USE_DOLOOP_P for targets that do
+   not support nested low-overhead loops.  */
+
+bool
+can_use_doloop_if_innermost (double_int, double_int,
+			     unsigned int loop_depth, bool)
+{
+  return loop_depth == 1;
+}
 
 #include "gt-targhooks.h"
Index: gcc/target.h
===================================================================
--- gcc/target.h	2013-11-05 08:55:57.423644646 +0000
+++ gcc/target.h	2013-11-05 08:56:11.618792842 +0000
@@ -50,6 +50,7 @@  #define GCC_TARGET_H
 
 #include "insn-modes.h"
 #include "insn-codes.h"
+#include "double-int.h"
 
 #ifdef ENABLE_CHECKING
 
Index: gcc/loop-doloop.c
===================================================================
--- gcc/loop-doloop.c	2013-11-05 08:55:57.422644636 +0000
+++ gcc/loop-doloop.c	2013-11-05 08:56:11.616792820 +0000
@@ -548,20 +548,8 @@  doloop_modify (struct loop *loop, struct
 #ifdef HAVE_doloop_begin
   {
     rtx init;
-    unsigned level = get_loop_level (loop) + 1;
-    double_int iter;
-    rtx iter_rtx;
-
-    if (!get_max_loop_iterations (loop, &iter)
-	|| !iter.fits_shwi ())
-      iter_rtx = const0_rtx;
-    else
-      iter_rtx = GEN_INT (iter.to_shwi ());
-    init = gen_doloop_begin (counter_reg,
-			     desc->const_iter ? desc->niter_expr : const0_rtx,
-			     iter_rtx,
-			     GEN_INT (level),
-			     doloop_seq);
+
+    init = gen_doloop_begin (counter_reg, doloop_seq);
     if (init)
       {
 	start_sequence ();
@@ -608,8 +596,8 @@  doloop_optimize (struct loop *loop)
 {
   enum machine_mode mode;
   rtx doloop_seq, doloop_pat, doloop_reg;
-  rtx iterations, count;
-  rtx iterations_max;
+  rtx count;
+  double_int iterations, iterations_max;
   rtx start_label;
   rtx condition;
   unsigned level, est_niter;
@@ -617,7 +605,6 @@  doloop_optimize (struct loop *loop)
   struct niter_desc *desc;
   unsigned word_mode_size;
   unsigned HOST_WIDE_INT word_mode_max;
-  double_int iter;
   int entered_at_top;
 
   if (dump_file)
@@ -667,25 +654,30 @@  doloop_optimize (struct loop *loop)
       return false;
     }
 
-  count = copy_rtx (desc->niter_expr);
-  iterations = desc->const_iter ? desc->niter_expr : const0_rtx;
-  if (!get_max_loop_iterations (loop, &iter)
-      || !iter.fits_shwi ())
-    iterations_max = const0_rtx;
+  if (desc->const_iter)
+    iterations = rtx_to_double_int (desc->niter_expr);
   else
-    iterations_max = GEN_INT (iter.to_shwi ());
+    iterations = double_int_zero;
+  if (!get_max_loop_iterations (loop, &iterations_max))
+    iterations_max = double_int_zero;
   level = get_loop_level (loop) + 1;
+  entered_at_top = (loop->latch == desc->in_edge->dest
+		    && contains_no_active_insn_p (loop->latch));
+  if (!targetm.can_use_doloop_p (iterations, iterations_max, level,
+				 entered_at_top))
+    {
+      if (dump_file)
+	fprintf (dump_file, "Loop rejected by can_use_doloop_p.\n");
+      return false;
+    }
 
   /* 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.  */
+  count = copy_rtx (desc->niter_expr);
   start_label = block_label (desc->in_edge->dest);
   doloop_reg = gen_reg_rtx (mode);
-  entered_at_top = (loop->latch == desc->in_edge->dest
-		    && contains_no_active_insn_p (loop->latch));
-  doloop_seq = gen_doloop_end (doloop_reg, iterations, iterations_max,
-			       GEN_INT (level), start_label,
-			       GEN_INT (entered_at_top));
+  doloop_seq = gen_doloop_end (doloop_reg, start_label);
 
   word_mode_size = GET_MODE_PRECISION (word_mode);
   word_mode_max
@@ -696,27 +688,14 @@  doloop_optimize (struct loop *loop)
 	 computed, we must be sure that the number of iterations fits into
 	 the new mode.  */
       && (word_mode_size >= GET_MODE_PRECISION (mode)
-	  || iter.ule (double_int::from_shwi (word_mode_max))))
+	  || iterations_max.ule (double_int::from_shwi (word_mode_max))))
     {
       if (word_mode_size > GET_MODE_PRECISION (mode))
-	{
-	  count = simplify_gen_unary (ZERO_EXTEND, word_mode,
-				      count, mode);
-	  iterations = simplify_gen_unary (ZERO_EXTEND, word_mode,
-					   iterations, mode);
-	  iterations_max = simplify_gen_unary (ZERO_EXTEND, word_mode,
-					       iterations_max, mode);
-	}
+	count = simplify_gen_unary (ZERO_EXTEND, word_mode, count, mode);
       else
-	{
-	  count = lowpart_subreg (word_mode, count, mode);
-	  iterations = lowpart_subreg (word_mode, iterations, mode);
-	  iterations_max = lowpart_subreg (word_mode, iterations_max, mode);
-	}
+	count = lowpart_subreg (word_mode, count, mode);
       PUT_MODE (doloop_reg, word_mode);
-      doloop_seq = gen_doloop_end (doloop_reg, iterations, iterations_max,
-				   GEN_INT (level), start_label,
-				   GEN_INT (entered_at_top));
+      doloop_seq = gen_doloop_end (doloop_reg, start_label);
     }
   if (! doloop_seq)
     {
Index: gcc/config/arc/arc.md
===================================================================
--- gcc/config/arc/arc.md	2013-11-05 08:55:57.423644646 +0000
+++ gcc/config/arc/arc.md	2013-11-05 08:56:11.069787126 +0000
@@ -4706,16 +4706,10 @@  (define_insn_and_split "*bbit_di"
 })
 
 ; operand 0 is the loop count pseudo register
-; operand 1 is the number of loop iterations or 0 if it is unknown
-; operand 2 is the maximum number of loop iterations
-; operand 3 is the number of levels of enclosed loops
-; operand 4 is the loop end pattern
+; operand 1 is the loop end pattern
 (define_expand "doloop_begin"
   [(use (match_operand 0 "register_operand" ""))
-   (use (match_operand:QI 1 "const_int_operand" ""))
-   (use (match_operand:QI 2 "const_int_operand" ""))
-   (use (match_operand:QI 3 "const_int_operand" ""))
-   (use (match_operand 4 "" ""))]
+   (use (match_operand 1 "" ""))]
   ""
 {
   /* Using the INSN_UID of the loop end pattern to identify it causes
@@ -4725,10 +4719,8 @@  (define_expand "doloop_begin"
      still be able to tell what kind of number this is.  */
   static HOST_WIDE_INT loop_end_id = 0;
 
-  if (INTVAL (operands[3]) > 1)
-    FAIL;
   rtx id = GEN_INT (--loop_end_id);
-  XEXP (XVECEXP (PATTERN (operands[4]), 0, 4), 0) = id;
+  XEXP (XVECEXP (PATTERN (operands[1]), 0, 4), 0) = id;
   emit_insn (gen_doloop_begin_i (operands[0], const0_rtx, id,
 				 const0_rtx, const0_rtx));
   DONE;
@@ -4907,11 +4899,7 @@  (define_insn "doloop_begin_i"
 )
 
 ; operand 0 is the loop count pseudo register
-; operand 1 is the number of loop iterations or 0 if it is unknown
-; operand 2 is the maximum number of loop iterations
-; operand 3 is the number of levels of enclosed loops
-; operand 4 is the label to jump to at the top of the loop
-; operand 5 is nonzero if the loop is entered at its top.
+; operand 1 is the label to jump to at the top of the loop
 ; Use this for the ARC600 and ARC700.  For ARCtangent-A5, this is unsafe
 ; without further checking for nearby branches etc., and without proper
 ; annotation of shift patterns that clobber lp_count
@@ -4919,24 +4907,14 @@  (define_insn "doloop_begin_i"
 ; single insn - loop setup is expensive then.
 (define_expand "doloop_end"
   [(use (match_operand 0 "register_operand" ""))
-   (use (match_operand:QI 1 "const_int_operand" ""))
-   (use (match_operand:QI 2 "const_int_operand" ""))
-   (use (match_operand:QI 3 "const_int_operand" ""))
-   (use (label_ref (match_operand 4 "" "")))
-   (use (match_operand:QI 5 "const_int_operand" ""))]
+   (use (label_ref (match_operand 1 "" "")))]
   "TARGET_ARC600 || TARGET_ARC700"
 {
-  if (INTVAL (operands[3]) > 1)
-    FAIL;
-  /* Setting up the loop with two sr isntructions costs 6 cycles.  */
-  if (TARGET_ARC700 && !INTVAL (operands[5])
-      && INTVAL (operands[1]) && INTVAL (operands[1]) <= (flag_pic ? 6 : 3))
-    FAIL;
   /* We could do smaller bivs with biv widening, and wider bivs by having
      a high-word counter in an outer loop - but punt on this for now.  */
   if (GET_MODE (operands[0]) != SImode)
     FAIL;
-  emit_jump_insn (gen_doloop_end_i (operands[0], operands[4], const0_rtx));
+  emit_jump_insn (gen_doloop_end_i (operands[0], operands[1], const0_rtx));
   DONE;
 })
 
Index: gcc/config/arc/arc.c
===================================================================
--- gcc/config/arc/arc.c	2013-11-05 08:55:57.423644646 +0000
+++ gcc/config/arc/arc.c	2013-11-05 08:56:11.045786876 +0000
@@ -388,6 +388,7 @@  static bool arc_return_in_memory (const_
 static void arc_init_simd_builtins (void);
 static bool arc_vector_mode_supported_p (enum machine_mode);
 
+static bool arc_can_use_doloop_p (double_int, double_int, unsigned int, bool);
 static const char *arc_invalid_within_doloop (const_rtx);
 
 static void output_short_suffix (FILE *file);
@@ -493,6 +494,9 @@  #define TARGET_SCHED_ADJUST_PRIORITY arc
 #undef TARGET_VECTOR_MODE_SUPPORTED_P
 #define TARGET_VECTOR_MODE_SUPPORTED_P arc_vector_mode_supported_p
 
+#undef TARGET_CAN_USE_DOLOOP_P
+#define TARGET_CAN_USE_DOLOOP_P arc_can_use_doloop_p
+
 #undef TARGET_INVALID_WITHIN_DOLOOP
 #define TARGET_INVALID_WITHIN_DOLOOP arc_invalid_within_doloop
 
@@ -5638,6 +5642,23 @@  arc_pass_by_reference (cumulative_args_t
 	      || TREE_ADDRESSABLE (type)));
 }
 
+/* Implement TARGET_CAN_USE_DOLOOP_P.  */
+
+static bool
+arc_can_use_doloop_p (double_int iterations, double_int,
+		      unsigned int loop_depth, bool entered_at_top)
+{
+  if (loop_depth > 1)
+    return false;
+  /* Setting up the loop with two sr instructions costs 6 cycles.  */
+  if (TARGET_ARC700
+      && !entered_at_top
+      && iterations.high == 0
+      && iterations.low > 0
+      && iterations.low <= (flag_pic ? 6 : 3))
+    return false;
+  return true;
+}
 
 /* NULL if INSN insn is valid within a low-overhead loop.
    Otherwise return why doloop cannot be applied.  */
Index: gcc/config/arm/thumb2.md
===================================================================
--- gcc/config/arm/thumb2.md	2013-11-05 08:55:57.423644646 +0000
+++ gcc/config/arm/thumb2.md	2013-11-05 08:56:11.212788615 +0000
@@ -1449,11 +1449,7 @@  (define_peephole2
 ;; knows what to generate.
 (define_expand "doloop_end"
   [(use (match_operand 0 "" ""))      ; loop pseudo
-   (use (match_operand 1 "" ""))      ; iterations; zero if unknown
-   (use (match_operand 2 "" ""))      ; max iterations
-   (use (match_operand 3 "" ""))      ; loop level
-   (use (match_operand 4 "" ""))      ; label
-   (use (match_operand 5 "" ""))]     ; flag: 1 if loop entered at top, else 0
+   (use (match_operand 1 "" ""))]     ; label
   "TARGET_32BIT"
   "
  {
@@ -1472,10 +1468,6 @@  (define_expand "doloop_end"
      rtx insn;
      rtx cmp;
 
-     /* Only use this on innermost loops.  */
-     if (INTVAL (operands[3]) > 1)
-       FAIL;
-
      if (GET_MODE (operands[0]) != SImode)
        FAIL;
 
@@ -1488,7 +1480,7 @@  (define_expand "doloop_end"
      cmp = XVECEXP (PATTERN (insn), 0, 0);
      cc_reg = SET_DEST (cmp);
      bcomp = gen_rtx_NE (VOIDmode, cc_reg, const0_rtx);
-     loc_ref = gen_rtx_LABEL_REF (VOIDmode, operands [4]);
+     loc_ref = gen_rtx_LABEL_REF (VOIDmode, operands [1]);
      emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx,
                                   gen_rtx_IF_THEN_ELSE (VOIDmode, bcomp,
                                                         loc_ref, pc_rtx)));
Index: gcc/config/arm/arm.c
===================================================================
--- gcc/config/arm/arm.c	2013-11-05 08:55:57.423644646 +0000
+++ gcc/config/arm/arm.c	2013-11-05 08:56:11.211788604 +0000
@@ -669,6 +669,8 @@  #define TARGET_ASAN_SHADOW_OFFSET arm_as
 #undef MAX_INSN_PER_IT_BLOCK
 #define MAX_INSN_PER_IT_BLOCK (arm_restrict_it ? 1 : 4)
 
+#undef TARGET_CAN_USE_DOLOOP_P
+#define TARGET_CAN_USE_DOLOOP_P can_use_doloop_if_innermost
 
 struct gcc_target targetm = TARGET_INITIALIZER;
 
Index: gcc/config/bfin/bfin.md
===================================================================
--- gcc/config/bfin/bfin.md	2013-11-05 08:55:57.423644646 +0000
+++ gcc/config/bfin/bfin.md	2013-11-05 08:56:11.619792853 +0000
@@ -1929,35 +1929,25 @@  (define_insn "*tablejump_internal"
 ;;  Hardware loop
 
 ; operand 0 is the loop count pseudo register
-; operand 1 is the number of loop iterations or 0 if it is unknown
-; operand 2 is the maximum number of loop iterations
-; operand 3 is the number of levels of enclosed loops
-; operand 4 is the label to jump to at the top of the loop
-; operand 5 indicates if the loop is entered at the top
+; operand 1 is the label to jump to at the top of the loop
 (define_expand "doloop_end"
   [(parallel [(set (pc) (if_then_else
 			  (ne (match_operand:SI 0 "" "")
 			      (const_int 1))
-			  (label_ref (match_operand 4 "" ""))
+			  (label_ref (match_operand 1 "" ""))
 			  (pc)))
 	      (set (match_dup 0)
 		   (plus:SI (match_dup 0)
 			    (const_int -1)))
 	      (unspec [(const_int 0)] UNSPEC_LSETUP_END)
-	      (clobber (match_operand 5 ""))])] ; match_scratch
+	      (clobber (match_dup 2))])] ; match_scratch
   ""
 {
   /* The loop optimizer doesn't check the predicates... */
   if (GET_MODE (operands[0]) != SImode)
     FAIL;
-  /* Due to limitations in the hardware (an initial loop count of 0
-     does not loop 2^32 times) we must avoid to generate a hardware
-     loops when we cannot rule out this case.  */
-  if (!flag_unsafe_loop_optimizations
-      && (unsigned HOST_WIDE_INT) INTVAL (operands[2]) >= 0xFFFFFFFF)
-    FAIL;
   bfin_hardware_loop ();
-  operands[5] = gen_rtx_SCRATCH (SImode);
+  operands[2] = gen_rtx_SCRATCH (SImode);
 })
 
 (define_insn "loop_end"
Index: gcc/config/bfin/bfin.c
===================================================================
--- gcc/config/bfin/bfin.c	2013-11-05 08:55:57.423644646 +0000
+++ gcc/config/bfin/bfin.c	2013-11-05 08:56:11.367790231 +0000
@@ -3366,6 +3366,22 @@  find_prev_insn_start (rtx insn)
   return insn;
 }
 
+/* Implement TARGET_CAN_USE_DOLOOP_P.  */
+
+static bool
+bfin_can_use_doloop_p (double_int, double_int iterations_max,
+		       unsigned int, bool)
+{
+  /* Due to limitations in the hardware (an initial loop count of 0
+     does not loop 2^32 times) we must avoid to generate a hardware
+     loops when we cannot rule out this case.  */
+  if (!flag_unsafe_loop_optimizations
+      && (iterations_max.high != 0
+	  || iterations_max.low >= 0xFFFFFFFF))
+    return false;
+  return true;
+}
+
 /* Increment the counter for the number of loop instructions in the
    current function.  */
 
@@ -5810,4 +5826,7 @@  #define TARGET_DELAY_SCHED2 true
 #undef TARGET_DELAY_VARTRACK
 #define TARGET_DELAY_VARTRACK true
 
+#undef TARGET_CAN_USE_DOLOOP_P
+#define TARGET_CAN_USE_DOLOOP_P bfin_can_use_doloop_p
+
 struct gcc_target targetm = TARGET_INITIALIZER;
Index: gcc/config/c6x/c6x.md
===================================================================
--- gcc/config/c6x/c6x.md	2013-11-05 08:55:57.423644646 +0000
+++ gcc/config/c6x/c6x.md	2013-11-05 08:56:11.384790405 +0000
@@ -1421,27 +1421,23 @@  (define_insn_and_split "eh_return"
 ;; -------------------------------------------------------------------------
 
 ; operand 0 is the loop count pseudo register
-; operand 1 is the number of loop iterations or 0 if it is unknown
-; operand 2 is the maximum number of loop iterations
-; operand 3 is the number of levels of enclosed loops
-; operand 4 is the label to jump to at the top of the loop
-; operand 5 indicates if the loop is entered at the top
+; operand 1 is the label to jump to at the top of the loop
 (define_expand "doloop_end"
   [(parallel [(set (pc) (if_then_else
 			  (ne (match_operand:SI 0 "" "")
 			      (const_int 1))
-			  (label_ref (match_operand 4 "" ""))
+			  (label_ref (match_operand 1 "" ""))
 			  (pc)))
 	      (set (match_dup 0)
 		   (plus:SI (match_dup 0)
 			    (const_int -1)))
-	      (clobber (match_operand 5 ""))])] ; match_scratch
+	      (clobber (match_dup 2))])] ; match_scratch
   "TARGET_INSNS_64PLUS && optimize"
 {
   /* The loop optimizer doesn't check the predicates... */
   if (GET_MODE (operands[0]) != SImode)
     FAIL;
-  operands[5] = gen_rtx_SCRATCH (SImode);
+  operands[2] = gen_rtx_SCRATCH (SImode);
 })
 
 (define_insn "mvilc"
Index: gcc/config/ia64/ia64.md
===================================================================
--- gcc/config/ia64/ia64.md	2013-11-05 08:55:57.423644646 +0000
+++ gcc/config/ia64/ia64.md	2013-11-05 08:56:11.389790457 +0000
@@ -3956,18 +3956,11 @@  (define_insn "*br_false"
 
 (define_expand "doloop_end"
   [(use (match_operand 0 "" ""))	; loop pseudo
-   (use (match_operand 1 "" ""))	; iterations; zero if unknown
-   (use (match_operand 2 "" ""))	; max iterations
-   (use (match_operand 3 "" ""))	; loop level
-   (use (match_operand 4 "" ""))	; label
-   (use (match_operand 5 "" ""))]	; flag: 1 if loop entered at top, else 0
+   (use (match_operand 1 "" ""))]	; label
   ""
 {
-  /* Only use cloop on innermost loops.  */
-  if (INTVAL (operands[3]) > 1)
-    FAIL;
   emit_jump_insn (gen_doloop_end_internal (gen_rtx_REG (DImode, AR_LC_REGNUM),
-					   operands[4]));
+					   operands[1]));
   DONE;
 })
 
Index: gcc/config/ia64/ia64.c
===================================================================
--- gcc/config/ia64/ia64.c	2013-11-05 08:55:57.423644646 +0000
+++ gcc/config/ia64/ia64.c	2013-11-05 08:56:11.387790438 +0000
@@ -620,6 +620,8 @@  #define TARGET_CAN_ELIMINATE ia64_can_el
 #undef TARGET_TRAMPOLINE_INIT
 #define TARGET_TRAMPOLINE_INIT ia64_trampoline_init
 
+#undef TARGET_CAN_USE_DOLOOP_P
+#define TARGET_CAN_USE_DOLOOP_P can_use_doloop_if_innermost
 #undef TARGET_INVALID_WITHIN_DOLOOP
 #define TARGET_INVALID_WITHIN_DOLOOP hook_constcharptr_const_rtx_null
 
Index: gcc/config/mep/mep.md
===================================================================
--- gcc/config/mep/mep.md	2013-11-05 08:55:57.423644646 +0000
+++ gcc/config/mep/mep.md	2013-11-05 08:56:11.391790478 +0000
@@ -2076,14 +2076,9 @@  (define_insn "doloop_begin_internal"
 
 (define_expand "doloop_begin"
   [(use (match_operand 0 "register_operand" ""))
-   (use (match_operand:QI 1 "const_int_operand" ""))
-   (use (match_operand:QI 2 "const_int_operand" ""))
-   (use (match_operand:QI 3 "const_int_operand" ""))
-   (use (match_operand 4 "" ""))]
+   (use (match_operand 1 "" ""))]
   "!profile_arc_flag && TARGET_OPT_REPEAT"
-  "if (INTVAL (operands[3]) > 1)
-     FAIL;
-   mep_emit_doloop (operands, 0);
+  "mep_emit_doloop (operands, 0);
    DONE;
   ")
 
@@ -2112,15 +2107,9 @@  (define_insn "doloop_end_internal"
 
 (define_expand "doloop_end"
   [(use (match_operand 0 "nonimmediate_operand" ""))
-   (use (match_operand:QI 1 "const_int_operand" ""))
-   (use (match_operand:QI 2 "const_int_operand" ""))
-   (use (match_operand:QI 3 "const_int_operand" ""))
-   (use (label_ref (match_operand 4 "" "")))
-   (use (match_operand 5 "" ""))]
+   (use (label_ref (match_operand 1 "" "")))]
   "!profile_arc_flag && TARGET_OPT_REPEAT"
-  "if (INTVAL (operands[3]) > 1)
-     FAIL;
-   if (GET_CODE (operands[0]) == REG && GET_MODE (operands[0]) != SImode)
+  "if (GET_CODE (operands[0]) == REG && GET_MODE (operands[0]) != SImode)
      FAIL;
    mep_emit_doloop (operands, 1);
    DONE;
Index: gcc/config/mep/mep.c
===================================================================
--- gcc/config/mep/mep.c	2013-11-05 08:55:57.423644646 +0000
+++ gcc/config/mep/mep.c	2013-11-05 08:56:11.390790467 +0000
@@ -5103,7 +5103,7 @@  mep_emit_doloop (rtx *operands, int is_e
 
   tag = GEN_INT (cfun->machine->doloop_tags - 1);
   if (is_end)
-    emit_jump_insn (gen_doloop_end_internal (operands[0], operands[4], tag));
+    emit_jump_insn (gen_doloop_end_internal (operands[0], operands[1], tag));
   else
     emit_insn (gen_doloop_begin_internal (operands[0], operands[0], tag));
 }
@@ -7280,6 +7280,8 @@  #define TARGET_CONDITIONAL_REGISTER_USAG
 #define TARGET_TRAMPOLINE_INIT		mep_trampoline_init
 #undef  TARGET_LEGITIMATE_CONSTANT_P
 #define TARGET_LEGITIMATE_CONSTANT_P	mep_legitimate_constant_p
+#undef  TARGET_CAN_USE_DOLOOP_P
+#define TARGET_CAN_USE_DOLOOP_P		can_use_doloop_if_innermost
 
 struct gcc_target targetm = TARGET_INITIALIZER;
 
Index: gcc/config/rs6000/rs6000.md
===================================================================
--- gcc/config/rs6000/rs6000.md	2013-11-05 08:55:57.423644646 +0000
+++ gcc/config/rs6000/rs6000.md	2013-11-05 08:56:11.430790883 +0000
@@ -14791,28 +14791,21 @@  (define_insn "group_ending_nop"
 
 (define_expand "doloop_end"
   [(use (match_operand 0 "" ""))	; loop pseudo
-   (use (match_operand 1 "" ""))	; iterations; zero if unknown
-   (use (match_operand 2 "" ""))	; max iterations
-   (use (match_operand 3 "" ""))	; loop level
-   (use (match_operand 4 "" ""))	; label
-   (use (match_operand 5 "" ""))]	; flag: 1 if loop entered at top, else 0
+   (use (match_operand 1 "" ""))]	; label
   ""
   "
 {
-  /* Only use this on innermost loops.  */
-  if (INTVAL (operands[3]) > 1)
-    FAIL;
   if (TARGET_64BIT)
     {
       if (GET_MODE (operands[0]) != DImode)
 	FAIL;
-      emit_jump_insn (gen_ctrdi (operands[0], operands[4]));
+      emit_jump_insn (gen_ctrdi (operands[0], operands[1]));
     }
   else
     {
       if (GET_MODE (operands[0]) != SImode)
 	FAIL;
-      emit_jump_insn (gen_ctrsi (operands[0], operands[4]));
+      emit_jump_insn (gen_ctrsi (operands[0], operands[1]));
     }
   DONE;
 }")
Index: gcc/config/rs6000/rs6000.c
===================================================================
--- gcc/config/rs6000/rs6000.c	2013-11-05 08:55:57.423644646 +0000
+++ gcc/config/rs6000/rs6000.c	2013-11-05 08:56:11.397790540 +0000
@@ -1593,6 +1593,9 @@  #define TARGET_LEGITIMATE_CONSTANT_P rs6
 
 #undef TARGET_VECTORIZE_VEC_PERM_CONST_OK
 #define TARGET_VECTORIZE_VEC_PERM_CONST_OK rs6000_vectorize_vec_perm_const_ok
+
+#undef TARGET_CAN_USE_DOLOOP_P
+#define TARGET_CAN_USE_DOLOOP_P can_use_doloop_if_innermost
 
 
 /* Processor table.  */
Index: gcc/config/s390/s390.md
===================================================================
--- gcc/config/s390/s390.md	2013-11-05 08:55:57.423644646 +0000
+++ gcc/config/s390/s390.md	2013-11-05 08:56:11.551792144 +0000
@@ -8412,19 +8412,15 @@  (define_insn_and_split "*brx_31bit"
 
 (define_expand "doloop_end"
   [(use (match_operand 0 "" ""))        ; loop pseudo
-   (use (match_operand 1 "" ""))        ; iterations; zero if unknown
-   (use (match_operand 2 "" ""))        ; max iterations
-   (use (match_operand 3 "" ""))        ; loop level
-   (use (match_operand 4 "" ""))        ; label
-   (use (match_operand 5 "" ""))]       ; flag: 1 if loop entered at top, else 0
+   (use (match_operand 1 "" ""))]       ; label
   ""
 {
   if (GET_MODE (operands[0]) == SImode && !TARGET_CPU_ZARCH)
-    emit_jump_insn (gen_doloop_si31 (operands[4], operands[0], operands[0]));
+    emit_jump_insn (gen_doloop_si31 (operands[1], operands[0], operands[0]));
   else if (GET_MODE (operands[0]) == SImode && TARGET_CPU_ZARCH)
-    emit_jump_insn (gen_doloop_si64 (operands[4], operands[0], operands[0]));
+    emit_jump_insn (gen_doloop_si64 (operands[1], operands[0], operands[0]));
   else if (GET_MODE (operands[0]) == DImode && TARGET_ZARCH)
-    emit_jump_insn (gen_doloop_di (operands[4], operands[0], operands[0]));
+    emit_jump_insn (gen_doloop_di (operands[1], operands[0], operands[0]));
   else
     FAIL;
 
Index: gcc/config/sh/sh.md
===================================================================
--- gcc/config/sh/sh.md	2013-11-05 08:55:57.423644646 +0000
+++ gcc/config/sh/sh.md	2013-11-05 08:56:11.554792175 +0000
@@ -8775,25 +8775,21 @@  (define_split
 })
 
 ; operand 0 is the loop count pseudo register
-; operand 1 is the number of loop iterations or 0 if it is unknown
-; operand 2 is the maximum number of loop iterations
-; operand 3 is the number of levels of enclosed loops
-; operand 4 is the label to jump to at the top of the loop
+; operand 1 is the label to jump to at the top of the loop
 (define_expand "doloop_end"
   [(parallel [(set (pc)
 		   (if_then_else (ne:SI (match_operand:SI 0 "" "")
 				        (const_int 1))
-				 (label_ref (match_operand 4 "" ""))
+				 (label_ref (match_operand 1 "" ""))
 				 (pc)))
 	      (set (match_dup 0)
 		   (plus:SI (match_dup 0) (const_int -1)))
-	      (clobber (reg:SI T_REG))])
-   (match_operand 5 "" "")]
+	      (clobber (reg:SI T_REG))])]
   "TARGET_SH2"
 {
   if (GET_MODE (operands[0]) != SImode)
     FAIL;
-  emit_jump_insn (gen_doloop_end_split (operands[0], operands[4], operands[0]));
+  emit_jump_insn (gen_doloop_end_split (operands[0], operands[1], operands[0]));
   DONE;
 })
 
Index: gcc/config/spu/spu.md
===================================================================
--- gcc/config/spu/spu.md	2013-11-05 08:55:57.423644646 +0000
+++ gcc/config/spu/spu.md	2013-11-05 08:56:11.593792586 +0000
@@ -4487,11 +4487,7 @@  (define_insn "dsync"
  ;; knows what to generate.
  (define_expand "doloop_end"
    [(use (match_operand 0 "" ""))      ; loop pseudo
-    (use (match_operand 1 "" ""))      ; iterations; zero if unknown
-    (use (match_operand 2 "" ""))      ; max iterations
-    (use (match_operand 3 "" ""))      ; loop level
-    (use (match_operand 4 "" ""))      ; label
-    (match_operand 5 "" "")]
+    (use (match_operand 1 "" ""))]     ; label
    ""
    "
  {
@@ -4507,16 +4503,13 @@  (define_insn "dsync"
      rtx bcomp;
      rtx loc_ref;
 
-     /* Only use this on innermost loops.  */
-     if (INTVAL (operands[3]) > 1)
-       FAIL;
      if (GET_MODE (operands[0]) != SImode)
        FAIL;
 
      s0 = operands [0];
      emit_move_insn (s0, gen_rtx_PLUS (SImode, s0, GEN_INT (-1)));
      bcomp = gen_rtx_NE(SImode, s0, const0_rtx);
-     loc_ref = gen_rtx_LABEL_REF (VOIDmode, operands [4]);
+     loc_ref = gen_rtx_LABEL_REF (VOIDmode, operands [1]);
      emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx,
                                   gen_rtx_IF_THEN_ELSE (VOIDmode, bcomp,
                                                         loc_ref, pc_rtx)));
Index: gcc/config/spu/spu.c
===================================================================
--- gcc/config/spu/spu.c	2013-11-05 08:55:57.423644646 +0000
+++ gcc/config/spu/spu.c	2013-11-05 08:56:11.592792578 +0000
@@ -7328,6 +7328,9 @@  #define TARGET_DELAY_VARTRACK true
 #undef TARGET_CANONICALIZE_COMPARISON
 #define TARGET_CANONICALIZE_COMPARISON spu_canonicalize_comparison
 
+#undef TARGET_CAN_USE_DOLOOP_P
+#define TARGET_CAN_USE_DOLOOP_P can_use_doloop_if_innermost
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 
 #include "gt-spu.h"
Index: gcc/config/tilegx/tilegx.md
===================================================================
--- gcc/config/tilegx/tilegx.md	2013-11-05 08:55:57.423644646 +0000
+++ gcc/config/tilegx/tilegx.md	2013-11-05 08:56:11.595792600 +0000
@@ -2414,11 +2414,7 @@  (define_expand "udivsi3"
 ;; generate.
 (define_expand "doloop_end"
   [(use (match_operand 0 "" ""))    ;; loop pseudo
-   (use (match_operand 1 "" ""))    ;; iterations; zero if unknown
-   (use (match_operand 2 "" ""))    ;; max iterations
-   (use (match_operand 3 "" ""))    ;; loop level
-   (use (match_operand 4 "" ""))    ;; label
-   (use (match_operand 5 "" ""))]   ;; flag: 1 if loop entered at top, else 0
+   (use (match_operand 1 "" ""))]   ;; label
    ""
 {
   if (optimize > 0 && flag_modulo_sched)
@@ -2428,9 +2424,6 @@  (define_expand "doloop_end"
      rtx loc_ref;
      enum machine_mode mode = GET_MODE (operands[0]);
 
-     /* only do inner loop  */
-     if (INTVAL (operands[3]) > 1)
-       FAIL;
      /* only deal with loop counters in SImode or DImode  */
      if (mode != SImode && mode != DImode)
        FAIL;
@@ -2438,7 +2431,7 @@  (define_expand "doloop_end"
      s0 = operands [0];
      emit_move_insn (s0, gen_rtx_PLUS (mode, s0, GEN_INT (-1)));
      bcomp = gen_rtx_NE(mode, s0, const0_rtx);
-     loc_ref = gen_rtx_LABEL_REF (VOIDmode, operands [4]);
+     loc_ref = gen_rtx_LABEL_REF (VOIDmode, operands [1]);
      emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx,
                                   gen_rtx_IF_THEN_ELSE (VOIDmode, bcomp,
                                                         loc_ref, pc_rtx)));
Index: gcc/config/tilegx/tilegx.c
===================================================================
--- gcc/config/tilegx/tilegx.c	2013-11-05 08:55:57.423644646 +0000
+++ gcc/config/tilegx/tilegx.c	2013-11-05 08:56:11.594792593 +0000
@@ -5578,6 +5578,8 @@  #define TARGET_ASM_FILE_END tilegx_file_
 #undef  TARGET_ASM_ALIGNED_DI_OP
 #define TARGET_ASM_ALIGNED_DI_OP "\t.quad\t"
 
+#undef  TARGET_CAN_USE_DOLOOP_P
+#define TARGET_CAN_USE_DOLOOP_P can_use_doloop_if_innermost
 
 struct gcc_target targetm = TARGET_INITIALIZER;
 
Index: gcc/config/tilepro/tilepro.md
===================================================================
--- gcc/config/tilepro/tilepro.md	2013-11-05 08:55:57.423644646 +0000
+++ gcc/config/tilepro/tilepro.md	2013-11-05 08:56:11.597792621 +0000
@@ -1318,11 +1318,7 @@  (define_expand "umulsi3_highpart"
 ;; generate.
 (define_expand "doloop_end"
   [(use (match_operand 0 "" ""))    ;; loop pseudo
-   (use (match_operand 1 "" ""))    ;; iterations; zero if unknown
-   (use (match_operand 2 "" ""))    ;; max iterations
-   (use (match_operand 3 "" ""))    ;; loop level
-   (use (match_operand 4 "" ""))    ;; label
-   (use (match_operand 5 "" ""))]   ;; flag: 1 if loop entered at top, else 0
+   (use (match_operand 1 "" ""))]   ;; label
    ""
 {
   if (optimize > 0)
@@ -1331,9 +1327,6 @@  (define_expand "doloop_end"
      rtx bcomp;
      rtx loc_ref;
 
-     /* only do inner loop  */
-     if (INTVAL (operands[3]) > 1)
-       FAIL;
      /* only deal with loop counters in SImode  */
      if (GET_MODE (operands[0]) != SImode)
        FAIL;
@@ -1342,7 +1335,7 @@  (define_expand "doloop_end"
 
      emit_move_insn (s0, gen_rtx_PLUS (SImode, s0, GEN_INT (-1)));
      bcomp = gen_rtx_NE(SImode, s0, const0_rtx);
-     loc_ref = gen_rtx_LABEL_REF (VOIDmode, operands [4]);
+     loc_ref = gen_rtx_LABEL_REF (VOIDmode, operands [1]);
      emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx,
                                   gen_rtx_IF_THEN_ELSE (VOIDmode, bcomp,
                                                         loc_ref, pc_rtx)));
Index: gcc/config/tilepro/tilepro.c
===================================================================
--- gcc/config/tilepro/tilepro.c	2013-11-05 08:55:57.423644646 +0000
+++ gcc/config/tilepro/tilepro.c	2013-11-05 08:56:11.596792609 +0000
@@ -5067,6 +5067,8 @@  #define TARGET_PRINT_OPERAND_ADDRESS til
 #undef  TARGET_ASM_FILE_END
 #define TARGET_ASM_FILE_END tilepro_file_end
 
+#undef  TARGET_CAN_USE_DOLOOP_P
+#define TARGET_CAN_USE_DOLOOP_P can_use_doloop_if_innermost
 
 struct gcc_target targetm = TARGET_INITIALIZER;
 
Index: gcc/config/v850/v850.md
===================================================================
--- gcc/config/v850/v850.md	2013-11-05 08:55:57.423644646 +0000
+++ gcc/config/v850/v850.md	2013-11-05 08:56:11.599792647 +0000
@@ -1357,20 +1357,11 @@  (define_insn "*rotlsi3_16"
 
 (define_expand "doloop_begin"
  [(use (match_operand 0 "" ""))        ; loop pseudo
-  (use (match_operand 1 "" ""))        ; iterations; zero if unknown
-  (use (match_operand 2 "" ""))        ; max iterations
-  (use (match_operand 3 "" ""))        ; loop level
-  (use (match_operand 4 "" ""))]       ; condition
+  (use (match_operand 1 "" ""))]       ; doloop_end pattern
   "TARGET_V850E3V5_UP && TARGET_LOOP"
   {
-    rtx loop_cnt   = operands[0];
-    rtx loop_level = operands[3];
-
-    if (INTVAL (loop_level) > 1)
-      FAIL;
-    if (GET_MODE (loop_cnt) != SImode)
-      FAIL;
-
+    rtx loop_cnt = operands[0];
+    gcc_assert (GET_MODE (loop_cnt) == SImode);
     emit_insn (gen_fix_loop_counter (loop_cnt));
     DONE;
   }
@@ -1394,19 +1385,12 @@  (define_insn "fix_loop_counter"
 
 (define_expand "doloop_end"
  [(use (match_operand 0 "" ""))        ; loop pseudo
-  (use (match_operand 1 "" ""))        ; iterations; zero if unknown
-  (use (match_operand 2 "" ""))        ; max iterations
-  (use (match_operand 3 "" ""))        ; loop level
-  (use (match_operand 4 "" ""))        ; label
-  (use (match_operand 5 "" ""))]       ; entered at top
+  (use (match_operand 1 "" ""))]       ; label
   "TARGET_V850E3V5_UP && TARGET_LOOP"
   {
-    rtx loop_cnt   = operands[0];
-    rtx loop_level = operands[3];
-    rtx label      = operands[4];
+    rtx loop_cnt = operands[0];
+    rtx label    = operands[1];
 
-    if (INTVAL (loop_level) > 1)
-      FAIL;
     if (GET_MODE (loop_cnt) != SImode)
       FAIL;
 
Index: gcc/config/v850/v850.c
===================================================================
--- gcc/config/v850/v850.c	2013-11-05 08:55:57.423644646 +0000
+++ gcc/config/v850/v850.c	2013-11-05 08:56:11.598792634 +0000
@@ -3269,6 +3269,9 @@  #define TARGET_TRAMPOLINE_INIT v850_tram
 #undef  TARGET_LEGITIMATE_CONSTANT_P
 #define TARGET_LEGITIMATE_CONSTANT_P v850_legitimate_constant_p
 
+#undef  TARGET_CAN_USE_DOLOOP_P
+#define TARGET_CAN_USE_DOLOOP_P can_use_doloop_if_innermost
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 
 #include "gt-v850.h"