OSDN Git Service

(c_sizeof, build_c_cast): Set TREE_OVERFLOW in addition
[pf3gnuchains/gcc-fork.git] / gcc / unroll.c
index 9ff78f4..fc8a3f6 100644 (file)
@@ -1,5 +1,5 @@
 /* Try to unroll loops, and split induction variables.
-   Copyright (C) 1992 Free Software Foundation, Inc.
+   Copyright (C) 1992, 1993 Free Software Foundation, Inc.
    Contributed by James E. Wilson, Cygnus Support/UC Berkeley.
 
 This file is part of GNU CC.
@@ -620,6 +620,8 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
 
   map = (struct inline_remap *) alloca (sizeof (struct inline_remap));
 
+  map->integrating = 0;
+
   /* Allocate the label map.  */
 
   if (max_labelno > 0)
@@ -1316,7 +1318,10 @@ calculate_giv_inc (pattern, src_insn, regno)
      int regno;
 {
   rtx increment;
+  rtx increment_total = 0;
+  int tries = 0;
 
+ retry:
   /* Verify that we have an increment insn here.  First check for a plus
      as the set source.  */
   if (GET_CODE (SET_SRC (pattern)) != PLUS)
@@ -1339,7 +1344,8 @@ calculate_giv_inc (pattern, src_insn, regno)
     {
       /* SR sometimes puts the constant in a register, especially if it is
         too big to be an add immed operand.  */
-      increment = SET_SRC (PATTERN (PREV_INSN (src_insn)));
+      src_insn = PREV_INSN (src_insn);
+      increment = SET_SRC (PATTERN (src_insn));
 
       /* SR may have used LO_SUM to compute the constant if it is too large
         for a load immed operand.  In this case, the constant is in operand
@@ -1355,14 +1361,81 @@ calculate_giv_inc (pattern, src_insn, regno)
       delete_insn (get_last_insn ());
     }
 
-  /* Check that the source register is the same as the dest register.  */
+  if (increment_total)
+    increment_total = GEN_INT (INTVAL (increment_total) + INTVAL (increment));
+  else
+    increment_total = increment;
+
+  /* Check that the source register is the same as the register we expected
+     to see as the source.  If not, something is seriously wrong.  */
   if (GET_CODE (XEXP (SET_SRC (pattern), 0)) != REG
       || REGNO (XEXP (SET_SRC (pattern), 0)) != regno)
+    {
+      /* Some machines (e.g. the romp), may emit two add instructions for
+        certain constants, so lets try looking for another add immediately
+        before this one if we have only seen one add insn so far.  */
+
+      if (tries == 0)
+       {
+         tries++;
+
+         src_insn = PREV_INSN (src_insn);
+         pattern = PATTERN (src_insn);
+
+         delete_insn (get_last_insn ());
+
+         goto retry;
+       }
+
+      abort ();
+    }
+
+  return increment_total;
+}
+
+/* Copy REG_NOTES, except for insn references, because not all insn_map
+   entries are valid yet.  We do need to copy registers now though, because
+   the reg_map entries can change during copying.  */
+
+static rtx
+initial_reg_note_copy (notes, map)
+     rtx notes;
+     struct inline_remap *map;
+{
+  rtx copy;
+
+  if (notes == 0)
+    return 0;
+
+  copy = rtx_alloc (GET_CODE (notes));
+  PUT_MODE (copy, GET_MODE (notes));
+
+  if (GET_CODE (notes) == EXPR_LIST)
+    XEXP (copy, 0) = copy_rtx_and_substitute (XEXP (notes, 0), map);
+  else if (GET_CODE (notes) == INSN_LIST)
+    /* Don't substitute for these yet.  */
+    XEXP (copy, 0) = XEXP (notes, 0);
+  else
     abort ();
 
-  return increment;
+  XEXP (copy, 1) = initial_reg_note_copy (XEXP (notes, 1), map);
+
+  return copy;
 }
 
+/* Fixup insn references in copied REG_NOTES.  */
+
+static void
+final_reg_note_copy (notes, map)
+     rtx notes;
+     struct inline_remap *map;
+{
+  rtx note;
+
+  for (note = notes; note; note = XEXP (note, 1))
+    if (GET_CODE (note) == INSN_LIST)
+      XEXP (note, 0) = map->insn_map[INSN_UID (XEXP (note, 0))];
+}
 
 /* Copy each instruction in the loop, substituting from map as appropriate.
    This is very similar to a loop in expand_inline_function.  */
@@ -1373,6 +1446,7 @@ copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
                copy_notes_from)
      rtx copy_start, copy_end;
      struct inline_remap *map;
