OSDN Git Service

* gcj.texi (Linking): New node. Document -lgij usage.
[pf3gnuchains/gcc-fork.git] / gcc / reorg.c
index 3d7159d..da4a1a0 100644 (file)
@@ -1,6 +1,6 @@
 /* Perform instruction reorganizations for delay slot filling.
    Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+   1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
    Contributed by Richard Kenner (kenner@vlsi1.ultra.nyu.edu).
    Hacked by Michael Tiemann (tiemann@cygnus.com).
 
@@ -36,19 +36,11 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
    cycle, and the Branch Penalty is 0.  Several RISC machines approach
    branch delays differently:
 
-   The MIPS and AMD 29000 have a single branch delay slot.  Most insns
+   The MIPS has a single branch delay slot.  Most insns
    (except other branches) can be used to fill this slot.  When the
    slot is filled, two insns execute in two cycles, reducing the
    branch penalty to zero.
 
-   The Motorola 88000 conditionally exposes its branch delay slot,
-   so code is shorter when it is turned off, but will run faster
-   when useful insns are scheduled there.
-
-   The IBM ROMP has two forms of branch and call insns, both with and
-   without a delay slot.  Much like the 88k, insns not using the delay
-   slot can be shorted (2 bytes vs. 4 bytes), but will run slowed.
-
    The SPARC always has a branch delay slot, but its effects can be
    annulled when the branch is not taken.  This means that failing to
    find other sources of insns, we can hoist an insn from the branch
@@ -84,8 +76,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
    `fill_eager_delay_slots' tries to guess the direction the branch
    will go; if it guesses right 100% of the time, it can reduce the
    branch penalty as much as `fill_simple_delay_slots' does.  If it
-   guesses wrong 100% of the time, it might as well schedule nops (or
-   on the m88k, unexpose the branch slot).  When
+   guesses wrong 100% of the time, it might as well schedule nops.  When
    `fill_eager_delay_slots' takes insns from the fall-through path of
    the jump, usually there is no code expansion; when it takes insns
    from the branch target, there is code expansion if it is not the
@@ -235,6 +226,12 @@ stop_search_p (rtx insn, int labels_p)
   if (insn == 0)
     return 1;
 
+  /* If the insn can throw an exception that is caught within the function,
+     it may effectively perform a jump from the viewpoint of the function.
+     Therefore act like for a jump.  */
+  if (can_throw_internal (insn))
+    return 1;
+
   switch (GET_CODE (insn))
     {
     case NOTE:
@@ -320,6 +317,20 @@ insn_sets_resource_p (rtx insn, struct resources *res,
   mark_set_resources (insn, &insn_sets, 0, include_delayed_effects);
   return resource_conflicts_p (&insn_sets, res);
 }
+
+/* Return TRUE if INSN is a return, possibly with a filled delay slot.  */
+
+static bool
+return_insn_p (rtx insn)
+{
+  if (GET_CODE (insn) == JUMP_INSN && GET_CODE (PATTERN (insn)) == RETURN)
+    return true;
+
+  if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SEQUENCE)
+    return return_insn_p (XVECEXP (PATTERN (insn), 0, 0));
+
+  return false;
+}
 \f
 /* Find a label at the end of the function or before a RETURN.  If there is
    none, make one.  */
@@ -347,15 +358,13 @@ find_end_label (void)
   /* When a target threads its epilogue we might already have a
      suitable return insn.  If so put a label before it for the
      end_of_function_label.  */
