OSDN Git Service

Fix problem reported by chris@lslsun.epfl.ch (Christian Iseli)
[pf3gnuchains/gcc-fork.git] / gcc / unroll.c
index 3f5c548..ce6623c 100644 (file)
@@ -202,7 +202,7 @@ static rtx initial_reg_note_copy PROTO((rtx, struct inline_remap *));
 static void final_reg_note_copy PROTO((rtx, struct inline_remap *));
 static void copy_loop_body PROTO((rtx, rtx, struct inline_remap *, rtx, int,
                                  enum unroll_types, rtx, rtx, rtx, rtx));
-static void iteration_info PROTO((rtx, rtx *, rtx *, rtx, rtx));
+void iteration_info PROTO((rtx, rtx *, rtx *, rtx, rtx));
 static rtx approx_final_value PROTO((enum rtx_code, rtx, int *, int *));
 static int find_splittable_regs PROTO((enum unroll_types, rtx, rtx, rtx, int));
 static int find_splittable_givs PROTO((struct iv_class *,enum unroll_types,
@@ -1046,8 +1046,11 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
 
              for (j = FIRST_PSEUDO_REGISTER; j < max_reg_before_loop; j++)
                if (local_regno[j])
-                 map->reg_map[j] = gen_reg_rtx (GET_MODE (regno_reg_rtx[j]));
-
+                 {
+                   map->reg_map[j] = gen_reg_rtx (GET_MODE (regno_reg_rtx[j]));
+                   record_base_value (REGNO (map->reg_map[j]),
+                                      regno_reg_rtx[j]);
+                 }
              /* The last copy needs the compare/branch insns at the end,
                 so reset copy_end here if the loop ends with a conditional
                 branch.  */
@@ -1091,6 +1094,16 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
          /* Set unroll type to MODULO now.  */
          unroll_type = UNROLL_MODULO;
          loop_preconditioned = 1;
+#ifdef HAIFA
+         if (loop_n_iterations > 0)
+           loop_unroll_iter[ loop_number(loop_start, loop_end) ]
+             = (loop_n_iterations
+                 - loop_n_iterations % (abs_inc * unroll_number));
+         else
+           /* inform loop.c about the new initial value */
+           loop_start_value[loop_number(loop_start, loop_end)] = initial_value;
+#endif
+
        }
     }
 
@@ -1105,6 +1118,15 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
 
   /* At this point, we are guaranteed to unroll the loop.  */
 
+#ifdef HAIFA
+  /* inform loop.c about the factor of unrolling */
+  if (unroll_type == UNROLL_COMPLETELY)
+    loop_unroll_factor[ loop_number(loop_start, loop_end) ] = -1;
+  else
+    loop_unroll_factor[ loop_number(loop_start, loop_end) ] = unroll_number;
+#endif  /* HAIFA */
+
+
   /* For each biv and giv, determine whether it can be safely split into
      a different variable for each unrolled copy of the loop body.
      We precalculate and save this info here, since computing it is
@@ -1191,7 +1213,11 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
 
       for (j = FIRST_PSEUDO_REGISTER; j < max_reg_before_loop; j++)
        if (local_regno[j])
-         map->reg_map[j] = gen_reg_rtx (GET_MODE (regno_reg_rtx[j]));
+         {
+           map->reg_map[j] = gen_reg_rtx (GET_MODE (regno_reg_rtx[j]));
+           record_base_value (REGNO (map->reg_map[j]),
+                              regno_reg_rtx[j]);
+         }
 
       /* If loop starts with a branch to the test, then fix it so that
         it points to the test of the first unrolled copy of the loop.  */
