OSDN Git Service

2005-09-13 Erik Edelmann <erik.edelmann@iki.fi>
[pf3gnuchains/gcc-fork.git] / gcc / loop-unroll.c
index c93170c..4cabfd5 100644 (file)
@@ -15,8 +15,8 @@ for more details.
 
 You should have received a copy of the GNU General Public License
 along with GCC; see the file COPYING.  If not, write to the Free
-Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA.  */
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA.  */
 
 #include "config.h"
 #include "system.h"
@@ -85,13 +85,16 @@ struct iv_to_split
                           XEXP (XEXP (single_set, loc[0]), loc[1]).  */ 
 };
 
+DEF_VEC_P(rtx);
+DEF_VEC_ALLOC_P(rtx,heap);
+
 /* Information about accumulators to expand.  */
 
 struct var_to_expand
 {
   rtx insn;                       /* The insn in that the variable expansion occurs.  */
   rtx reg;                         /* The accumulator which is expanded.  */
-  varray_type var_expansions;      /* The copies of the accumulator which is expanded.  */ 
+  VEC(rtx,heap) *var_expansions;   /* The copies of the accumulator which is expanded.  */ 
   enum rtx_code op;                /* The type of the accumulation - addition, subtraction 
                                       or multiplication.  */
   int expansion_count;             /* Count the number of expansions generated so far.  */
@@ -372,6 +375,7 @@ decide_peel_once_rolling (struct loop *loop, int flags ATTRIBUTE_UNUSED)
   /* Check number of iterations.  */
   if (!desc->simple_p
       || desc->assumptions
+      || desc->infinite
       || !desc->const_iter
       || desc->niter != 0)
     {
@@ -441,7 +445,8 @@ decide_peel_completely (struct loop *loop, int flags ATTRIBUTE_UNUSED)
   /* Check number of iterations.  */
   if (!desc->simple_p
       || desc->assumptions
-      || !desc->const_iter)
+      || !desc->const_iter
+      || desc->infinite)
     {
       if (dump_file)
        fprintf (dump_file,
@@ -514,7 +519,10 @@ peel_loop_completely (struct loops *loops, struct loop *loop)
                                          loops, npeel,
                                          wont_exit, desc->out_edge,
                                          remove_edges, &n_remove_edges,
-                                         DLTHE_FLAG_UPDATE_FREQ);
+                                         DLTHE_FLAG_UPDATE_FREQ
+                                         | DLTHE_FLAG_COMPLETTE_PEEL
+                                         | (opt_info
+                                            ? DLTHE_RECORD_COPY_NUMBER : 0));
       gcc_assert (ok);
 
       free (wont_exit);
@@ -712,7 +720,10 @@ unroll_loop_constant_iterations (struct loops *loops, struct loop *loop)
                                              loops, exit_mod,
                                              wont_exit, desc->out_edge,
                                              remove_edges, &n_remove_edges,
-                                             DLTHE_FLAG_UPDATE_FREQ);
+                                             DLTHE_FLAG_UPDATE_FREQ
+                                             | (opt_info && exit_mod > 1
+                                                ? DLTHE_RECORD_COPY_NUMBER
+                                                  : 0));
          gcc_assert (ok);
 
           if (opt_info && exit_mod > 1)
@@ -748,7 +759,10 @@ unroll_loop_constant_iterations (struct loops *loops, struct loop *loop)
                                              loops, exit_mod + 1,
                                              wont_exit, desc->out_edge,
                                              remove_edges, &n_remove_edges,
-                                             DLTHE_FLAG_UPDATE_FREQ);
+                                             DLTHE_FLAG_UPDATE_FREQ
+                                             | (opt_info && exit_mod > 0
+                                                ? DLTHE_RECORD_COPY_NUMBER
+                                                  : 0));
          gcc_assert (ok);
  
           if (opt_info && exit_mod > 0)
@@ -772,7 +786,10 @@ unroll_loop_constant_iterations (struct loops *loops, struct loop *loop)
                                      loops, max_unroll,
                                      wont_exit, desc->out_edge,
                                      remove_edges, &n_remove_edges,
-                                     DLTHE_FLAG_UPDATE_FREQ);
+                                     DLTHE_FLAG_UPDATE_FREQ
+                                     | (opt_info
+                                        ? DLTHE_RECORD_COPY_NUMBER
+                                          : 0));
   gcc_assert (ok);
 
   if (opt_info)