+     rtx exit_label;
      int last_iteration;
      enum unroll_types unroll_type;
      rtx start_label, loop_end, insert_before, copy_notes_from;
@@ -1608,7 +1682,7 @@ copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
              pattern = copy_rtx_and_substitute (pattern, map);
              copy = emit_insn (pattern);
            }
-         /* REG_NOTES will be copied later.  */
+         REG_NOTES (copy) = initial_reg_note_copy (REG_NOTES (insn), map);
          
 #ifdef HAVE_cc0
          /* If this insn is setting CC0, it may need to look at
@@ -1650,6 +1724,10 @@ copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
          break;
          
        case JUMP_INSN:
+         pattern = copy_rtx_and_substitute (PATTERN (insn), map);
+         copy = emit_jump_insn (pattern);
+         REG_NOTES (copy) = initial_reg_note_copy (REG_NOTES (insn), map);
+
          if (JUMP_LABEL (insn) == start_label && insn == copy_end
              && ! last_iteration)
            {
@@ -1659,26 +1737,13 @@ copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
                 case to be a branch past the end of the loop, and the
                 original jump label case to fall_through.  */
 
-             int fall_through;
-
-             /* Never map the label in this case.  */
-             rtx tmp_pattern = copy_rtx (PATTERN (insn));
-             
-             /* Set the fall through case to the exit label.  If we 
-                can't do this in place, abort for now.  Maybe
-                we can do something more sophisticated eventually.  */
-
-             if (! invert_exp (tmp_pattern, insn)
-                 || ! redirect_exp (&tmp_pattern, JUMP_LABEL (insn),
-                                    exit_label, insn))
+             if (! invert_exp (pattern, copy)
+                 || ! redirect_exp (&pattern,
+                                    map->label_map[CODE_LABEL_NUMBER
+                                                   (JUMP_LABEL (insn))],
+                                    exit_label, copy))
                abort ();
-
-             pattern = tmp_pattern;
            }
-         else
-           pattern = copy_rtx_and_substitute (PATTERN (insn), map);
-         
-         copy = emit_jump_insn (pattern);
          
 #ifdef HAVE_cc0
          if (cc0_insn)