@@ -1469,10 +1495,11 @@ calculate_giv_inc (pattern, src_insn, regno)
       if (GET_CODE (increment) == LO_SUM)
        increment = XEXP (increment, 1);
       else if (GET_CODE (increment) == IOR
-              || GET_CODE (increment) == ASHIFT)
+              || GET_CODE (increment) == ASHIFT
+              || GET_CODE (increment) == PLUS)
        {
          /* The rs6000 port loads some constants with IOR.
-            The alpha port loads some constants with ASHIFT.  */
+            The alpha port loads some constants with ASHIFT and PLUS.  */
          rtx second_part = XEXP (increment, 1);
          enum rtx_code code = GET_CODE (increment);
 
@@ -1487,6 +1514,8 @@ calculate_giv_inc (pattern, src_insn, regno)
 
          if (code == IOR)
            increment = GEN_INT (INTVAL (increment) | INTVAL (second_part));
+         else if (code == PLUS)
+           increment = GEN_INT (INTVAL (increment) + INTVAL (second_part));
          else
            increment = GEN_INT (INTVAL (increment) << INTVAL (second_part));
        }
@@ -1691,7 +1720,7 @@ copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
                        /* Check for shared address givs, and avoid
                           incrementing the shared pseudo reg more than
                           once.  */