@@ -785,7 +802,7 @@ unroll_loop_constant_iterations (struct loops *loops, struct loop *loop)
 
   if (exit_at_end)
     {
-      basic_block exit_block = desc->in_edge->src->rbi->copy;
+      basic_block exit_block = get_bb_copy (desc->in_edge->src);
       /* Find a new in and out edge; they are in the last copy we have made.  */
       
       if (EDGE_SUCC (exit_block, 0)->dest == desc->out_edge->dest)
@@ -1092,7 +1109,10 @@ unroll_loop_runtime_iterations (struct loops *loops, struct loop *loop)
                                      loops, max_unroll,
                                      wont_exit, desc->out_edge,
                                      remove_edges, &n_remove_edges,
-                                     DLTHE_FLAG_UPDATE_FREQ);
+                                     DLTHE_FLAG_UPDATE_FREQ
+                                     | (opt_info
+                                        ? DLTHE_RECORD_COPY_NUMBER
+                                          : 0));
   gcc_assert (ok);
   
   if (opt_info)
@@ -1105,7 +1125,7 @@ unroll_loop_runtime_iterations (struct loops *loops, struct loop *loop)
 
   if (exit_at_end)
     {
-      basic_block exit_block = desc->in_edge->src->rbi->copy;
+      basic_block exit_block = get_bb_copy (desc->in_edge->src);
       /* Find a new in and out edge; they are in the last copy we have
         made.  */
       
@@ -1269,7 +1289,10 @@ peel_loop_simple (struct loops *loops, struct loop *loop)
   ok = duplicate_loop_to_header_edge (loop, loop_preheader_edge (loop),
                                      loops, npeel, wont_exit,
                                      NULL, NULL,
-                                     NULL, DLTHE_FLAG_UPDATE_FREQ);
+                                     NULL, DLTHE_FLAG_UPDATE_FREQ
+                                     | (opt_info
+                                        ? DLTHE_RECORD_COPY_NUMBER
+                                          : 0));
   gcc_assert (ok);
 
   free (wont_exit);
@@ -1417,7 +1440,10 @@ unroll_loop_stupid (struct loops *loops, struct loop *loop)
   ok = duplicate_loop_to_header_edge (loop, loop_latch_edge (loop),
                                      loops, nunroll, wont_exit,
                                      NULL, NULL, NULL,
-                                     DLTHE_FLAG_UPDATE_FREQ);
+                                     DLTHE_FLAG_UPDATE_FREQ
+                                     | (opt_info
+                                        ? DLTHE_RECORD_COPY_NUMBER
+                                          : 0));
   gcc_assert (ok);
   
   if (opt_info)
@@ -1548,7 +1574,19 @@ analyze_insn_to_expand_var (struct loop *loop, rtx insn)
       && GET_CODE (src) != MINUS
       && GET_CODE (src) != MULT)
     return NULL;
-  
+
+  /* Hmm, this is a bit paradoxical.  We know that INSN is a valid insn
+     in MD.  But if there is no optab to generate the insn, we can not
+     perform the variable expansion.  This can happen if an MD provides
+     an insn but not a named pattern to generate it, for example to avoid
+     producing code that needs additional mode switches like for x87/mmx.
+
+     So we check have_insn_for which looks for an optab for the operation
+     in SRC.  If it doesn't exist, we can't perform the expansion even
+     though INSN is valid.  */
+  if (!have_insn_for (GET_CODE (src), GET_MODE (src)))
+    return NULL;
+
   if (!XEXP (src, 0))
     return NULL;
   
@@ -1578,7 +1616,7 @@ analyze_insn_to_expand_var (struct loop *loop, rtx insn)
   /* Record the accumulator to expand.  */
   ves = xmalloc (sizeof (struct var_to_expand));
   ves->insn = insn;
-  VARRAY_RTX_INIT (ves->var_expansions, 1, "var_expansions");
+  ves->var_expansions = VEC_alloc (rtx, heap, 1);
   ves->reg = copy_rtx (dest);
   ves->op = GET_CODE (src);
   ves->expansion_count = 0;
@@ -1889,9 +1927,9 @@ get_expansion (struct var_to_expand *ve)
   if (ve->reuse_expansion == 0)
     reg = ve->reg;
   else
-    reg = VARRAY_RTX (ve->var_expansions,  ve->reuse_expansion - 1);
+    reg = VEC_index (rtx, ve->var_expansions, ve->reuse_expansion - 1);
   
-  if (VARRAY_ACTIVE_SIZE (ve->var_expansions) == (unsigned) ve->reuse_expansion)
+  if (VEC_length (rtx, ve->var_expansions) == (unsigned) ve->reuse_expansion)
     ve->reuse_expansion = 0;
   else 
     ve->reuse_expansion++;
@@ -1928,7 +1966,7 @@ expand_var_during_unrolling (struct var_to_expand *ve, rtx insn)
   if (apply_change_group ())
     if (really_new_expansion)
       {
-        VARRAY_PUSH_RTX (ve->var_expansions, new_reg);
+        VEC_safe_push (rtx, heap, ve->var_expansions, new_reg);
         ve->expansion_count++;
       }
 }