@@ -1691,23 +1756,26 @@ copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
             later passes of unroll_loop, if INSN had jump label set.  */
          if (JUMP_LABEL (insn))
            {
+             rtx label = 0;
+
              /* Can't use the label_map for every insn, since this may be
                 the backward branch, and hence the label was not mapped.  */
              if (GET_CODE (pattern) == SET)
                {
                  tem = SET_SRC (pattern);
                  if (GET_CODE (tem) == LABEL_REF)
-                   JUMP_LABEL (copy) = XEXP (tem, 0);
+                   label = XEXP (tem, 0);
                  else if (GET_CODE (tem) == IF_THEN_ELSE)
                    {
                      if (XEXP (tem, 1) != pc_rtx)
-                       JUMP_LABEL (copy) = XEXP (XEXP (tem, 1), 0);
+                       label = XEXP (XEXP (tem, 1), 0);
                      else
-                       JUMP_LABEL (copy) = XEXP (XEXP (tem, 2), 0);
+                       label = XEXP (XEXP (tem, 2), 0);
                    }
-                 else
-                   abort ();
                }
+
+             if (label && GET_CODE (label) == CODE_LABEL)
+               JUMP_LABEL (copy) = label;
              else
                {
                  /* An unrecognizable jump insn, probably the entry jump
@@ -1760,6 +1828,7 @@ copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
        case CALL_INSN:
          pattern = copy_rtx_and_substitute (PATTERN (insn), map);
          copy = emit_call_insn (pattern);
+         REG_NOTES (copy) = initial_reg_note_copy (REG_NOTES (insn), map);
 
 #ifdef HAVE_cc0
          if (cc0_insn)
@@ -1810,7 +1879,7 @@ copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
     }
   while (insn != copy_end);
   
-  /* Now copy the REG_NOTES.  */
+  /* Now finish coping the REG_NOTES.  */
   insn = copy_start;
   do
     {
@@ -1818,8 +1887,7 @@ copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
       if ((GET_CODE (insn) == INSN || GET_CODE (insn) == JUMP_INSN
           || GET_CODE (insn) == CALL_INSN)
          && map->insn_map[INSN_UID (insn)])
-       REG_NOTES (map->insn_map[INSN_UID (insn)])
-         = copy_rtx_and_substitute (REG_NOTES (insn), map);
+       final_reg_note_copy (REG_NOTES (map->insn_map[INSN_UID (insn)]), map);
     }
   while (insn != copy_end);
 
@@ -2178,6 +2246,7 @@ find_splittable_regs (unroll_type, loop_start, loop_end, end_insert_before,
      int unroll_number;
 {
   struct iv_class *bl;
+  struct induction *v;
   rtx increment, tem;
   rtx biv_final_value;
   int biv_splittable;
@@ -2215,6 +2284,15 @@ find_splittable_regs (unroll_type, loop_start, loop_end, end_insert_before,
          && ! (biv_final_value = final_biv_value (bl, loop_start, loop_end)))
        biv_splittable = 0;
 
+      /* If any of the insns setting the BIV don't do so with a simple
+        PLUS, we don't know how to split it.  */
+      for (v = bl->biv; biv_splittable && v; v = v->next_iv)
+       if ((tem = single_set (v->insn)) == 0
+           || GET_CODE (SET_DEST (tem)) != REG
+           || REGNO (SET_DEST (tem)) != bl->regno
+           || GET_CODE (SET_SRC (tem)) != PLUS)
+         biv_splittable = 0;
+
       /* If final value is non-zero, then must emit an instruction which sets
         the value of the biv to the proper value.  This is done after
         handling all of the givs, since some of them may need to use the
@@ -2414,11 +2492,31 @@ find_splittable_givs (bl, unroll_type, loop_start, loop_end, increment,
         giv's initial value.  Otherwise, save the constant zero for it.  */
 
       if (unroll_type == UNROLL_COMPLETELY)
-       /* It is not safe to use bl->initial_value here, because it may not
-          be invariant.  It is safe to use the initial value stored in
-          the splittable_regs array.  */
-       value = fold_rtx_mult_add (v->mult_val, splittable_regs[bl->regno],
-                                  v->add_val, v->mode);
+       {
+         /* It is not safe to use bl->initial_value here, because it may not
+            be invariant.  It is safe to use the initial value stored in
+            the splittable_regs array if it is set.  In rare cases, it won't
+            be set, so then we do exactly the same thing as
+            find_splittable_regs does to get a safe value.  */
+         rtx biv_initial_value;
+
+         if (splittable_regs[bl->regno])
+           biv_initial_value = splittable_regs[bl->regno];
+         else if (GET_CODE (bl->initial_value) != REG
+                  || (REGNO (bl->initial_value) != bl->regno
+                      && REGNO (bl->initial_value) >= FIRST_PSEUDO_REGISTER))
+           biv_initial_value = bl->initial_value;
+         else
+           {
+             rtx tem = gen_reg_rtx (bl->biv->mode);
+
+             emit_insn_before (gen_move_insn (tem, bl->biv->src_reg),
+                               loop_start);
+             biv_initial_value = tem;
+           }
+         value = fold_rtx_mult_add (v->mult_val, biv_initial_value,
+                                    v->add_val, v->mode);
+       }
       else
        value = const0_rtx;
 
@@ -2500,8 +2598,8 @@ find_splittable_givs (bl, unroll_type, loop_start, loop_end, increment,
                         Try to validate both the first and the last
                         address resulting from loop unrolling, if
                         one fails, then can't do const elim here.  */
-                     if (memory_address_p (v->mode, v->dest_reg)
-                         && memory_address_p (v->mode,
+                     if (memory_address_p (v->mem_mode, v->dest_reg)
+                         && memory_address_p (v->mem_mode,
                                       plus_constant (v->dest_reg,
                                                      INTVAL (giv_inc)
                                                      * (unroll_number - 1))))
@@ -2527,8 +2625,8 @@ find_splittable_givs (bl, unroll_type, loop_start, loop_end, increment,
                     now, and fail completely if either the first or the last
                     unrolled copy of the address is not a valid address.  */
                  if (v->dest_reg == tem
-                     && (! memory_address_p (v->mode, v->dest_reg)
-                         || ! memory_address_p (v->mode,
+                     && (! memory_address_p (v->mem_mode, v->dest_reg)
+                         || ! memory_address_p (v->mem_mode,
                                 plus_constant (v->dest_reg,
                                                INTVAL (giv_inc)
                                                * (unroll_number -1)))))
@@ -2548,7 +2646,7 @@ find_splittable_givs (bl, unroll_type, loop_start, loop_end, increment,
                  emit_insn_before (gen_rtx (SET, VOIDmode, tem,
                                             copy_rtx (v->new_reg)),
                                    loop_start);
-                 if (! recog_memoized (PREV_INSN (loop_start)))
+                 if (recog_memoized (PREV_INSN (loop_start)) < 0)
                    {
                      delete_insn (PREV_INSN (loop_start));
                      emit_iv_add_mult (bl->initial_value, v->mult_val,
@@ -2564,8 +2662,8 @@ find_splittable_givs (bl, unroll_type, loop_start, loop_end, increment,
                  
                  /* Check the resulting address for validity, and fail
                     if the resulting address would be illegal.  */
-                 if (! memory_address_p (v->mode, v->dest_reg)
-                     || ! memory_address_p (v->mode,
+                 if (! memory_address_p (v->mem_mode, v->dest_reg)
+                     || ! memory_address_p (v->mem_mode,
                                     plus_constant (v->dest_reg,
                                                    INTVAL (giv_inc) *
                                                    (unroll_number -1))))
@@ -2769,6 +2867,9 @@ final_biv_value (bl, loop_start, loop_end)
             case it is needed later.  */
 
          tem = gen_reg_rtx (bl->biv->mode);
+         /* Make sure loop_end is not the last insn.  */
+         if (NEXT_INSN (loop_end) == 0)
+           emit_note_after (NOTE_INSN_DELETED, loop_end);
          emit_iv_add_mult (increment, GEN_INT (loop_n_iterations),
                            bl->initial_value, tem, NEXT_INSN (loop_end));
 
@@ -2803,7 +2904,7 @@ final_giv_value (v, loop_start, loop_end)
      rtx loop_start, loop_end;
 {
   struct iv_class *bl;
-  rtx reg, insn, pattern;
+  rtx insn;
   rtx increment, tem;
   enum rtx_code code;
   rtx insert_before, seq;
@@ -2867,31 +2968,19 @@ final_giv_value (v, loop_start, loop_end)
          for (insn = NEXT_INSN (v->insn); insn != loop_end;
               insn = NEXT_INSN (insn))
            {
-             if (GET_CODE (insn) == INSN
-                 && GET_CODE (PATTERN (insn)) == SET
-                 && SET_DEST (PATTERN (insn)) == v->src_reg)
-               {
-                 pattern = PATTERN (insn);
-                 if (GET_CODE (SET_SRC (pattern)) != PLUS)
-                   {
-                     /* Sometimes a biv is computed in a temp reg,
-                        and then copied into the biv reg.  */
-                     pattern = PATTERN (PREV_INSN (insn));
-                     if (GET_CODE (SET_SRC (pattern)) != PLUS)
-                       abort ();
-                   }
-                 if (GET_CODE (XEXP (SET_SRC (pattern), 0)) != REG
-                     || REGNO (XEXP (SET_SRC (pattern), 0)) != bl->regno)
-                   abort ();
-                 
-                 start_sequence ();
-                 tem = expand_binop (GET_MODE (tem), sub_optab, tem,
-                                     XEXP (SET_SRC (pattern), 1), NULL_RTX, 0,
-                                     OPTAB_LIB_WIDEN);
-                 seq = gen_sequence ();
-                 end_sequence ();
-                 emit_insn_before (seq, insert_before);
-               }
+             struct induction *biv;
+
+             for (biv = bl->biv; biv; biv = biv->next_iv)
+               if (biv->insn == insn)
+                 {
+                   start_sequence ();
+                   tem = expand_binop (GET_MODE (tem), sub_optab, tem,
+                                       biv->add_val, NULL_RTX, 0,
+                                       OPTAB_LIB_WIDEN);
+                   seq = gen_sequence ();
+                   end_sequence ();
+                   emit_insn_before (seq, insert_before);
+                 }
            }
          
          /* Now calculate the giv's final value.  */
@@ -3024,14 +3113,19 @@ loop_iterations (loop_start, loop_end)
            break;
 
          else if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
-                  && (set = single_set (insn))
-                  && (SET_DEST (set) == comparison_value))
+                  && reg_set_p (comparison_value, insn))
            {
-             rtx note = find_reg_note (insn, REG_EQUAL, NULL_RTX);
-
-             if (note && GET_CODE (XEXP (note, 0)) != EXPR_LIST)
-               comparison_value = XEXP (note, 0);
+             /* We found the last insn before the loop that sets the register.
+                If it sets the entire register, and has a REG_EQUAL note,
+                then use the value of the REG_EQUAL note.  */
+             if ((set = single_set (insn))
+                 && (SET_DEST (set) == comparison_value))
+               {
+                 rtx note = find_reg_note (insn, REG_EQUAL, NULL_RTX);
 
+                 if (note && GET_CODE (XEXP (note, 0)) != EXPR_LIST)
+                   comparison_value = XEXP (note, 0);
+               }
              break;
            }
        }