-                       if (! tv->same_insn)
+                       if (! tv->same_insn && ! tv->shared)
                          {
                            /* tv->dest_reg may actually be a (PLUS (REG)
                               (CONST)) here, so we must call plus_constant
@@ -1817,6 +1846,7 @@ copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
                      tem = gen_reg_rtx (GET_MODE (giv_src_reg));
                      giv_dest_reg = tem;
                      map->reg_map[regno] = tem;
+                     record_base_value (REGNO (tem), giv_src_reg);
                    }
                  else
                    map->reg_map[regno] = giv_src_reg;
@@ -2255,7 +2285,7 @@ biv_total_increment (bl, loop_start, loop_end)
    Initial_value and/or increment are set to zero if their values could not
    be calculated.  */
 
-static void
+void
 iteration_info (iteration_var, initial_value, increment, loop_start, loop_end)
      rtx iteration_var, *initial_value, *increment;
      rtx loop_start, loop_end;
@@ -2505,7 +2535,8 @@ find_splittable_regs (unroll_type, loop_start, loop_end, end_insert_before,
                      || ! invariant_p (bl->initial_value)))
                {
                  rtx tem = gen_reg_rtx (bl->biv->mode);
-                 
+
+                 record_base_value (REGNO (tem), bl->biv->add_val);
                  emit_insn_before (gen_move_insn (tem, bl->biv->src_reg),
                                    loop_start);
 
@@ -2562,6 +2593,8 @@ find_splittable_regs (unroll_type, loop_start, loop_end, end_insert_before,
                 this insn will always be executed, no matter how the loop
                 exits.  */
              rtx tem = gen_reg_rtx (bl->biv->mode);
+             record_base_value (REGNO (tem), bl->biv->add_val);
+
              emit_insn_before (gen_move_insn (tem, bl->biv->src_reg),
                                loop_start);
              emit_insn_before (gen_move_insn (bl->biv->src_reg,
@@ -2737,6 +2770,7 @@ find_splittable_givs (bl, unroll_type, loop_start, loop_end, increment,
            {
              rtx tem = gen_reg_rtx (bl->biv->mode);
 
+             record_base_value (REGNO (tem), bl->biv->add_val);
              emit_insn_before (gen_move_insn (tem, bl->biv->src_reg),
                                loop_start);
              biv_initial_value = tem;
@@ -2778,6 +2812,7 @@ find_splittable_givs (bl, unroll_type, loop_start, loop_end, increment,
                      || GET_CODE (XEXP (value, 1)) != CONST_INT))
                {
                  rtx tem = gen_reg_rtx (v->mode);
+                 record_base_value (REGNO (tem), v->add_val);
                  emit_iv_add_mult (bl->initial_value, v->mult_val,
                                    v->add_val, tem, loop_start);
                  value = tem;
@@ -2796,16 +2831,9 @@ find_splittable_givs (bl, unroll_type, loop_start, loop_end, increment,
                 what we want for split addr regs. We always create a new
                 register for the split addr giv, just to be safe.  */
 
-             /* ??? If there are multiple address givs which have been
-                combined with the same dest_reg giv, then we may only need
-                one new register for them.  Pulling out constants below will
-                catch some of the common cases of this.  Currently, I leave
-                the work of simplifying multiple address givs to the
-                following cse pass.  */
-             
-             /* As a special case, if we have multiple identical address givs
-                within a single instruction, then we do use a single pseudo
-                reg for both.  This is necessary in case one is a match_dup
+             /* If we have multiple identical address givs within a
+                single instruction, then use a single pseudo reg for
+                both.  This is necessary in case one is a match_dup
                 of the other.  */
 
              v->const_adjust = 0;
@@ -2818,12 +2846,33 @@ find_splittable_givs (bl, unroll_type, loop_start, loop_end, increment,
                             "Sharing address givs in insn %d\n",
                             INSN_UID (v->insn));
                }
+             /* If multiple address GIVs have been combined with the
+                same dest_reg GIV, do not create a new register for
+                each.  */
+             else if (unroll_type != UNROLL_COMPLETELY
+                      && v->giv_type == DEST_ADDR
+                      && v->same && v->same->giv_type == DEST_ADDR
+                      && v->same->unrolled
+                      /* combine_givs_p may return true for some cases
+                         where the add and mult values are not equal.
+                         To share a register here, the values must be
+                         equal.  */
+                      && rtx_equal_p (v->same->mult_val, v->mult_val)
+                      && rtx_equal_p (v->same->add_val, v->add_val))
+
+               {
+                 v->dest_reg = v->same->dest_reg;
+                 v->shared = 1;
+               }
              else if (unroll_type != UNROLL_COMPLETELY)
                {
                  /* If not completely unrolling the loop, then create a new
                     register to hold the split value of the DEST_ADDR giv.
                     Emit insn to initialize its value before loop start.  */
-                 tem = gen_reg_rtx (v->mode);
+
+                 rtx tem = gen_reg_rtx (v->mode);
+                 record_base_value (REGNO (tem), v->add_val);
+                 v->unrolled = 1;
 
                  /* If the address giv has a constant in its new_reg value,
                     then this constant can be pulled out and put in value,
@@ -2834,7 +2883,7 @@ find_splittable_givs (bl, unroll_type, loop_start, loop_end, increment,
                    {
                      v->dest_reg
                        = plus_constant (tem, INTVAL (XEXP (v->new_reg,1)));
-                     
+
                      /* Only succeed if this will give valid addresses.
                         Try to validate both the first and the last
                         address resulting from loop unrolling, if
@@ -3130,6 +3179,7 @@ final_biv_value (bl, loop_start, loop_end)
             case it is needed later.  */
 
          tem = gen_reg_rtx (bl->biv->mode);
+         record_base_value (REGNO (tem), bl->biv->add_val);
          /* Make sure loop_end is not the last insn.  */
          if (NEXT_INSN (loop_end) == 0)
            emit_note_after (NOTE_INSN_DELETED, loop_end);
@@ -3205,9 +3255,14 @@ final_giv_value (v, loop_start, loop_end)
         determine whether giv's are replaceable so that we can use the
         biv value here if it is not eliminable.  */
 
+      /* We are emitting code after the end of the loop, so we must make
+        sure that bl->initial_value is still valid then.  It will still
+        be valid if it is invariant.  */
+
       increment = biv_total_increment (bl, loop_start, loop_end);
 
-      if (increment && invariant_p (increment))
+      if (increment && invariant_p (increment)
+         && invariant_p (bl->initial_value))
        {
          /* Can calculate the loop exit value of its biv as
             (loop_n_iterations * increment) + initial_value */
@@ -3223,6 +3278,7 @@ final_giv_value (v, loop_start, loop_end)
 
          /* Put the final biv value in tem.  */
          tem = gen_reg_rtx (bl->biv->mode);
+         record_base_value (REGNO (tem), bl->biv->add_val);
          emit_iv_add_mult (increment, GEN_INT (loop_n_iterations),
                            bl->initial_value, tem, insert_before);