Example #1
0
static bool
prefer_and_bit_test (enum machine_mode mode, int bitnum)
{
  if (and_test == 0)
    {
      /* Set up rtxes for the two variations.  Use NULL as a placeholder
	 for the BITNUM-based constants.  */
      and_reg = gen_rtx_REG (mode, FIRST_PSEUDO_REGISTER);
      and_test = gen_rtx_AND (mode, and_reg, NULL);
      shift_test = gen_rtx_AND (mode, gen_rtx_ASHIFTRT (mode, and_reg, NULL),
				const1_rtx);
    }
  else
    {
      /* Change the mode of the previously-created rtxes.  */
      PUT_MODE (and_reg, mode);
      PUT_MODE (and_test, mode);
      PUT_MODE (shift_test, mode);
      PUT_MODE (XEXP (shift_test, 0), mode);
    }

  /* Fill in the integers.  */
  XEXP (and_test, 1)
    = immed_double_int_const (double_int_setbit (double_int_zero, bitnum),
						 mode);
  XEXP (XEXP (shift_test, 0), 1) = GEN_INT (bitnum);

  return (rtx_cost (and_test, IF_THEN_ELSE, optimize_insn_for_speed_p ())
	  <= rtx_cost (shift_test, IF_THEN_ELSE, optimize_insn_for_speed_p ()));
}
Example #2
0
static bool
prefer_and_bit_test (machine_mode mode, int bitnum)
{
  bool speed_p;
  wide_int mask = wi::set_bit_in_zero (bitnum, GET_MODE_PRECISION (mode));

  if (and_test == 0)
    {
      /* Set up rtxes for the two variations.  Use NULL as a placeholder
	 for the BITNUM-based constants.  */
      and_reg = gen_rtx_REG (mode, LAST_VIRTUAL_REGISTER + 1);
      and_test = gen_rtx_AND (mode, and_reg, NULL);
      shift_test = gen_rtx_AND (mode, gen_rtx_ASHIFTRT (mode, and_reg, NULL),
				const1_rtx);
    }
  else
    {
      /* Change the mode of the previously-created rtxes.  */
      PUT_MODE (and_reg, mode);
      PUT_MODE (and_test, mode);
      PUT_MODE (shift_test, mode);
      PUT_MODE (XEXP (shift_test, 0), mode);
    }

  /* Fill in the integers.  */
  XEXP (and_test, 1) = immed_wide_int_const (mask, mode);
  XEXP (XEXP (shift_test, 0), 1) = GEN_INT (bitnum);

  speed_p = optimize_insn_for_speed_p ();
  return (rtx_cost (and_test, mode, IF_THEN_ELSE, 0, speed_p)
	  <= rtx_cost (shift_test, mode, IF_THEN_ELSE, 0, speed_p));
}
Example #3
0
rtx
gen_rtx_fmt_iuuBieiee (RTX_CODE code, enum machine_mode mode,
	int arg0,
	rtx arg1,
	rtx arg2,
	struct basic_block_def *arg3,
	int arg4,
	rtx arg5,
	int arg6,
	rtx arg7,
	rtx arg8)
{
  rtx rt;
  rt = rtx_alloc (code);

  PUT_MODE (rt, mode);
  XINT (rt, 0) = arg0;
  XEXP (rt, 1) = arg1;
  XEXP (rt, 2) = arg2;
  XBBDEF (rt, 3) = arg3;
  XINT (rt, 4) = arg4;
  XEXP (rt, 5) = arg5;
  XINT (rt, 6) = arg6;
  XEXP (rt, 7) = arg7;
  XEXP (rt, 8) = arg8;

  return rt;
}
rtx
gen_rtx_fmt_iuuBieie0_stat (RTX_CODE code, enum machine_mode mode,
	int arg0,
	rtx arg1,
	rtx arg2,
	struct basic_block_def *arg3,
	int arg4,
	rtx arg5,
	int arg6,
	rtx arg7 MEM_STAT_DECL)
{
  rtx rt;
  rt = rtx_alloc_stat (code PASS_MEM_STAT);

  PUT_MODE (rt, mode);
  XINT (rt, 0) = arg0;
  XEXP (rt, 1) = arg1;
  XEXP (rt, 2) = arg2;
  XBBDEF (rt, 3) = arg3;
  XINT (rt, 4) = arg4;
  XEXP (rt, 5) = arg5;
  XINT (rt, 6) = arg6;
  XEXP (rt, 7) = arg7;
  X0EXP (rt, 8) = NULL_RTX;

  return rt;
}
Example #5
0
rtx
gen_rtx_fmt_ (RTX_CODE code, enum machine_mode mode)
{
  rtx rt;
  rt = rtx_alloc (code);

  PUT_MODE (rt, mode);

  return rt;
}
Example #6
0
rtx
gen_rtx_fmt_0 (RTX_CODE code, enum machine_mode mode)
{
  rtx rt;
  rt = rtx_alloc (code);

  PUT_MODE (rt, mode);
  X0EXP (rt, 0) = NULL_RTX;

  return rt;
}
rtx
gen_rtx_fmt_e_stat (RTX_CODE code, enum machine_mode mode,
	rtx arg0 MEM_STAT_DECL)
{
  rtx rt;
  rt = rtx_alloc_stat (code PASS_MEM_STAT);

  PUT_MODE (rt, mode);
  XEXP (rt, 0) = arg0;

  return rt;
}
Example #8
0
rtx
gen_rtx_fmt_e (RTX_CODE code, enum machine_mode mode,
	rtx arg0)
{
  rtx rt;
  rt = rtx_alloc (code);

  PUT_MODE (rt, mode);
  XEXP (rt, 0) = arg0;

  return rt;
}
Example #9
0
rtx
gen_rtx_fmt_s (RTX_CODE code, enum machine_mode mode,
	const char *arg0)
{
  rtx rt;
  rt = rtx_alloc (code);

  PUT_MODE (rt, mode);
  XSTR (rt, 0) = arg0;

  return rt;
}
Example #10
0
rtx
gen_rtx_fmt_w (RTX_CODE code, enum machine_mode mode,
	HOST_WIDE_INT arg0)
{
  rtx rt;
  rt = rtx_alloc (code);

  PUT_MODE (rt, mode);
  XWINT (rt, 0) = arg0;

  return rt;
}
Example #11
0
rtx
gen_rtx_fmt_i (RTX_CODE code, enum machine_mode mode,
	int arg0)
{
  rtx rt;
  rt = rtx_alloc (code);

  PUT_MODE (rt, mode);
  XINT (rt, 0) = arg0;

  return rt;
}
Example #12
0
rtx
gen_rtx_fmt_ei (RTX_CODE code, enum machine_mode mode,
	rtx arg0,
	int arg1)
{
  rtx rt;
  rt = rtx_alloc (code);

  PUT_MODE (rt, mode);
  XEXP (rt, 0) = arg0;
  XINT (rt, 1) = arg1;

  return rt;
}
Example #13
0
rtx
gen_rtx_fmt_i00 (RTX_CODE code, enum machine_mode mode,
	int arg0)
{
  rtx rt;
  rt = rtx_alloc (code);

  PUT_MODE (rt, mode);
  XINT (rt, 0) = arg0;
  X0EXP (rt, 1) = NULL_RTX;
  X0EXP (rt, 2) = NULL_RTX;

  return rt;
}
Example #14
0
rtx
gen_rtx_fmt_sE (RTX_CODE code, enum machine_mode mode,
	const char *arg0,
	rtvec arg1)
{
  rtx rt;
  rt = rtx_alloc (code);

  PUT_MODE (rt, mode);
  XSTR (rt, 0) = arg0;
  XVEC (rt, 1) = arg1;

  return rt;
}
Example #15
0
rtx
gen_rtx_fmt_is (RTX_CODE code, enum machine_mode mode,
	int arg0,
	const char *arg1)
{
  rtx rt;
  rt = rtx_alloc (code);

  PUT_MODE (rt, mode);
  XINT (rt, 0) = arg0;
  XSTR (rt, 1) = arg1;

  return rt;
}
Example #16
0
rtx
gen_rtx_fmt_te (RTX_CODE code, enum machine_mode mode,
	union tree_node *arg0,
	rtx arg1)
{
  rtx rt;
  rt = rtx_alloc (code);

  PUT_MODE (rt, mode);
  XTREE (rt, 0) = arg0;
  XEXP (rt, 1) = arg1;

  return rt;
}
Example #17
0
rtx
gen_rtx_fmt_Ee (RTX_CODE code, enum machine_mode mode,
	rtvec arg0,
	rtx arg1)
{
  rtx rt;
  rt = rtx_alloc (code);

  PUT_MODE (rt, mode);
  XVEC (rt, 0) = arg0;
  XEXP (rt, 1) = arg1;

  return rt;
}
Example #18
0
rtx
gen_rtx_fmt_s00 (RTX_CODE code, enum machine_mode mode,
	const char *arg0)
{
  rtx rt;
  rt = rtx_alloc (code);

  PUT_MODE (rt, mode);
  XSTR (rt, 0) = arg0;
  X0EXP (rt, 1) = NULL_RTX;
  X0EXP (rt, 2) = NULL_RTX;

  return rt;
}
Example #19
0
rtx
gen_rtx_fmt_sse (RTX_CODE code, enum machine_mode mode,
	const char *arg0,
	const char *arg1,
	rtx arg2)
{
  rtx rt;
  rt = rtx_alloc (code);

  PUT_MODE (rt, mode);
  XSTR (rt, 0) = arg0;
  XSTR (rt, 1) = arg1;
  XEXP (rt, 2) = arg2;

  return rt;
}
Example #20
0
rtx
gen_rtx_fmt_sies (RTX_CODE code, enum machine_mode mode,
	const char *arg0,
	int arg1,
	rtx arg2,
	const char *arg3)
{
  rtx rt;
  rt = rtx_alloc (code);

  PUT_MODE (rt, mode);
  XSTR (rt, 0) = arg0;
  XINT (rt, 1) = arg1;
  XEXP (rt, 2) = arg2;
  XSTR (rt, 3) = arg3;

  return rt;
}
Example #21
0
rtx
gen_rtx_fmt_eEee0 (RTX_CODE code, enum machine_mode mode,
	rtx arg0,
	rtvec arg1,
	rtx arg2,
	rtx arg3)
{
  rtx rt;
  rt = rtx_alloc (code);

  PUT_MODE (rt, mode);
  XEXP (rt, 0) = arg0;
  XVEC (rt, 1) = arg1;
  XEXP (rt, 2) = arg2;
  XEXP (rt, 3) = arg3;
  X0EXP (rt, 4) = NULL_RTX;

  return rt;
}
rtx
gen_rtx_fmt_iuu00000_stat (RTX_CODE code, enum machine_mode mode,
	int arg0,
	rtx arg1,
	rtx arg2 MEM_STAT_DECL)
{
  rtx rt;
  rt = rtx_alloc_stat (code PASS_MEM_STAT);

  PUT_MODE (rt, mode);
  XINT (rt, 0) = arg0;
  XEXP (rt, 1) = arg1;
  XEXP (rt, 2) = arg2;
  X0EXP (rt, 3) = NULL_RTX;
  X0EXP (rt, 4) = NULL_RTX;
  X0EXP (rt, 5) = NULL_RTX;
  X0EXP (rt, 6) = NULL_RTX;
  X0EXP (rt, 7) = NULL_RTX;

  return rt;
}
Example #23
0
static void
expand_STORE_LANES (gimple stmt)
{
  struct expand_operand ops[2];
  tree type, lhs, rhs;
  rtx target, reg;

  lhs = gimple_call_lhs (stmt);
  rhs = gimple_call_arg (stmt, 0);
  type = TREE_TYPE (rhs);

  target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
  reg = expand_normal (rhs);

  gcc_assert (MEM_P (target));
  PUT_MODE (target, TYPE_MODE (type));

  create_fixed_operand (&ops[0], target);
  create_input_operand (&ops[1], reg, TYPE_MODE (type));
  expand_insn (get_multi_vector_move (type, vec_store_lanes_optab), 2, ops);
}
Example #24
0
int
c54x_expand_movqi(rtx ops[])
{
	int done = 0;
	int i;

	fprintf(stderr, "--->>>");
	for(i=0; i < 2; i++) {
		print_rtl(stderr, ops[i]);
	}
	fprintf(stderr, "<<<---\n");

	
	if(ACC_REG_P(ops[0])) {
		ops[0] = copy_rtx(ops[0]);
		PUT_MODE(ops[0], PSImode);
		fprintf(stderr, "+++");
		print_rtl(stderr, ops[0]);
		fprintf(stderr, "+++\n");

		done = 1;

		if(MEM_P(ops[1])) {
			emit_insn(gen_ldm(ops[0], ops[1]));
		} else if(REG_P(ops[1])) {
			emit_insn(gen_ldu(ops[0], ops[1]));
		} else if(CONSTANT_P(ops[1])) {
			emit_insn(gen_ld_const(ops[0], ops[1], gen_reg_rtx(QImode)));
		} else {
			done = 2;
		}

	} else if( (REG_P(ops[0]) && (GET_CODE(ops[1]) == MEM && REG_P(XEXP(ops[1],0))))
			   || (T_REG_P(ops[0]) && ARSP_REG_P(ops[1])) )
	{
		done = 2;
	}
	
	return done;
}
Example #25
0
rtx
gen_rtx_fmt_iuu000000 (RTX_CODE code, enum machine_mode mode,
	int arg0,
	rtx arg1,
	rtx arg2)
{
  rtx rt;
  rt = rtx_alloc (code);

  PUT_MODE (rt, mode);
  XINT (rt, 0) = arg0;
  XEXP (rt, 1) = arg1;
  XEXP (rt, 2) = arg2;
  X0EXP (rt, 3) = NULL_RTX;
  X0EXP (rt, 4) = NULL_RTX;
  X0EXP (rt, 5) = NULL_RTX;
  X0EXP (rt, 6) = NULL_RTX;
  X0EXP (rt, 7) = NULL_RTX;
  X0EXP (rt, 8) = NULL_RTX;

  return rt;
}
Example #26
0
rtx
gen_rtx_fmt_iuuB00is (RTX_CODE code, enum machine_mode mode,
	int arg0,
	rtx arg1,
	rtx arg2,
	struct basic_block_def *arg3,
	int arg4,
	const char *arg5)
{
  rtx rt;
  rt = rtx_alloc (code);

  PUT_MODE (rt, mode);
  XINT (rt, 0) = arg0;
  XEXP (rt, 1) = arg1;
  XEXP (rt, 2) = arg2;
  XBBDEF (rt, 3) = arg3;
  X0EXP (rt, 4) = NULL_RTX;
  X0EXP (rt, 5) = NULL_RTX;
  XINT (rt, 6) = arg4;
  XSTR (rt, 7) = arg5;

  return rt;
}
Example #27
0
rtx
gen_rtx_fmt_ssiEEsi (RTX_CODE code, enum machine_mode mode,
	const char *arg0,
	const char *arg1,
	int arg2,
	rtvec arg3,
	rtvec arg4,
	const char *arg5,
	int arg6)
{
  rtx rt;
  rt = rtx_alloc (code);

  PUT_MODE (rt, mode);
  XSTR (rt, 0) = arg0;
  XSTR (rt, 1) = arg1;
  XINT (rt, 2) = arg2;
  XVEC (rt, 3) = arg3;
  XVEC (rt, 4) = arg4;
  XSTR (rt, 5) = arg5;
  XINT (rt, 6) = arg6;

  return rt;
}
Example #28
0
static void
finish_handler_array ()
{
  tree decl = current_handler->handler_array_decl;
  tree t;
  tree handler_array_init = NULL_TREE;
  int handlers_count = 1;
  int nelts;

  /* Build the table mapping exceptions to handler(-number)s.
     This is done in reverse order. */
  
  /* First push the end of the list.  This is either the ELSE
     handler (current_handler->else_handler>0) or NULL handler to indicate
     the end of the list (if current_handler->else-handler == 0).
     The following works either way. */
  handler_array_init = build_tree_list
    (NULL_TREE, chill_expand_tuple
     (handler_element_type,
      build_nt (CONSTRUCTOR, NULL_TREE,
		tree_cons (NULL_TREE,
			   null_pointer_node,
			   build_tree_list (NULL_TREE,
					    build_int_2 (current_handler->else_handler,
							     0))))));
  
  for (t = current_handler->on_alt_list; t != NULL_TREE; t = TREE_CHAIN (t))
    { tree handler_number = TREE_PURPOSE(t);
      tree elist = TREE_VALUE (t);
      for ( ; elist != NULL_TREE; elist = TREE_CHAIN (elist))
	{
	  tree ex_decl =
	    build_chill_exception_decl (IDENTIFIER_POINTER(TREE_VALUE(elist)));
	  tree ex_addr = build1 (ADDR_EXPR,
				 char_pointer_type_for_handler,
				 ex_decl);
	  tree el = build_nt (CONSTRUCTOR, NULL_TREE,
			      tree_cons (NULL_TREE,
					 ex_addr,
					 build_tree_list (NULL_TREE,
							  handler_number)));
	  mark_addressable (ex_decl);
	  TREE_CONSTANT (ex_addr) = 1;
	  handler_array_init =
	    tree_cons (NULL_TREE,
		       chill_expand_tuple (handler_element_type, el),
		       handler_array_init);
	  handlers_count++;
	}
    }

#if 1
  nelts = list_length (handler_array_init);
  TYPE_DOMAIN (TREE_TYPE (decl))
    = build_index_type (build_int_2 (nelts - 1, - (nelts == 0)));
  layout_type (TREE_TYPE (decl));
  DECL_INITIAL (decl)
    = convert (TREE_TYPE (decl),
	       build_nt (CONSTRUCTOR, NULL_TREE, handler_array_init));

  /* Pop back to the obstack that is current for this binding level.
     This is because MAXINDEX, rtl, etc. to be made below
     must go in the permanent obstack.  But don't discard the
     temporary data yet.  */
  pop_obstacks ();
  layout_decl (decl, 0);
  /* To prevent make_decl_rtl (called indiectly by rest_of_decl_compilation)
     throwing the existing RTL (which has already been used). */
  PUT_MODE (DECL_RTL (decl), DECL_MODE (decl));
  rest_of_decl_compilation (decl, (char*)0, 0, 0);
  expand_decl_init (decl);
#else
  /* To prevent make_decl_rtl (called indirectly by finish_decl)
     altering the existing RTL. */
  GET_MODE (DECL_RTL (current_handler->handler_array_decl)) =
    DECL_MODE (current_handler->handler_array_decl);

  finish_decl (current_handler->handler_array_decl,
	       build_nt (CONSTRUCTOR, NULL_TREE, handler_array_init),
	       NULL_TREE);
#endif
}
Example #29
0
static bool
attempt_change (rtx new_addr, rtx inc_reg)
{
  /* There are four cases: For the two cases that involve an add
     instruction, we are going to have to delete the add and insert a
     mov.  We are going to assume that the mov is free.  This is
     fairly early in the backend and there are a lot of opportunities
     for removing that move later.  In particular, there is the case
     where the move may be dead, this is what dead code elimination
     passes are for.  The two cases where we have an inc insn will be
     handled mov free.  */

  basic_block bb = BLOCK_FOR_INSN (mem_insn.insn);
  rtx mov_insn = NULL;
  int regno;
  rtx mem = *mem_insn.mem_loc;
  enum machine_mode mode = GET_MODE (mem);
  rtx new_mem;
  int old_cost = 0;
  int new_cost = 0;
  bool speed = optimize_bb_for_speed_p (bb);

  PUT_MODE (mem_tmp, mode);
  XEXP (mem_tmp, 0) = new_addr;

  old_cost = (set_src_cost (mem, speed)
	      + set_rtx_cost (PATTERN (inc_insn.insn), speed));
  new_cost = set_src_cost (mem_tmp, speed);

  /* The first item of business is to see if this is profitable.  */
  if (old_cost < new_cost)
    {
      if (dump_file)
	fprintf (dump_file, "cost failure old=%d new=%d\n", old_cost, new_cost);
      return false;
    }

  /* Jump through a lot of hoops to keep the attributes up to date.  We
     do not want to call one of the change address variants that take
     an offset even though we know the offset in many cases.  These
     assume you are changing where the address is pointing by the
     offset.  */
  new_mem = replace_equiv_address_nv (mem, new_addr);
  if (! validate_change (mem_insn.insn, mem_insn.mem_loc, new_mem, 0))
    {
      if (dump_file)
	fprintf (dump_file, "validation failure\n");
      return false;
    }

  /* From here to the end of the function we are committed to the
     change, i.e. nothing fails.  Generate any necessary movs, move
     any regnotes, and fix up the reg_next_{use,inc_use,def}.  */
  switch (inc_insn.form)
    {
    case FORM_PRE_ADD:
      /* Replace the addition with a move.  Do it at the location of
	 the addition since the operand of the addition may change
	 before the memory reference.  */
      mov_insn = insert_move_insn_before (inc_insn.insn,
					  inc_insn.reg_res, inc_insn.reg0);
      move_dead_notes (mov_insn, inc_insn.insn, inc_insn.reg0);

      regno = REGNO (inc_insn.reg_res);
      reg_next_def[regno] = mov_insn;
      reg_next_use[regno] = NULL;
      regno = REGNO (inc_insn.reg0);
      reg_next_use[regno] = mov_insn;
      df_recompute_luids (bb);
      break;

    case FORM_POST_INC:
      regno = REGNO (inc_insn.reg_res);
      if (reg_next_use[regno] == reg_next_inc_use[regno])
	reg_next_inc_use[regno] = NULL;

      /* Fallthru.  */
    case FORM_PRE_INC:
      regno = REGNO (inc_insn.reg_res);
      reg_next_def[regno] = mem_insn.insn;
      reg_next_use[regno] = NULL;

      break;

    case FORM_POST_ADD:
      mov_insn = insert_move_insn_before (mem_insn.insn,
					  inc_insn.reg_res, inc_insn.reg0);
      move_dead_notes (mov_insn, inc_insn.insn, inc_insn.reg0);

      /* Do not move anything to the mov insn because the instruction
	 pointer for the main iteration has not yet hit that.  It is
	 still pointing to the mem insn. */
      regno = REGNO (inc_insn.reg_res);
      reg_next_def[regno] = mem_insn.insn;
      reg_next_use[regno] = NULL;

      regno = REGNO (inc_insn.reg0);
      reg_next_use[regno] = mem_insn.insn;
      if ((reg_next_use[regno] == reg_next_inc_use[regno])
	  || (reg_next_inc_use[regno] == inc_insn.insn))
	reg_next_inc_use[regno] = NULL;
      df_recompute_luids (bb);
      break;

    case FORM_last:
    default:
      gcc_unreachable ();
    }

  if (!inc_insn.reg1_is_const)
    {
      regno = REGNO (inc_insn.reg1);
      reg_next_use[regno] = mem_insn.insn;
      if ((reg_next_use[regno] == reg_next_inc_use[regno])
	  || (reg_next_inc_use[regno] == inc_insn.insn))
	reg_next_inc_use[regno] = NULL;
    }

  delete_insn (inc_insn.insn);

  if (dump_file && mov_insn)
    {
      fprintf (dump_file, "inserting mov ");
      dump_insn_slim (dump_file, mov_insn);
    }

  /* Record that this insn has an implicit side effect.  */
  add_reg_note (mem_insn.insn, REG_INC, inc_reg);

  if (dump_file)
    {
      fprintf (dump_file, "****success ");
      dump_insn_slim (dump_file, mem_insn.insn);
    }

  return true;
}
Example #30
0
static bool
doloop_optimize (struct loop *loop)
{
    enum machine_mode mode;
    rtx doloop_seq, doloop_pat, doloop_reg;
    rtx iterations, count;
    rtx iterations_max;
    rtx start_label;
    rtx condition;
    unsigned level, est_niter;
    struct niter_desc *desc;
    unsigned word_mode_size;
    unsigned HOST_WIDE_INT word_mode_max;

    if (dump_file)
        fprintf (dump_file, "Doloop: Processing loop %d.\n", loop->num);

    /* APPLE LOCAL begin lno */
    /* Ignore large loops.  */
    if (loop->ninsns > (unsigned) PARAM_VALUE (PARAM_MAX_DOLOOP_INSNS))
    {
        if (dump_file)
            fprintf (dump_file,
                     "Doloop: The loop is too large.\n");
        return false;
    }
    /* APPLE LOCAL end lno */

    iv_analysis_loop_init (loop);

    /* Find the simple exit of a LOOP.  */
    desc = get_simple_loop_desc (loop);

    /* Check that loop is a candidate for a low-overhead looping insn.  */
    if (!doloop_valid_p (loop, desc))
    {
        if (dump_file)
            fprintf (dump_file,
                     "Doloop: The loop is not suitable.\n");
        return false;
    }
    mode = desc->mode;

    est_niter = 3;
    if (desc->const_iter)
        est_niter = desc->niter;
    /* If the estimate on number of iterations is reliable (comes from profile
       feedback), use it.  Do not use it normally, since the expected number
       of iterations of an unrolled loop is 2.  */
    if (loop->header->count)
        est_niter = expected_loop_iterations (loop);

    if (est_niter < 3)
    {
        if (dump_file)
            fprintf (dump_file,
                     "Doloop: Too few iterations (%u) to be profitable.\n",
                     est_niter);
        return false;
    }

    count = copy_rtx (desc->niter_expr);
    iterations = desc->const_iter ? desc->niter_expr : const0_rtx;
    iterations_max = GEN_INT (desc->niter_max);
    level = get_loop_level (loop) + 1;

    /* Generate looping insn.  If the pattern FAILs then give up trying
       to modify the loop since there is some aspect the back-end does
       not like.  */
    start_label = block_label (desc->in_edge->dest);
    doloop_reg = gen_reg_rtx (mode);
    doloop_seq = gen_doloop_end (doloop_reg, iterations, iterations_max,
                                 GEN_INT (level), start_label);

    word_mode_size = GET_MODE_BITSIZE (word_mode);
    word_mode_max
        = ((unsigned HOST_WIDE_INT) 1 << (word_mode_size - 1) << 1) - 1;
    if (! doloop_seq
            && mode != word_mode
            /* Before trying mode different from the one in that # of iterations is
            computed, we must be sure that the number of iterations fits into
             the new mode.  */
            && (word_mode_size >= GET_MODE_BITSIZE (mode)
                || desc->niter_max <= word_mode_max))
    {
        if (word_mode_size > GET_MODE_BITSIZE (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);
        }
        else
        {
            count = lowpart_subreg (word_mode, count, mode);
            iterations = lowpart_subreg (word_mode, iterations, mode);
            iterations_max = lowpart_subreg (word_mode, iterations_max, mode);
        }
        PUT_MODE (doloop_reg, word_mode);
        doloop_seq = gen_doloop_end (doloop_reg, iterations, iterations_max,
                                     GEN_INT (level), start_label);
    }
    if (! doloop_seq)
    {
        if (dump_file)
            fprintf (dump_file,
                     "Doloop: Target unwilling to use doloop pattern!\n");
        return false;
    }

    /* If multiple instructions were created, the last must be the
       jump instruction.  Also, a raw define_insn may yield a plain
       pattern.  */
    doloop_pat = doloop_seq;
    if (INSN_P (doloop_pat))
    {
        while (NEXT_INSN (doloop_pat) != NULL_RTX)
            doloop_pat = NEXT_INSN (doloop_pat);
        if (JUMP_P (doloop_pat))
            doloop_pat = PATTERN (doloop_pat);
        else
            doloop_pat = NULL_RTX;
    }

    if (! doloop_pat
            || ! (condition = doloop_condition_get (doloop_pat)))
    {
        if (dump_file)
            fprintf (dump_file, "Doloop: Unrecognizable doloop pattern!\n");
        return false;
    }

    doloop_modify (loop, desc, doloop_seq, condition, count);
    return true;
}