-  if (GET_CODE (insn) == BARRIER
-      && GET_CODE (PREV_INSN (insn)) == JUMP_INSN
-      && GET_CODE (PATTERN (PREV_INSN (insn))) == RETURN)
+  if (GET_CODE (insn) == BARRIER && return_insn_p (PREV_INSN (insn)))
     {
       rtx temp = PREV_INSN (PREV_INSN (insn));
       end_of_function_label = gen_label_rtx ();
       LABEL_NUSES (end_of_function_label) = 0;
 
-      /* Put the label before an USE insns that may proceed the RETURN insn.  */
+      /* Put the label before an USE insn that may precede the RETURN insn.  */
       while (GET_CODE (temp) == USE)
        temp = PREV_INSN (temp);
 
@@ -371,8 +380,7 @@ find_end_label (void)
       /* If the basic block reorder pass moves the return insn to
         some other place try to locate it again and put our
         end_of_function_label there.  */
-      while (insn && ! (GET_CODE (insn) == JUMP_INSN
-                       && (GET_CODE (PATTERN (insn)) == RETURN)))
+      while (insn && ! return_insn_p (insn))
        insn = PREV_INSN (insn);
       if (insn)
        {
@@ -573,6 +581,7 @@ delete_from_delay_slot (rtx insn)
   rtx trial, seq_insn, seq, prev;
   rtx delay_list = 0;
   int i;
+  int had_barrier = 0;
 
   /* We first must find the insn containing the SEQUENCE with INSN in its
      delay slot.  Do this by finding an insn, TRIAL, where
@@ -586,6 +595,9 @@ delete_from_delay_slot (rtx insn)
   seq_insn = PREV_INSN (NEXT_INSN (trial));
   seq = PATTERN (seq_insn);
 
+  if (NEXT_INSN (seq_insn) && GET_CODE (NEXT_INSN (seq_insn)) == BARRIER)
+    had_barrier = 1;
+
   /* Create a delay list consisting of all the insns other than the one
      we are deleting (unless we were the only one).  */
   if (XVECLEN (seq, 0) > 2)
@@ -600,8 +612,8 @@ delete_from_delay_slot (rtx insn)
   delete_related_insns (seq_insn);
   add_insn_after (trial, prev);
 
-  if (GET_CODE (trial) == JUMP_INSN
-      && (simplejump_p (trial) || GET_CODE (PATTERN (trial)) == RETURN))
+  /* If there was a barrier after the old SEQUENCE, remit it.  */
+  if (had_barrier)
     emit_barrier_after (trial);
 
   /* If there are any delay insns, remit them.  Otherwise clear the
@@ -1615,7 +1627,7 @@ try_merge_delay_insns (rtx insn, rtx thread)
    If we are not careful, this routine can take up a significant fraction
    of the total compilation time (4%), but only wins rarely.  Hence we
    speed this routine up by making two passes.  The first pass goes back
-   until it hits a label and sees if it find an insn with an identical
+   until it hits a label and sees if it finds an insn with an identical
    pattern.  Only in this (relatively rare) event does it check for
    data conflicts.
 
@@ -1923,7 +1935,7 @@ update_reg_dead_notes (rtx insn, rtx delayed_insn)
        next = XEXP (link, 1);
 
        if (REG_NOTE_KIND (link) != REG_DEAD
-           || GET_CODE (XEXP (link, 0)) != REG)
+           || !REG_P (XEXP (link, 0)))
          continue;
 
        if (reg_referenced_p (XEXP (link, 0), PATTERN (insn)))
@@ -1956,7 +1968,7 @@ fix_reg_dead_note (rtx start_insn, rtx stop_insn)
        next = XEXP (link, 1);
 
        if (REG_NOTE_KIND (link) != REG_DEAD
-           || GET_CODE (XEXP (link, 0)) != REG)
+           || !REG_P (XEXP (link, 0)))
          continue;
 
        if (reg_set_p (XEXP (link, 0), PATTERN (start_insn)))
@@ -1984,7 +1996,7 @@ update_reg_unused_notes (rtx insn, rtx redundant_insn)
       next = XEXP (link, 1);
 
       if (REG_NOTE_KIND (link) != REG_UNUSED
-         || GET_CODE (XEXP (link, 0)) != REG)
+         || !REG_P (XEXP (link, 0)))
        continue;
 
       if (! find_regno_note (redundant_insn, REG_UNUSED,
@@ -2352,7 +2364,9 @@ fill_simple_delay_slots (int non_jumps_p)
              && eligible_for_delay (insn, slots_filled, next_trial, flags)
              && ! can_throw_internal (trial))
            {
-             rtx new_label = next_active_insn (next_trial);
+             /* See comment in relax_delay_slots about necessity of using
+                next_real_insn here.  */
+             rtx new_label = next_real_insn (next_trial);
 
              if (new_label != 0)
                new_label = get_label_before (new_label);
@@ -2421,10 +2435,8 @@ fill_simple_delay_slots (int non_jumps_p)
 #if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM
       SET_HARD_REG_BIT (needed.regs, HARD_FRAME_POINTER_REGNUM);
 #endif
-#ifdef EXIT_IGNORE_STACK
       if (! EXIT_IGNORE_STACK
          || current_function_sp_is_unchanging)
-#endif
        SET_HARD_REG_BIT (needed.regs, STACK_POINTER_REGNUM);
     }
   else
@@ -2763,8 +2775,8 @@ fill_slots_from_thread (rtx insn, rtx condition, rtx thread,
         destination.  Overlap may happen for larger-than-register-size modes.  */
 
       if (GET_CODE (trial) == INSN && GET_CODE (pat) == SET
-         && GET_CODE (SET_SRC (pat)) == REG
-         && GET_CODE (SET_DEST (pat)) == REG
+         && REG_P (SET_SRC (pat))
+         && REG_P (SET_DEST (pat))
          && !reg_overlap_mentioned_p (SET_DEST (pat), SET_SRC (pat)))
        {
          rtx next = next_nonnote_insn (trial);
@@ -3078,9 +3090,7 @@ relax_delay_slots (rtx first)
          && (condjump_p (insn) || condjump_in_parallel_p (insn))
          && (target_label = JUMP_LABEL (insn)) != 0)
        {
-         target_label = follow_jumps (target_label);
-         target_label = prev_label (next_active_insn (target_label));
-
+         target_label = skip_consecutive_labels (follow_jumps (target_label));
          if (target_label == 0)
            target_label = find_end_label ();
 
@@ -3175,7 +3185,7 @@ relax_delay_slots (rtx first)
 
       /* See if we have a RETURN insn with a filled delay slot followed
         by a RETURN insn with an unfilled a delay slot.  If so, we can delete
-        the first RETURN (but not it's delay insn).  This gives the same
+        the first RETURN (but not its delay insn).  This gives the same
         effect in fewer instructions.
 
         Only do so if optimizing for size since this results in slower, but
@@ -3228,14 +3238,8 @@ relax_delay_slots (rtx first)
        {
          /* If this jump goes to another unconditional jump, thread it, but
             don't convert a jump into a RETURN here.  */
-         trial = follow_jumps (target_label);
-         /* We use next_real_insn instead of next_active_insn, so that
-            the special USE insns emitted by reorg won't be ignored.
-            If they are ignored, then they will get deleted if target_label
-            is now unreachable, and that would cause mark_target_live_regs
-            to fail.  */
-         trial = prev_label (next_real_insn (trial));
-         if (trial == 0 && target_label != 0)
+         trial = skip_consecutive_labels (follow_jumps (target_label));
+         if (trial == 0)
            trial = find_end_label ();
 
          if (trial != target_label
@@ -3282,10 +3286,18 @@ relax_delay_slots (rtx first)
            {
              target_label = JUMP_LABEL (XVECEXP (PATTERN (trial), 0, 0));
              if (target_label == 0)
-               target_label = find_end_label ();
+               {
+                 target_label = find_end_label ();
+                 /* The following condition may be true if TRIAL contains
+                    the unique RETURN.  In this case, threading would be
+                    a nop and we would enter an infinite loop if we did it.  */
+                 if (next_active_insn (target_label) == trial)
+                   target_label = 0;
+               }
 
-             if (redirect_with_delay_slots_safe_p (delay_insn, target_label,
-                                                   insn))
+             if (target_label
+                 && redirect_with_delay_slots_safe_p (delay_insn, target_label,
+                                                      insn))
                {
                  reorg_redirect_jump (delay_insn, target_label);
                  next = insn;
@@ -3618,7 +3630,7 @@ dbr_schedule (rtx first, FILE *file)
       if (GET_CODE (insn) == JUMP_INSN
          && (condjump_p (insn) || condjump_in_parallel_p (insn))
          && JUMP_LABEL (insn) != 0
-         && ((target = prev_label (next_active_insn (JUMP_LABEL (insn))))
+         && ((target = skip_consecutive_labels (JUMP_LABEL (insn)))
              != JUMP_LABEL (insn)))
        redirect_jump (insn, target, 1);
     }