This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[lno] Use new iv analysis in unroller


Hello,

this patch makes use of the new iv analysis code in unroller and branch
prediction.  I have verified that the code is strictly better (i.e.
detects superset of loops as simple) during the c bootstrap on i686.
I leave the old code still in place, since similar verification needs
to be done on other platforms once handling of subregs is added.

Bootstrapped & regtested on i686 with -funroll-loops -floop-optimize2.

Zdenek

Index: ChangeLog.lno
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/ChangeLog.lno,v
retrieving revision 1.1.2.42
diff -c -3 -p -r1.1.2.42 ChangeLog.lno
*** ChangeLog.lno	29 Jan 2004 21:56:48 -0000	1.1.2.42
--- ChangeLog.lno	30 Jan 2004 01:31:20 -0000
***************
*** 1,5 ****
--- 1,44 ----
  2004-01-29  Zdenek Dvorak  <rakdver@atrey.karlin.mff.cuni.cz>
  
+ 	* basic-block.h (FOR_BB_INSNS, FOR_BB_INSNS_REVERSE): New macros.
+ 	* cfgloop.c (num_loop_branches): New function.
+ 	* cfgloop.h (struct loop_desc): Add field strange.
+ 	(struct loop): Remove fields simple, desc, has_desc.
+ 	(num_loop_branches, get_simple_loop_desc, free_simple_loop_desc):
+ 	Declare.
+ 	(simple_loop_desc): New inline function.
+ 	* cfgloopanal.c (count_loop_iterations): Set field strange.
+ 	(simple_loop_exit_p): Initialize postincr properly.
+ 	* loop-iv.c (assign_luids, mark_sets, simplify_using_initial_values):
+ 	Use FOR_BB_INSNS/FOR_BB_INSNS_REVERSE.
+ 	(iv_number_of_iterations): Restrict the number of iterations to the
+ 	actual mode.
+ 	(find_simple_exit): Check results with the old simple loop analyser.
+ 	(get_simple_loop_desc, free_simple_loop_desc): New functions.
+ 	* loop-unroll.c (loop_exit_at_end_p): New function.
+ 	(unroll_and_peel_loops, peel_loops_completely,
+ 	decide_unrolling_and_peeling, decide_peel_once_rolling,
+ 	decide_peel_completely, peel_loop_completely,
+ 	decide_unroll_constant_iterations, unroll_loop_constant_iterations,
+ 	decide_unroll_runtime_iterations, unroll_loop_runtime_iterations,
+ 	decide_peel_simple, decide_unroll_stupid): Use new iv analysis.
+ 	* predict.c (predict_loops): Use new iv analysis.
+ 
+ 	* tree-ssa-loop.c (copy_loop_headers): Predict entry edge from
+ 	copied loop header to be taken.
+ 
+ 	* tree-cfg.c (tree_find_edge_insert_loc,
+ 	bsi_insert_on_edge_immediate): Return the newly created block.
+ 	(bsi_commit_edge_inserts_1): Add parameter to
+ 	tree_find_edge_insert_loc call.
+ 	* tree-flow.h (bsi_insert_on_edge_immediate): Declaration changed.
+ 	* tree-ssa-loop-ivopts.c (create_new_iv): Update loop for newly
+ 	created block.
+ 
+ 	* cfg.c (unlink_block): Clean prev_bb and next_bb fields.
+ 
+ 2004-01-29  Zdenek Dvorak  <rakdver@atrey.karlin.mff.cuni.cz>
+ 
  	* tree-scalar-evolution.c (scev_analyze_inner_loop_phi): Add ;.
  
  2004-01-29  Sebastian Pop  <sebastian.pop@ensmp.fr>
Index: basic-block.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/basic-block.h,v
retrieving revision 1.153.2.39.2.3
diff -c -3 -p -r1.153.2.39.2.3 basic-block.h
*** basic-block.h	22 Jan 2004 01:10:45 -0000	1.153.2.39.2.3
--- basic-block.h	30 Jan 2004 01:31:20 -0000
*************** extern varray_type basic_block_info;
*** 331,336 ****
--- 331,347 ----
  #define FOR_EACH_BB_REVERSE(BB) \
    FOR_BB_BETWEEN (BB, EXIT_BLOCK_PTR->prev_bb, ENTRY_BLOCK_PTR, prev_bb)
  
+ /* For iterating over insns in basic block.  */
+ #define FOR_BB_INSNS(BB, INSN)			\
+   for ((INSN) = BB_HEAD (BB);			\
+        (INSN) != NEXT_INSN (BB_END (BB));	\
+        (INSN) = NEXT_INSN (INSN))
+ 
+ #define FOR_BB_INSNS_REVERSE(BB, INSN)		\
+   for ((INSN) = BB_END (BB);			\
+        (INSN) != PREV_INSN (BB_HEAD (BB));	\
+        (INSN) = PREV_INSN (INSN))
+ 
  /* Cycles through _all_ basic blocks, even the fake ones (entry and
     exit block).  */
  
Index: cfg.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cfg.c,v
retrieving revision 1.34.2.19.2.2
diff -c -3 -p -r1.34.2.19.2.2 cfg.c
*** cfg.c	21 Jan 2004 09:24:58 -0000	1.34.2.19.2.2
--- cfg.c	30 Jan 2004 01:31:20 -0000
*************** unlink_block (basic_block b)
*** 229,234 ****
--- 229,236 ----
  {
    b->next_bb->prev_bb = b->prev_bb;
    b->prev_bb->next_bb = b->next_bb;
+   b->prev_bb = NULL;
+   b->next_bb = NULL;
  }
  
  /* Sequentially order blocks and compact the arrays.  */
Index: cfgloop.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cfgloop.c,v
retrieving revision 1.14.2.12.2.1
diff -c -3 -p -r1.14.2.12.2.1 cfgloop.c
*** cfgloop.c	3 Jan 2004 20:25:25 -0000	1.14.2.12.2.1
--- cfgloop.c	30 Jan 2004 01:31:20 -0000
*************** get_loop_exit_edges (const struct loop *
*** 1061,1066 ****
--- 1061,1087 ----
    return edges;
  }
  
+ /* Counts the number of conditional branches inside LOOP.  */
+ 
+ unsigned
+ num_loop_branches (const struct loop *loop)
+ {
+   unsigned i, n;
+   basic_block * body;
+ 
+   if (loop->latch == EXIT_BLOCK_PTR)
+     abort ();
+ 
+   body = get_loop_body (loop);
+   n = 0;
+   for (i = 0; i < loop->num_nodes; i++)
+     if (body[i]->succ && body[i]->succ->succ_next)
+       n++;
+   free (body);
+ 
+   return n;
+ }
+ 
  /* Adds basic block BB to LOOP.  */
  void
  add_bb_to_loop (basic_block bb, struct loop *loop)