@@ -1946,21 +1984,19 @@ insert_var_expansion_initialization (void **slot, void *place_p)
   rtx seq, var, zero_init, insn;
   unsigned i;
   
-  if (VARRAY_ACTIVE_SIZE (ve->var_expansions) == 0)
+  if (VEC_length (rtx, ve->var_expansions) == 0)
     return 1;
   
   start_sequence ();
   if (ve->op == PLUS || ve->op == MINUS) 
-    for (i = 0; i < VARRAY_ACTIVE_SIZE (ve->var_expansions); i++)
+    for (i = 0; VEC_iterate (rtx, ve->var_expansions, i, var); i++)
       {
-        var = VARRAY_RTX (ve->var_expansions, i);
         zero_init =  CONST0_RTX (GET_MODE (var));
         emit_move_insn (var, zero_init);
       }
   else if (ve->op == MULT)
-    for (i = 0; i < VARRAY_ACTIVE_SIZE (ve->var_expansions); i++)
+    for (i = 0; VEC_iterate (rtx, ve->var_expansions, i, var); i++)
       {
-        var = VARRAY_RTX (ve->var_expansions, i);
         zero_init =  CONST1_RTX (GET_MODE (var));
         emit_move_insn (var, zero_init);
       }
@@ -1991,21 +2027,19 @@ combine_var_copies_in_loop_exit (void **slot, void *place_p)
   rtx expr, seq, var, insn;
   unsigned i;
 
-  if (VARRAY_ACTIVE_SIZE (ve->var_expansions) == 0)
+  if (VEC_length (rtx, ve->var_expansions) == 0)
     return 1;
   
   start_sequence ();
   if (ve->op == PLUS || ve->op == MINUS)
-    for (i = 0; i < VARRAY_ACTIVE_SIZE (ve->var_expansions); i++)
+    for (i = 0; VEC_iterate (rtx, ve->var_expansions, i, var); i++)
       {
-        var = VARRAY_RTX (ve->var_expansions, i);
         sum = simplify_gen_binary (PLUS, GET_MODE (ve->reg),
                                    var, sum);
       }
   else if (ve->op == MULT)
-    for (i = 0; i < VARRAY_ACTIVE_SIZE (ve->var_expansions); i++)
+    for (i = 0; VEC_iterate (rtx, ve->var_expansions, i, var); i++)
       {
-        var = VARRAY_RTX (ve->var_expansions, i);
         sum = simplify_gen_binary (MULT, GET_MODE (ve->reg),
                                    var, sum);
       }
@@ -2057,10 +2091,13 @@ apply_opt_in_copies (struct opt_info *opt_info,
   for (i = opt_info->first_new_block; i < (unsigned) last_basic_block; i++)
     {
       bb = BASIC_BLOCK (i);
-      orig_bb = bb->rbi->original;
+      orig_bb = get_bb_original (bb);
       
-      delta = determine_split_iv_delta (bb->rbi->copy_number, n_copies,
+      /* bb->aux holds position in copy sequence initialized by
+        duplicate_loop_to_header_edge.  */
+      delta = determine_split_iv_delta ((size_t)bb->aux, n_copies,
                                        unrolling);
+      bb->aux = 0;
       orig_insn = BB_HEAD (orig_bb);
       for (insn = BB_HEAD (bb); insn != NEXT_INSN (BB_END (bb)); insn = next)
         {
@@ -2123,12 +2160,12 @@ apply_opt_in_copies (struct opt_info *opt_info,
   
   /* Rewrite also the original loop body.  Find them as originals of the blocks
      in the last copied iteration, i.e. those that have
-     bb->rbi->original->copy == bb.  */
+     get_bb_copy (get_bb_original (bb)) == bb.  */
   for (i = opt_info->first_new_block; i < (unsigned) last_basic_block; i++)
     {
       bb = BASIC_BLOCK (i);
-      orig_bb = bb->rbi->original;
-      if (orig_bb->rbi->copy != bb)
+      orig_bb = get_bb_original (bb);
+      if (get_bb_copy (orig_bb) != bb)
        continue;
       
       delta = determine_split_iv_delta (0, n_copies, unrolling);
@@ -2166,7 +2203,7 @@ release_var_copies (void **slot, void *data ATTRIBUTE_UNUSED)
 {
   struct var_to_expand *ve = *slot;
   
-  VARRAY_CLEAR (ve->var_expansions);
+  VEC_free (rtx, heap, ve->var_expansions);
   
   /* Continue traversing the hash table.  */
   return 1;