Index: cfgloop.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cfgloop.h,v
retrieving revision 1.2.4.9.2.7
diff -c -3 -p -r1.2.4.9.2.7 cfgloop.h
*** cfgloop.h	29 Jan 2004 18:36:31 -0000	1.2.4.9.2.7
--- cfgloop.h	30 Jan 2004 01:31:20 -0000
*************** struct lpt_decision
*** 39,44 ****
--- 39,45 ----
  /* Description of loop for simple loop unrolling.  */
  struct loop_desc
  {
+   bool strange;
    int postincr;		/* 1 if increment/decrement is done after loop exit condition.  */
    rtx stride;		/* Value added to VAR in each iteration.  */
    rtx var;		/* Loop control variable.  */
*************** struct loop
*** 77,87 ****
    /* For loop unrolling/peeling decision.  */
    struct lpt_decision lpt_decision;
  
-   /* Simple loop description.  */
-   int simple;
-   struct loop_desc desc;
-   int has_desc;
- 
    /* Number of loop insns.  */
    unsigned ninsns;
  
--- 78,83 ----
*************** extern unsigned get_loop_level (const st
*** 289,294 ****
--- 285,291 ----
  extern basic_block *get_loop_body (const struct loop *);
  extern basic_block *get_loop_body_in_dom_order (const struct loop *);
  extern edge *get_loop_exit_edges (const struct loop *, unsigned *);
+ extern unsigned num_loop_branches (const struct loop *);
  
  extern edge loop_preheader_edge (const struct loop *);
  extern edge loop_latch_edge (const struct loop *);
*************** extern void find_simple_exit (struct loo
*** 394,399 ****
--- 391,405 ----
  extern void iv_number_of_iterations (struct loop *, rtx, rtx,
  				     struct niter_desc *);
  extern void iv_analysis_done (void);
+ 
+ extern struct niter_desc *get_simple_loop_desc (struct loop *loop);
+ extern void free_simple_loop_desc (struct loop *loop);
+ 
+ static inline struct niter_desc *
+ simple_loop_desc (struct loop *loop)
+ {
+   return loop->aux;
+ }
  
  /* Loop optimizer initialization.  */
  extern struct loops *loop_optimizer_init (FILE *);
Index: cfgloopanal.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cfgloopanal.c,v
retrieving revision 1.2.4.9.2.4
diff -c -3 -p -r1.2.4.9.2.4 cfgloopanal.c
*** cfgloopanal.c	28 Jan 2004 21:07:33 -0000	1.2.4.9.2.4
--- cfgloopanal.c	30 Jan 2004 01:31:21 -0000
*************** count_loop_iterations (struct loop_desc 
*** 724,729 ****
--- 724,731 ----
    if (!INTEGRAL_MODE_P (mode))
      return NULL;
  
+   desc->strange = false;
+ 
    init = copy_rtx (init ? init : desc->var);
    lim = copy_rtx (lim ? lim : desc->lim);
  
*************** count_loop_iterations (struct loop_desc 
*** 813,828 ****
        /* Handle strange tests specially.  */
        if (cond == EQ || cond == GE || cond == GT || cond == GEU
  	  || cond == GTU)
! 	return count_strange_loop_iterations (init, lim, cond, desc->postincr,
! 					      stride, mode, desc->inner_mode);
        exp = simplify_gen_binary (MINUS, mode, lim, init);
      }
    else
      {
        if (cond == EQ || cond == LE || cond == LT || cond == LEU
  	  || cond == LTU)
! 	return count_strange_loop_iterations (init, lim, cond, desc->postincr,
! 					      stride, mode, desc->inner_mode);
        exp = simplify_gen_binary (MINUS, mode, init, lim);
        stride = simplify_gen_unary (NEG, mode, stride, mode);
      }
--- 815,836 ----
        /* Handle strange tests specially.  */
        if (cond == EQ || cond == GE || cond == GT || cond == GEU
  	  || cond == GTU)
! 	{
! 	  desc->strange = true;
! 	  return count_strange_loop_iterations (init, lim, cond, desc->postincr,
! 						stride, mode, desc->inner_mode);
! 	}
        exp = simplify_gen_binary (MINUS, mode, lim, init);
      }
    else
      {
        if (cond == EQ || cond == LE || cond == LT || cond == LEU
  	  || cond == LTU)
! 	{
! 	  desc->strange = true;
! 	  return count_strange_loop_iterations (init, lim, cond, desc->postincr,
! 						stride, mode, desc->inner_mode);
! 	}
        exp = simplify_gen_binary (MINUS, mode, init, lim);
        stride = simplify_gen_unary (NEG, mode, stride, mode);
      }
*************** simple_loop_exit_p (struct loop *loop, e
*** 967,973 ****
  {
    basic_block mod_bb, exit_bb;
    int fallthru_out;
!   rtx condition;
    edge ei, e;
  
    exit_bb = exit_edge->src;
--- 975,981 ----
  {
    basic_block mod_bb, exit_bb;
    int fallthru_out;
!   rtx condition, at, insn;
    edge ei, e;
  
    exit_bb = exit_edge->src;
*************** simple_loop_exit_p (struct loop *loop, e
*** 994,1000 ****
  
    /* Condition must be a simple comparison in that one of operands
       is register and the other one is invariant.  */
!   if (!(condition = get_condition (BB_END (exit_bb), NULL, false)))
      return false;
  
    if (!simple_condition_p (loop, condition, invariant_regs, desc))
--- 1002,1008 ----
  
    /* Condition must be a simple comparison in that one of operands
       is register and the other one is invariant.  */
!   if (!(condition = get_condition (BB_END (exit_bb), &at, false)))
      return false;
  
    if (!simple_condition_p (loop, condition, invariant_regs, desc))
*************** simple_loop_exit_p (struct loop *loop, e
*** 1006,1012 ****
      return false;
  
    /* OK, it is simple loop.  Now just fill in remaining info.  */
!   desc->postincr = !dominated_by_p (CDI_DOMINATORS, exit_bb, mod_bb);
    desc->neg = !fallthru_out;
  
    /* Find initial value of var and alternative values for lim.  */
--- 1014,1037 ----
      return false;
  
    /* OK, it is simple loop.  Now just fill in remaining info.  */
!   if (exit_bb == mod_bb)
!     {
!       /* It might be that we are incremented in the middle of the
! 	 condition.  */
! 
!       insn = single_set_regs[REGNO (desc->var)];
!       desc->postincr = true;
!       for (; insn != NEXT_INSN (BB_END (mod_bb)); insn = NEXT_INSN (insn))
! 	if (insn == at)
! 	  {
! 	    desc->postincr = false;
! 	    break;
! 	  }
!     }
!   else
!     {
!       desc->postincr = !dominated_by_p (CDI_DOMINATORS, exit_bb, mod_bb);
!     }
    desc->neg = !fallthru_out;
  
    /* Find initial value of var and alternative values for lim.  */
Index: loop-iv.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/loop-iv.c,v
retrieving revision 1.1.4.2
diff -c -3 -p -r1.1.4.2 loop-iv.c
*** loop-iv.c	29 Jan 2004 16:03:42 -0000	1.1.4.2
--- loop-iv.c	30 Jan 2004 01:31:21 -0000
*************** dump_iv_info (FILE *file, struct rtx_iv 
*** 122,136 ****
  static void
  assign_luids (basic_block bb)
  {
!   unsigned i, uid;
    rtx insn;
  
!   for (i = 0, insn = BB_HEAD (bb);
!        insn != NEXT_INSN (BB_END (bb));
!        insn = NEXT_INSN (insn), i++)
      {
        uid = INSN_UID (insn);
!       insn_info[uid].luid = i;
        insn_info[uid].prev_def = NULL_RTX;
        insn_info[uid].iv.analysed = false;
      }
--- 122,134 ----
  static void
  assign_luids (basic_block bb)
  {
!   unsigned i = 0, uid;
    rtx insn;
  
!   FOR_BB_INSNS (bb, insn)
      {
        uid = INSN_UID (insn);
!       insn_info[uid].luid = i++;
        insn_info[uid].prev_def = NULL_RTX;
        insn_info[uid].iv.analysed = false;
      }
*************** mark_sets (basic_block bb, bool dom)
*** 254,262 ****
  {
    rtx insn, set, def;
  
!   for (insn = BB_HEAD (bb);
!        insn != NEXT_INSN (BB_END (bb));
!        insn = NEXT_INSN (insn))
      {
        if (!INSN_P (insn))
  	continue;
--- 252,258 ----
  {
    rtx insn, set, def;
  
!   FOR_BB_INSNS (bb, insn)
      {
        if (!INSN_P (insn))
  	continue;
*************** simplify_using_initial_values (struct lo
*** 1210,1216 ****
  	    }
  	}
  
!       for (; insn != PREV_INSN (BB_HEAD (e->src)); insn = PREV_INSN (insn))
  	{
  	  if (!INSN_P (insn))
  	    continue;
--- 1206,1212 ----
  	    }
  	}
  
!       FOR_BB_INSNS_REVERSE (e->src, insn)
  	{
  	  if (!INSN_P (insn))
  	    continue;
*************** iv_number_of_iterations (struct loop *lo
*** 1619,1626 ****
  
    if (GET_CODE (desc->niter_expr) == CONST_INT)
      {
        desc->const_iter = true;
!       desc->niter_max = desc->niter = INTVAL (desc->niter_expr);
      }
    else if (!desc->niter_max)
      desc->niter_max = determine_max_iter (desc);
--- 1615,1624 ----
  
    if (GET_CODE (desc->niter_expr) == CONST_INT)
      {
+       unsigned HOST_WIDEST_INT val = INTVAL (desc->niter_expr);
+ 
        desc->const_iter = true;
!       desc->niter_max = desc->niter = val & GET_MODE_MASK (desc->mode);
      }
    else if (!desc->niter_max)
      desc->niter_max = determine_max_iter (desc);
*************** find_simple_exit (struct loop *loop, str
*** 1723,1728 ****
--- 1721,1747 ----
  	}
      }
  
+ #if 0
+     {
+       /* Check that we do not lose wrto older version.  */
+       struct loop_desc odesc;
+       if (simple_loop_p (loop, &odesc) && !odesc.strange)
+ 	{
+ 	  if (!desc->simple_p)
+ 	    abort ();
+ 
+ 	  if (odesc.const_iter)
+ 	    {
+ 	      if (!desc->const_iter)
+ 		abort ();
+ 
+ 	      if (desc->niter != odesc.niter)
+ 		abort ();
+ 	    }
+ 	}
+     }
+ #endif
+ 
    if (rtl_dump_file)
      {
        if (desc->simple_p)
*************** find_simple_exit (struct loop *loop, str
*** 1763,1766 ****
--- 1782,1818 ----
      }
  
    free (body);
+ }
+ 
+ /* Creates a simple loop description of LOOP if it was not computed
+    already.  */
+ 
+ struct niter_desc *
+ get_simple_loop_desc (struct loop *loop)
+ {
+   struct niter_desc *desc = simple_loop_desc (loop);
+ 
+   if (desc)
+     return desc;
+ 
+   desc = xmalloc (sizeof (struct niter_desc));
+   iv_analysis_loop_init (loop);
+   find_simple_exit (loop, desc);
+   loop->aux = desc;
+ 
+   return desc;
+ }
+ 
+ /* Releases simple loop description for LOOP.  */
+ 
+ void
+ free_simple_loop_desc (struct loop *loop)
+ {
+   struct niter_desc *desc = simple_loop_desc (loop);
+ 
+   if (!desc)
+     return;
+ 
+   free (desc);
+   loop->aux = NULL;
  }
Index: loop-unroll.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/loop-unroll.c,v
retrieving revision 1.2.2.6.2.1
diff -c -3 -p -r1.2.2.6.2.1 loop-unroll.c
*** loop-unroll.c	29 Jan 2004 16:03:42 -0000	1.2.2.6.2.1
--- loop-unroll.c	30 Jan 2004 01:31:21 -0000
*************** void
*** 85,91 ****
  unroll_and_peel_loops (struct loops *loops, int flags)
  {
    struct loop *loop, *next;
!   int check;
  
    /* First perform complete loop peeling (it is almost surely a win,
       and affects parameters for further decision a lot).  */
--- 85,92 ----
  unroll_and_peel_loops (struct loops *loops, int flags)
  {
    struct loop *loop, *next;
!   bool check;
!   unsigned i;
  
    /* First perform complete loop peeling (it is almost surely a win,
       and affects parameters for further decision a lot).  */
*************** unroll_and_peel_loops (struct loops *loo
*** 110,116 ****
        else
  	next = loop->outer;
  
!       check = 1;
        /* And perform the appropriate transformations.  */
        switch (loop->lpt_decision.decision)
  	{
--- 111,117 ----
        else
  	next = loop->outer;
  
!       check = true;
        /* And perform the appropriate transformations.  */
        switch (loop->lpt_decision.decision)
  	{
*************** unroll_and_peel_loops (struct loops *loo
*** 130,136 ****
  	  unroll_loop_stupid (loops, loop);
  	  break;
  	case LPT_NONE:
! 	  check = 0;
  	  break;
  	default:
  	  abort ();
--- 131,137 ----
  	  unroll_loop_stupid (loops, loop);
  	  break;
  	case LPT_NONE:
! 	  check = false;
  	  break;
  	default:
  	  abort ();
*************** unroll_and_peel_loops (struct loops *loo
*** 144,149 ****
--- 145,177 ----
  	}
        loop = next;
      }
+ 
+   for (i = 1; i < loops->num; i++)
+     if (loops->parray[i])
+       free_simple_loop_desc (loops->parray[i]);
+ 
+   iv_analysis_done ();
+ }
+ 
+ /* Check whether exit of the LOOP is at the end of loop body.  */
+ 
+ static bool
+ loop_exit_at_end_p (struct loop *loop)
+ {
+   struct niter_desc *desc = simple_loop_desc (loop);
+   rtx insn;
+ 
+   if (desc->in_edge->dest != loop->latch)
+     return false;
+ 
+   /* Check that the latch is empty.  */
+   FOR_BB_INSNS (loop->latch, insn)
+     {
+       if (INSN_P (insn))
+ 	return false;
+     }
+ 
+   return true;
  }
  
  /* Check whether to peel LOOPS (depending on FLAGS) completely and do so.  */
*************** peel_loops_completely (struct loops *loo
*** 168,177 ****
  	next = loop->outer;
  
        loop->lpt_decision.decision = LPT_NONE;
-       loop->has_desc = 0;
  
        if (rtl_dump_file)
! 	fprintf (rtl_dump_file, ";; Considering loop %d for complete peeling\n",
  		 loop->num);
  
        loop->ninsns = num_loop_insns (loop);
--- 196,204 ----
  	next = loop->outer;
  
        loop->lpt_decision.decision = LPT_NONE;
  
        if (rtl_dump_file)
! 	fprintf (rtl_dump_file, "\n;; *** Considering loop %d for complete peeling ***\n",
  		 loop->num);
  
        loop->ninsns = num_loop_insns (loop);
*************** decide_unrolling_and_peeling (struct loo
*** 216,222 ****
        loop->lpt_decision.decision = LPT_NONE;
  
        if (rtl_dump_file)
! 	fprintf (rtl_dump_file, ";; Considering loop %d\n", loop->num);
  
        /* Do not peel cold areas.  */
        if (!maybe_hot_bb_p (loop->header))
--- 243,249 ----
        loop->lpt_decision.decision = LPT_NONE;
  
        if (rtl_dump_file)
! 	fprintf (rtl_dump_file, "\n;; *** Considering loop %d ***\n", loop->num);
  
        /* Do not peel cold areas.  */
        if (!maybe_hot_bb_p (loop->header))
*************** decide_unrolling_and_peeling (struct loo
*** 269,276 ****
  static void
  decide_peel_once_rolling (struct loop *loop, int flags ATTRIBUTE_UNUSED)
  {
    if (rtl_dump_file)
!     fprintf (rtl_dump_file, ";; Considering peeling once rolling loop\n");
  
    /* Is the loop small enough?  */
    if ((unsigned) PARAM_VALUE (PARAM_MAX_ONCE_PEELED_INSNS) < loop->ninsns)
--- 296,305 ----
  static void
  decide_peel_once_rolling (struct loop *loop, int flags ATTRIBUTE_UNUSED)
  {
+   struct niter_desc *desc;
+ 
    if (rtl_dump_file)
!     fprintf (rtl_dump_file, "\n;; Considering peeling once rolling loop\n");
  
    /* Is the loop small enough?  */
    if ((unsigned) PARAM_VALUE (PARAM_MAX_ONCE_PEELED_INSNS) < loop->ninsns)
*************** decide_peel_once_rolling (struct loop *l
*** 281,291 ****
      }
  
    /* Check for simple loops.  */
!   loop->simple = simple_loop_p (loop, &loop->desc);
!   loop->has_desc = 1;
  
    /* Check number of iterations.  */
!   if (!loop->simple || !loop->desc.const_iter || loop->desc.niter != 0)
      {
        if (rtl_dump_file)
  	fprintf (rtl_dump_file, ";; Unable to prove that the loop rolls exactly once\n");
--- 310,321 ----
      }
  
    /* Check for simple loops.  */
!   desc = get_simple_loop_desc (loop);
  
    /* Check number of iterations.  */
!   if (!desc->simple_p
!       || !desc->const_iter
!       || desc->niter != 0)
      {
        if (rtl_dump_file)
  	fprintf (rtl_dump_file, ";; Unable to prove that the loop rolls exactly once\n");
*************** static void
*** 303,311 ****
  decide_peel_completely (struct loop *loop, int flags ATTRIBUTE_UNUSED)
  {
    unsigned npeel;
  
    if (rtl_dump_file)
!     fprintf (rtl_dump_file, ";; Considering peeling completely\n");
  
    /* Skip non-innermost loops.  */
    if (loop->inner)
--- 333,342 ----
  decide_peel_completely (struct loop *loop, int flags ATTRIBUTE_UNUSED)
  {
    unsigned npeel;
+   struct niter_desc *desc;
  
    if (rtl_dump_file)
!     fprintf (rtl_dump_file, "\n;; Considering peeling completely\n");
  
    /* Skip non-innermost loops.  */
    if (loop->inner)
*************** decide_peel_completely (struct loop *loo
*** 346,371 ****
      }
  
    /* Check for simple loops.  */
!   if (!loop->has_desc)
!     {
!       loop->simple = simple_loop_p (loop, &loop->desc);
!       loop->has_desc = 1;
!     }
  
    /* Check number of iterations.  */
!   if (!loop->simple || !loop->desc.const_iter)
      {
        if (rtl_dump_file)
  	fprintf (rtl_dump_file, ";; Unable to prove that the loop iterates constant times\n");
        return;
      }
  
!   if (loop->desc.niter > npeel - 1)
      {
        if (rtl_dump_file)
  	{
  	  fprintf (rtl_dump_file, ";; Not peeling loop completely, rolls too much (");
! 	  fprintf (rtl_dump_file, HOST_WIDEST_INT_PRINT_DEC,(HOST_WIDEST_INT) loop->desc.niter);
  	  fprintf (rtl_dump_file, " iterations > %d [maximum peelings])\n", npeel);
  	}
        return;
--- 377,399 ----
      }
  
    /* Check for simple loops.  */
!   desc = get_simple_loop_desc (loop);
  
    /* Check number of iterations.  */
!   if (!desc->simple_p
!       || !desc->const_iter)
      {
        if (rtl_dump_file)
  	fprintf (rtl_dump_file, ";; Unable to prove that the loop iterates constant times\n");
        return;
      }
  
!   if (desc->niter > npeel - 1)
      {
        if (rtl_dump_file)
  	{
  	  fprintf (rtl_dump_file, ";; Not peeling loop completely, rolls too much (");
! 	  fprintf (rtl_dump_file, HOST_WIDEST_INT_PRINT_DEC, desc->niter);
  	  fprintf (rtl_dump_file, " iterations > %d [maximum peelings])\n", npeel);
  	}
        return;
*************** peel_loop_completely (struct loops *loop
*** 397,404 ****
    sbitmap wont_exit;
    unsigned HOST_WIDE_INT npeel;
    unsigned n_remove_edges, i;
!   edge *remove_edges;
!   struct loop_desc *desc = &loop->desc;
  
    npeel = desc->niter;
  
--- 425,432 ----
    sbitmap wont_exit;
    unsigned HOST_WIDE_INT npeel;
    unsigned n_remove_edges, i;
!   edge *remove_edges, ei;
!   struct niter_desc *desc = simple_loop_desc (loop);
  
    npeel = desc->niter;
  
*************** peel_loop_completely (struct loops *loop
*** 407,413 ****
        wont_exit = sbitmap_alloc (npeel + 1);
        sbitmap_ones (wont_exit);
        RESET_BIT (wont_exit, 0);
!       if (desc->may_be_zero)
  	RESET_BIT (wont_exit, 1);
  
        remove_edges = xcalloc (npeel, sizeof (edge));
--- 435,441 ----
        wont_exit = sbitmap_alloc (npeel + 1);
        sbitmap_ones (wont_exit);
        RESET_BIT (wont_exit, 0);
!       if (desc->noloop_assumptions)
  	RESET_BIT (wont_exit, 1);
  
        remove_edges = xcalloc (npeel, sizeof (edge));
*************** peel_loop_completely (struct loops *loop
*** 427,445 ****
        free (remove_edges);
      }
  
    /* Now remove the unreachable part of the last iteration and cancel
       the loop.  */
!   remove_path (loops, desc->in_edge);
  
    if (rtl_dump_file)
      fprintf (rtl_dump_file, ";; Peeled loop completely, %d times\n", (int) npeel);
  }
  
  /* Decide whether to unroll LOOP iterating constant number of times and how much.  */
  static void
  decide_unroll_constant_iterations (struct loop *loop, int flags)
  {
!   unsigned nunroll, nunroll_by_av, best_copies, best_unroll = -1, n_copies, i;
  
    if (!(flags & UAP_UNROLL))
      {
--- 455,478 ----
        free (remove_edges);
      }
  
+   ei = desc->in_edge;
+   free_simple_loop_desc (loop);
+ 
    /* Now remove the unreachable part of the last iteration and cancel
       the loop.  */
!   remove_path (loops, ei);
  
    if (rtl_dump_file)
      fprintf (rtl_dump_file, ";; Peeled loop completely, %d times\n", (int) npeel);
  }
  
  /* Decide whether to unroll LOOP iterating constant number of times and how much.  */
+ 
  static void
  decide_unroll_constant_iterations (struct loop *loop, int flags)
  {
!   unsigned nunroll, nunroll_by_av, best_copies, best_unroll = 0, n_copies, i;
!   struct niter_desc *desc;
  
    if (!(flags & UAP_UNROLL))
      {
*************** decide_unroll_constant_iterations (struc
*** 448,454 ****
      }
  
    if (rtl_dump_file)
!     fprintf (rtl_dump_file, ";; Considering unrolling loop with constant number of iterations\n");
  
    /* nunroll = total number of copies of the original loop body in
       unrolled loop (i.e. if it is 2, we have to duplicate loop body once.  */
--- 481,488 ----
      }
  
    if (rtl_dump_file)
!     fprintf (rtl_dump_file,
! 	     "\n;; Considering unrolling loop with constant number of iterations\n");
  
    /* nunroll = total number of copies of the original loop body in
       unrolled loop (i.e. if it is 2, we have to duplicate loop body once.  */
*************** decide_unroll_constant_iterations (struc
*** 468,481 ****
      }
  
    /* Check for simple loops.  */
!   if (!loop->has_desc)
!     {
!       loop->simple = simple_loop_p (loop, &loop->desc);
!       loop->has_desc = 1;
!     }
  
    /* Check number of iterations.  */
!   if (!loop->simple || !loop->desc.const_iter)
      {
        if (rtl_dump_file)
  	fprintf (rtl_dump_file, ";; Unable to prove that the loop iterates constant times\n");
--- 502,511 ----
      }
  
    /* Check for simple loops.  */
!   desc = get_simple_loop_desc (loop);
  
    /* Check number of iterations.  */
!   if (!desc->simple_p || !desc->const_iter)
      {
        if (rtl_dump_file)
  	fprintf (rtl_dump_file, ";; Unable to prove that the loop iterates constant times\n");
*************** decide_unroll_constant_iterations (struc
*** 483,489 ****
      }
  
    /* Check whether the loop rolls enough to consider.  */
!   if (loop->desc.niter < 2 * nunroll)
      {
        if (rtl_dump_file)
  	fprintf (rtl_dump_file, ";; Not unrolling loop, doesn't roll\n");
--- 513,519 ----
      }
  
    /* Check whether the loop rolls enough to consider.  */
!   if (desc->niter < 2 * nunroll)
      {
        if (rtl_dump_file)
  	fprintf (rtl_dump_file, ";; Not unrolling loop, doesn't roll\n");
*************** decide_unroll_constant_iterations (struc
*** 497,512 ****
    best_copies = 2 * nunroll + 10;
  
    i = 2 * nunroll + 2;
!   if ((unsigned) i - 1 >= loop->desc.niter)
!     i = loop->desc.niter - 2;
  
    for (; i >= nunroll - 1; i--)
      {
!       unsigned exit_mod = loop->desc.niter % (i + 1);
  
!       if (loop->desc.postincr)
  	n_copies = exit_mod + i + 1;
!       else if (exit_mod != (unsigned) i || loop->desc.may_be_zero)
  	n_copies = exit_mod + i + 2;
        else
  	n_copies = i + 1;
--- 527,543 ----
    best_copies = 2 * nunroll + 10;
  
    i = 2 * nunroll + 2;
!   if (i - 1 >= desc->niter)
!     i = desc->niter - 2;
  
    for (; i >= nunroll - 1; i--)
      {
!       unsigned exit_mod = desc->niter % (i + 1);
  
!       if (!loop_exit_at_end_p (loop))
  	n_copies = exit_mod + i + 1;
!       else if (exit_mod != (unsigned) i
! 	       || desc->noloop_assumptions != NULL_RTX)
  	n_copies = exit_mod + i + 2;
        else
  	n_copies = i + 1;
*************** decide_unroll_constant_iterations (struc
*** 524,529 ****
--- 555,565 ----
  
    loop->lpt_decision.decision = LPT_UNROLL_CONSTANT;
    loop->lpt_decision.times = best_unroll;
+   
+   if (rtl_dump_file)
+     fprintf (rtl_dump_file,
+ 	     ";; Decided to unroll the constant times rolling loop, %d times.\n",
+ 	     loop->lpt_decision.times);
  }
  
  /* Unroll LOOP with constant number of iterations LOOP->LPT_DECISION.TIMES + 1
*************** unroll_loop_constant_iterations (struct 
*** 554,564 ****
    unsigned n_remove_edges, i;
    edge *remove_edges;
    unsigned max_unroll = loop->lpt_decision.times;
!   struct loop_desc *desc = &loop->desc;
  
    niter = desc->niter;
  
!   if (niter <= (unsigned) max_unroll + 1)
      abort ();  /* Should not get here (such loop should be peeled instead).  */
  
    exit_mod = niter % (max_unroll + 1);
--- 590,600 ----
    unsigned n_remove_edges, i;
    edge *remove_edges;
    unsigned max_unroll = loop->lpt_decision.times;
!   struct niter_desc *desc = simple_loop_desc (loop);
  
    niter = desc->niter;
  
!   if (niter <= max_unroll + 1)
      abort ();  /* Should not get here (such loop should be peeled instead).  */
  
    exit_mod = niter % (max_unroll + 1);
*************** unroll_loop_constant_iterations (struct 
*** 569,577 ****
    remove_edges = xcalloc (max_unroll + exit_mod + 1, sizeof (edge));
    n_remove_edges = 0;
  
!   if (desc->postincr)
      {
!       /* Counter is incremented after the exit test; leave exit test
  	 in the first copy, so that the loops that start with test
  	 of exit condition have continuous body after unrolling.  */
  
--- 605,613 ----
    remove_edges = xcalloc (max_unroll + exit_mod + 1, sizeof (edge));
    n_remove_edges = 0;
  
!   if (!loop_exit_at_end_p (loop))
      {
!       /* The exit is not at the end of the loop; leave exit test
  	 in the first copy, so that the loops that start with test
  	 of exit condition have continuous body after unrolling.  */
  
*************** unroll_loop_constant_iterations (struct 
*** 580,586 ****
  
        /* Peel exit_mod iterations.  */
        RESET_BIT (wont_exit, 0);
!       if (desc->may_be_zero)
  	RESET_BIT (wont_exit, 1);
  
        if (exit_mod
--- 616,622 ----
  
        /* Peel exit_mod iterations.  */
        RESET_BIT (wont_exit, 0);
!       if (desc->noloop_assumptions)
  	RESET_BIT (wont_exit, 1);
  
        if (exit_mod
*************** unroll_loop_constant_iterations (struct 
*** 602,613 ****
  
        /* We know that niter >= max_unroll + 2; so we do not need to care of
  	 case when we would exit before reaching the loop.  So just peel
! 	 exit_mod + 1 iterations.
! 	 */
!       if (exit_mod != (unsigned) max_unroll || desc->may_be_zero)
  	{
  	  RESET_BIT (wont_exit, 0);
! 	  if (desc->may_be_zero)
  	    RESET_BIT (wont_exit, 1);
  
  	  if (!duplicate_loop_to_header_edge (loop, loop_preheader_edge (loop),
--- 638,649 ----
  
        /* We know that niter >= max_unroll + 2; so we do not need to care of
  	 case when we would exit before reaching the loop.  So just peel
! 	 exit_mod + 1 iterations.  */
!       if (exit_mod != max_unroll
! 	  || desc->noloop_assumptions)
  	{
  	  RESET_BIT (wont_exit, 0);
! 	  if (desc->noloop_assumptions)
  	    RESET_BIT (wont_exit, 1);
  
  	  if (!duplicate_loop_to_header_edge (loop, loop_preheader_edge (loop),
*************** static void
*** 647,652 ****
--- 683,689 ----
  decide_unroll_runtime_iterations (struct loop *loop, int flags)
  {
    unsigned nunroll, nunroll_by_av, i;
+   struct niter_desc *desc;
  
    if (!(flags & UAP_UNROLL))
      {
*************** decide_unroll_runtime_iterations (struct
*** 655,661 ****
      }
  
    if (rtl_dump_file)
!     fprintf (rtl_dump_file, ";; Considering unrolling loop with runtime computable number of iterations\n");
  
    /* nunroll = total number of copies of the original loop body in
       unrolled loop (i.e. if it is 2, we have to duplicate loop body once.  */
--- 692,699 ----
      }
  
    if (rtl_dump_file)
!     fprintf (rtl_dump_file,
! 	     "\n;; Considering unrolling loop with runtime computable number of iterations\n");
  
    /* nunroll = total number of copies of the original loop body in
       unrolled loop (i.e. if it is 2, we have to duplicate loop body once.  */
*************** decide_unroll_runtime_iterations (struct
*** 675,695 ****
      }
  
    /* Check for simple loops.  */
!   if (!loop->has_desc)
!     {
!       loop->simple = simple_loop_p (loop, &loop->desc);
!       loop->has_desc = 1;
!     }
  
    /* Check simpleness.  */
!   if (!loop->simple)
      {
        if (rtl_dump_file)
! 	fprintf (rtl_dump_file, ";; Unable to prove that the number of iterations can be counted in runtime\n");
        return;
      }
  
!   if (loop->desc.const_iter)
      {
        if (rtl_dump_file)
  	fprintf (rtl_dump_file, ";; Loop iterates constant times\n");
--- 713,730 ----
      }
  
    /* Check for simple loops.  */
!   desc = get_simple_loop_desc (loop);
  
    /* Check simpleness.  */
!   if (!desc->simple_p)
      {
        if (rtl_dump_file)
! 	fprintf (rtl_dump_file,
! 		 ";; Unable to prove that the number of iterations can be counted in runtime\n");
        return;
      }
  
!   if (desc->const_iter)
      {
        if (rtl_dump_file)
  	fprintf (rtl_dump_file, ";; Loop iterates constant times\n");
*************** decide_unroll_runtime_iterations (struct
*** 706,715 ****
  
    /* Success; now force nunroll to be power of 2, as we are unable to
       cope with overflows in computation of number of iterations.  */
!   for (i = 1; 2 * i <= nunroll; i *= 2);
  
    loop->lpt_decision.decision = LPT_UNROLL_RUNTIME;
    loop->lpt_decision.times = i - 1;
  }
  
  /* Unroll LOOP for that we are able to count number of iterations in runtime
--- 741,756 ----
  
    /* Success; now force nunroll to be power of 2, as we are unable to
       cope with overflows in computation of number of iterations.  */
!   for (i = 1; 2 * i <= nunroll; i *= 2)
!     continue;
  
    loop->lpt_decision.decision = LPT_UNROLL_RUNTIME;
    loop->lpt_decision.times = i - 1;
+   
+   if (rtl_dump_file)
+     fprintf (rtl_dump_file,
+ 	     ";; Decided to unroll the runtime computable times rolling loop, %d times.\n",
+ 	     loop->lpt_decision.times);
  }
  
  /* Unroll LOOP for that we are able to count number of iterations in runtime
*************** unroll_loop_runtime_iterations (struct l
*** 756,762 ****
    edge *remove_edges, e;
    bool extra_zero_check, last_may_exit;
    unsigned max_unroll = loop->lpt_decision.times;
!   struct loop_desc *desc = &loop->desc;
  
    /* Remember blocks whose dominators will have to be updated.  */
    dom_bbs = xcalloc (n_basic_blocks, sizeof (basic_block));
--- 797,803 ----
    edge *remove_edges, e;
    bool extra_zero_check, last_may_exit;
    unsigned max_unroll = loop->lpt_decision.times;
!   struct niter_desc *desc = simple_loop_desc (loop);
  
    /* Remember blocks whose dominators will have to be updated.  */
    dom_bbs = xcalloc (n_basic_blocks, sizeof (basic_block));
*************** unroll_loop_runtime_iterations (struct l
*** 777,783 ****
      }
    free (body);
  
!   if (desc->postincr)
      {
        /* Leave exit in first copy (for explanation why see comment in
  	 unroll_loop_constant_iterations).  */
--- 818,824 ----
      }
    free (body);
  
!   if (!loop_exit_at_end_p (loop))
      {
        /* Leave exit in first copy (for explanation why see comment in
  	 unroll_loop_constant_iterations).  */
*************** unroll_loop_runtime_iterations (struct l
*** 798,804 ****
  
    /* Get expression for number of iterations.  */
    start_sequence ();
!   niter = count_loop_iterations (desc, NULL, NULL);
    if (!niter)
      abort ();
    niter = force_operand (niter, NULL);
--- 839,845 ----
  
    /* Get expression for number of iterations.  */
    start_sequence ();
!   niter = copy_rtx (desc->niter_expr);
    if (!niter)
      abort ();
    niter = force_operand (niter, NULL);
*************** unroll_loop_runtime_iterations (struct l
*** 806,812 ****
    /* Count modulo by ANDing it with max_unroll; we use the fact that
       the number of unrollings is a power of two, and thus this is correct
       even if there is overflow in the computation.  */
!   niter = expand_simple_binop (GET_MODE (desc->var), AND,
  			       niter,
  			       GEN_INT (max_unroll),
  			       NULL_RTX, 0, OPTAB_LIB_WIDEN);
--- 847,853 ----
    /* Count modulo by ANDing it with max_unroll; we use the fact that
       the number of unrollings is a power of two, and thus this is correct
       even if there is overflow in the computation.  */
!   niter = expand_simple_binop (desc->mode, AND,
  			       niter,
  			       GEN_INT (max_unroll),
  			       NULL_RTX, 0, OPTAB_LIB_WIDEN);
*************** unroll_loop_runtime_iterations (struct l
*** 824,833 ****
  
    /* Peel the first copy of loop body (almost always we must leave exit test
       here; the only exception is when we have extra zero check and the number
!      of iterations is reliable (i.e. comes out of NE condition).  Also record
!      the place of (possible) extra zero check.  */
    sbitmap_zero (wont_exit);
!   if (extra_zero_check && desc->cond == NE)
      SET_BIT (wont_exit, 1);
    ezc_swtch = loop_preheader_edge (loop)->src;
    if (!duplicate_loop_to_header_edge (loop, loop_preheader_edge (loop),
--- 865,875 ----
  
    /* Peel the first copy of loop body (almost always we must leave exit test
       here; the only exception is when we have extra zero check and the number
!      of iterations is reliable.  Also record the place of (possible) extra
!      zero check.  */
    sbitmap_zero (wont_exit);
!   if (extra_zero_check
!       && !desc->noloop_assumptions)
      SET_BIT (wont_exit, 1);
    ezc_swtch = loop_preheader_edge (loop)->src;
    if (!duplicate_loop_to_header_edge (loop, loop_preheader_edge (loop),
*************** static void
*** 917,922 ****
--- 959,965 ----
  decide_peel_simple (struct loop *loop, int flags)
  {
    unsigned npeel;
+   struct niter_desc *desc;
  
    if (!(flags & UAP_PEEL))
      {
*************** decide_peel_simple (struct loop *loop, i
*** 925,931 ****
      }
  
    if (rtl_dump_file)
!     fprintf (rtl_dump_file, ";; Considering simply peeling loop\n");
  
    /* npeel = number of iterations to peel.  */
    npeel = PARAM_VALUE (PARAM_MAX_PEELED_INSNS) / loop->ninsns;
--- 968,974 ----
      }
  
    if (rtl_dump_file)
!     fprintf (rtl_dump_file, "\n;; Considering simply peeling loop\n");
  
    /* npeel = number of iterations to peel.  */
    npeel = PARAM_VALUE (PARAM_MAX_PEELED_INSNS) / loop->ninsns;
*************** decide_peel_simple (struct loop *loop, i
*** 941,954 ****
      }
  
    /* Check for simple loops.  */
!   if (!loop->has_desc)
!     {
!       loop->simple = simple_loop_p (loop, &loop->desc);
!       loop->has_desc = 1;
!     }
  
    /* Check number of iterations.  */
!   if (loop->simple && loop->desc.const_iter)
      {
        if (rtl_dump_file)
  	fprintf (rtl_dump_file, ";; Loop iterates constant times\n");
--- 984,993 ----
      }
  
    /* Check for simple loops.  */
!   desc = get_simple_loop_desc (loop);
  
    /* Check number of iterations.  */
!   if (desc->simple_p && desc->const_iter)
      {
        if (rtl_dump_file)
  	fprintf (rtl_dump_file, ";; Loop iterates constant times\n");
*************** decide_peel_simple (struct loop *loop, i
*** 957,963 ****
  
    /* Do not simply peel loops with branches inside -- it increases number
       of mispredicts.  */
!   if (loop->desc.n_branches > 1)
      {
        if (rtl_dump_file)
  	fprintf (rtl_dump_file, ";; Not peeling, contains branches\n");
--- 996,1002 ----
  
    /* Do not simply peel loops with branches inside -- it increases number
       of mispredicts.  */
!   if (num_loop_branches (loop) > 1)
      {
        if (rtl_dump_file)
  	fprintf (rtl_dump_file, ";; Not peeling, contains branches\n");
*************** decide_peel_simple (struct loop *loop, i
*** 992,997 ****
--- 1031,1040 ----
    /* Success.  */
    loop->lpt_decision.decision = LPT_PEEL_SIMPLE;
    loop->lpt_decision.times = npeel;
+       
+   if (rtl_dump_file)
+     fprintf (rtl_dump_file, ";; Decided to simply peel the loop, %d times.\n",
+ 	     loop->lpt_decision.times);
  }
  
  /* Peel a LOOP LOOP->LPT_DECISION.TIMES times.  The transformation:
*************** static void
*** 1033,1038 ****
--- 1076,1082 ----
  decide_unroll_stupid (struct loop *loop, int flags)
  {
    unsigned nunroll, nunroll_by_av, i;
+   struct niter_desc *desc;
  
    if (!(flags & UAP_UNROLL_ALL))
      {
*************** decide_unroll_stupid (struct loop *loop,
*** 1041,1047 ****
      }
  
    if (rtl_dump_file)
!     fprintf (rtl_dump_file, ";; Considering unrolling loop stupidly\n");
  
    /* nunroll = total number of copies of the original loop body in
       unrolled loop (i.e. if it is 2, we have to duplicate loop body once.  */
--- 1085,1091 ----
      }
  
    if (rtl_dump_file)
!     fprintf (rtl_dump_file, "\n;; Considering unrolling loop stupidly\n");
  
    /* nunroll = total number of copies of the original loop body in
       unrolled loop (i.e. if it is 2, we have to duplicate loop body once.  */
*************** decide_unroll_stupid (struct loop *loop,
*** 1061,1074 ****
      }
  
    /* Check for simple loops.  */
!   if (!loop->has_desc)
!     {
!       loop->simple = simple_loop_p (loop, &loop->desc);
!       loop->has_desc = 1;
!     }
  
    /* Check simpleness.  */
!   if (loop->simple)
      {
        if (rtl_dump_file)
  	fprintf (rtl_dump_file, ";; The loop is simple\n");
--- 1105,1114 ----
      }
  
    /* Check for simple loops.  */
!   desc = get_simple_loop_desc (loop);
  
    /* Check simpleness.  */
!   if (desc->simple_p)
      {
        if (rtl_dump_file)
  	fprintf (rtl_dump_file, ";; The loop is simple\n");
*************** decide_unroll_stupid (struct loop *loop,
*** 1077,1083 ****
  
    /* Do not unroll loops with branches inside -- it increases number
       of mispredicts.  */
!   if (loop->desc.n_branches > 1)
      {
        if (rtl_dump_file)
  	fprintf (rtl_dump_file, ";; Not unrolling, contains branches\n");
--- 1117,1123 ----
  
    /* Do not unroll loops with branches inside -- it increases number
       of mispredicts.  */
!   if (num_loop_branches (loop) > 1)
      {
        if (rtl_dump_file)
  	fprintf (rtl_dump_file, ";; Not unrolling, contains branches\n");
*************** decide_unroll_stupid (struct loop *loop,
*** 1085,1091 ****
      }
  
    /* If we have profile feedback, check whether the loop rolls.  */
!   if (loop->header->count && expected_loop_iterations (loop) < 2 * nunroll)
      {
        if (rtl_dump_file)
  	fprintf (rtl_dump_file, ";; Not unrolling loop, doesn't roll\n");
--- 1125,1132 ----
      }
  
    /* If we have profile feedback, check whether the loop rolls.  */
!   if (loop->header->count
!       && expected_loop_iterations (loop) < 2 * nunroll)
      {
        if (rtl_dump_file)
  	fprintf (rtl_dump_file, ";; Not unrolling loop, doesn't roll\n");
*************** decide_unroll_stupid (struct loop *loop,
*** 1095,1104 ****
    /* Success.  Now force nunroll to be power of 2, as it seems that this
       improves results (partially because of better alignments, partially
       because of some dark magic).  */
!   for (i = 1; 2 * i <= nunroll; i *= 2);
  
    loop->lpt_decision.decision = LPT_UNROLL_STUPID;
    loop->lpt_decision.times = i - 1;
  }
  
  /* Unroll a LOOP LOOP->LPT_DECISION.TIMES times.  The transformation:
--- 1136,1151 ----
    /* Success.  Now force nunroll to be power of 2, as it seems that this
       improves results (partially because of better alignments, partially
       because of some dark magic).  */
!   for (i = 1; 2 * i <= nunroll; i *= 2)
!     continue;
  
    loop->lpt_decision.decision = LPT_UNROLL_STUPID;
    loop->lpt_decision.times = i - 1;
+       
+   if (rtl_dump_file)
+     fprintf (rtl_dump_file,
+ 	     ";; Decided to unroll the loop stupidly, %d times.\n",
+ 	     loop->lpt_decision.times);
  }
  
  /* Unroll a LOOP LOOP->LPT_DECISION.TIMES times.  The transformation:
Index: predict.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/predict.c,v
retrieving revision 1.71.2.14.2.1
diff -c -3 -p -r1.71.2.14.2.1 predict.c
*** predict.c	21 Jan 2004 01:10:38 -0000	1.71.2.14.2.1
--- predict.c	30 Jan 2004 01:31:21 -0000
*************** predict_loops (struct loops *loops_info,
*** 540,546 ****
        unsigned j;
        int exits;
        struct loop *loop = loops_info->parray[i];
!       struct loop_desc desc;
        unsigned HOST_WIDE_INT niter;
  
        flow_loop_scan (loop, LOOP_EXIT_EDGES);
--- 540,546 ----
        unsigned j;
        int exits;
        struct loop *loop = loops_info->parray[i];
!       struct niter_desc desc;
        unsigned HOST_WIDE_INT niter;
  
        flow_loop_scan (loop, LOOP_EXIT_EDGES);
*************** predict_loops (struct loops *loops_info,
*** 548,554 ****
  
        if (simpleloops)
  	{
! 	  if (simple_loop_p (loop, &desc) && desc.const_iter)
  	    {
  	      int prob;
  	      niter = desc.niter + 1;
--- 548,557 ----
  
        if (simpleloops)
  	{
! 	  iv_analysis_loop_init (loop);
! 	  find_simple_exit (loop, &desc);
! 
! 	  if (desc.simple_p && desc.const_iter)
  	    {
  	      int prob;
  	      niter = desc.niter + 1;
*************** predict_loops (struct loops *loops_info,
*** 606,611 ****
--- 609,617 ----
  		   / exits);
  	}
      }
+       
+   if (simpleloops)
+     iv_analysis_done ();
  }
  
  /* Statically estimate the probability that a branch will be taken and produce
Index: tree-cfg.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-cfg.c,v
retrieving revision 1.1.4.244.2.5
diff -c -3 -p -r1.1.4.244.2.5 tree-cfg.c
*** tree-cfg.c	25 Jan 2004 20:20:15 -0000	1.1.4.244.2.5
--- tree-cfg.c	30 Jan 2004 01:31:21 -0000
*************** bsi_replace (const block_stmt_iterator *
*** 2571,2580 ****
  
     In all cases, the returned *BSI points to the correct location.  The
     return value is true if insertion should be done after the location,
!    or false if before the location.  */
  
  static bool
! tree_find_edge_insert_loc (edge e, block_stmt_iterator *bsi)
  {
    basic_block dest, src;
    tree tmp;
--- 2571,2582 ----
  
     In all cases, the returned *BSI points to the correct location.  The
     return value is true if insertion should be done after the location,
!    or false if before the location.  If new basic block has to be created,
!    it is stored in *NEW_BB.  */
  
  static bool
! tree_find_edge_insert_loc (edge e, block_stmt_iterator *bsi,
! 			   basic_block *new_bb)
  {
    basic_block dest, src;
    tree tmp;
*************** tree_find_edge_insert_loc (edge e, block
*** 2635,2640 ****
--- 2637,2644 ----
  
    /* Otherwise, create a new basic block, and split this edge.  */
    dest = split_edge (e);
+   if (new_bb)
+     *new_bb = dest;
    e = dest->pred;
    goto restart;
  }
*************** bsi_commit_edge_inserts_1 (edge e)
*** 2677,2683 ****
  
        PENDING_STMT (e) = NULL_TREE;
  
!       if (tree_find_edge_insert_loc (e, &bsi))
  	bsi_insert_after (&bsi, stmt, BSI_NEW_STMT);
        else
  	bsi_insert_before (&bsi, stmt, BSI_NEW_STMT);
--- 2681,2687 ----
  
        PENDING_STMT (e) = NULL_TREE;
  
!       if (tree_find_edge_insert_loc (e, &bsi, NULL))
  	bsi_insert_after (&bsi, stmt, BSI_NEW_STMT);
        else
  	bsi_insert_before (&bsi, stmt, BSI_NEW_STMT);
*************** bsi_insert_on_edge (edge e, tree stmt)
*** 2694,2714 ****
    append_to_statement_list (stmt, &PENDING_STMT (e));
  }
  
! /* Similar to bsi_insert_on_edge+bsi_commit_edge_inserts.  */
  /* ??? Why in the world do we need this?  Only PRE uses it.  */
  
! void
  bsi_insert_on_edge_immediate (edge e, tree stmt)
  {
    block_stmt_iterator bsi;
  
    if (PENDING_STMT (e))
      abort ();
  
!   if (tree_find_edge_insert_loc (e, &bsi))
      bsi_insert_after (&bsi, stmt, BSI_NEW_STMT);
    else
      bsi_insert_before (&bsi, stmt, BSI_NEW_STMT);
  }
  
  /*---------------------------------------------------------------------------
--- 2698,2722 ----
    append_to_statement_list (stmt, &PENDING_STMT (e));
  }
  
! /* Similar to bsi_insert_on_edge+bsi_commit_edge_inserts.  If new block has to
!    be created, it is returned.  */
  /* ??? Why in the world do we need this?  Only PRE uses it.  */
  
! basic_block
  bsi_insert_on_edge_immediate (edge e, tree stmt)
  {
    block_stmt_iterator bsi;
+   basic_block new_bb = NULL;
  
    if (PENDING_STMT (e))
      abort ();
  
!   if (tree_find_edge_insert_loc (e, &bsi, &new_bb))
      bsi_insert_after (&bsi, stmt, BSI_NEW_STMT);
    else
      bsi_insert_before (&bsi, stmt, BSI_NEW_STMT);
+ 
+   return new_bb;
  }
  
  /*---------------------------------------------------------------------------
Index: tree-flow.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-flow.h,v
retrieving revision 1.1.4.177.2.6
diff -c -3 -p -r1.1.4.177.2.6 tree-flow.h
*** tree-flow.h	25 Jan 2004 20:20:16 -0000	1.1.4.177.2.6
--- tree-flow.h	30 Jan 2004 01:31:21 -0000
*************** extern void tree_optimize_tail_calls (bo
*** 448,454 ****
  extern edge tree_block_forwards_to (basic_block bb);
  extern void bsi_insert_on_edge (edge, tree);
  extern void bsi_commit_edge_inserts (int *);
! extern void bsi_insert_on_edge_immediate (edge, tree);
  extern void notice_special_calls (tree);
  extern void clear_special_calls (void);
  extern void compute_dominance_frontiers (bitmap *);
--- 448,454 ----
  extern edge tree_block_forwards_to (basic_block bb);
  extern void bsi_insert_on_edge (edge, tree);
  extern void bsi_commit_edge_inserts (int *);
! extern basic_block bsi_insert_on_edge_immediate (edge, tree);
  extern void notice_special_calls (tree);
  extern void clear_special_calls (void);
  extern void compute_dominance_frontiers (bitmap *);
Index: tree-ssa-loop-ivopts.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-ssa-loop-ivopts.c,v
retrieving revision 1.1.2.2
diff -c -3 -p -r1.1.2.2 tree-ssa-loop-ivopts.c
*** tree-ssa-loop-ivopts.c	25 Jan 2004 22:37:11 -0000	1.1.2.2
--- tree-ssa-loop-ivopts.c	30 Jan 2004 01:31:21 -0000
*************** create_new_iv (struct iv_cand *cand)
*** 2851,2857 ****
    initial = force_gimple_operand (base, &stmts,
  				  SSA_NAME_VAR (cand->var_before), false);
    if (stmts)
!     bsi_insert_on_edge_immediate (loop_preheader_edge (current_loop), stmts);
  
    stmt = create_phi_node (cand->var_before, current_loop->header);
    SSA_NAME_DEF_STMT (cand->var_before) = stmt;
--- 2851,2864 ----
    initial = force_gimple_operand (base, &stmts,
  				  SSA_NAME_VAR (cand->var_before), false);
    if (stmts)
!     {
!       basic_block new_bb;
!       edge pe = loop_preheader_edge (current_loop);
!       
!       new_bb = bsi_insert_on_edge_immediate (pe, stmts);
!       if (new_bb)
! 	add_bb_to_loop (new_bb, new_bb->pred->src->loop_father);
!     }
  
    stmt = create_phi_node (cand->var_before, current_loop->header);
    SSA_NAME_DEF_STMT (cand->var_before) = stmt;
Index: tree-ssa-loop.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-ssa-loop.c,v
retrieving revision 1.1.2.3.2.6
diff -c -3 -p -r1.1.2.3.2.6 tree-ssa-loop.c
*** tree-ssa-loop.c	29 Jan 2004 18:36:37 -0000	1.1.2.3.2.6
--- tree-ssa-loop.c	30 Jan 2004 01:31:21 -0000
*************** copy_loop_headers (void)
*** 192,197 ****
--- 192,201 ----
  	  loop->latch = loop->header;
  	  loop->header = new_header;
  
+ 	  /* Predict the loop to be entered.  */
+ 	  predict_edge_def (loop_preheader_edge (loop), PRED_LOOP_HEADER,
+ 			    TAKEN);
+ 
  	  /* Ensure that the latch has just a single successor.  */
  	  loop_split_edge_with (loop_latch_edge (loop), NULL);
  	}


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]