OSDN Git Service

[pf3gnuchains/gcc-fork.git] / gcc / reorg.c
index 7370a35..375d4f8 100644 (file)
@@ -61,6 +61,10 @@ Boston, MA 02111-1307, USA.  */
    we can hoist insns from the fall-through path for forward branches or
    steal insns from the target of backward branches.
 
+   The TMS320C3x and C4x have three branch delay slots.  When the three
+   slots are filled, the branch penalty is zero.  Most insns can fill the
+   delay slots except jump insns.
+
    Three techniques for filling delay slots have been implemented so far:
 
    (1) `fill_simple_delay_slots' is the simplest, most efficient way
@@ -131,12 +135,6 @@ Boston, MA 02111-1307, USA.  */
 #include "obstack.h"
 #include "insn-attr.h"
 
-/* Import list of registers used as spill regs from reload.  */
-extern HARD_REG_SET used_spill_regs;
-
-/* Import highest label used in function at end of reload.  */
-extern int max_label_num_after_reload;
-
 
 #ifdef DELAY_SLOTS
 
@@ -234,7 +232,7 @@ static int insn_sets_resource_p PROTO((rtx, struct resources *, int));
 static rtx find_end_label      PROTO((void));
 static rtx emit_delay_sequence PROTO((rtx, rtx, int));
 static rtx add_to_delay_list   PROTO((rtx, rtx));
-static void delete_from_delay_slot PROTO((rtx));
+static rtx delete_from_delay_slot PROTO((rtx));
 static void delete_scheduled_jump PROTO((rtx));
 static void note_delay_statistics PROTO((int, int));
 static rtx optimize_skip       PROTO((rtx));
@@ -579,7 +577,7 @@ mark_set_resources (x, res, in_dest, include_delayed_effects)
            SET_HARD_REG_SET (res->regs);
        }
 
-      /* ... and also what it's RTL says it modifies, if anything.  */
+      /* ... and also what its RTL says it modifies, if anything.  */
 
     case JUMP_INSN:
     case INSN:
@@ -983,7 +981,7 @@ add_to_delay_list (insn, delay_list)
      rtx delay_list;
 {
   /* If we have an empty list, just make a new list element.  If
-     INSN has it's block number recorded, clear it since we may
+     INSN has its block number recorded, clear it since we may
      be moving the insn to a new block.  */
 
   if (delay_list == 0)
@@ -1011,7 +1009,7 @@ add_to_delay_list (insn, delay_list)
 /* Delete INSN from the delay slot of the insn that it is in.  This may
    produce an insn without anything in its delay slots.  */
 
-static void
+static rtx
 delete_from_delay_slot (insn)
      rtx insn;
 {
@@ -1060,6 +1058,8 @@ delete_from_delay_slot (insn)
 
   /* Show we need to fill this insn again.  */
   obstack_ptr_grow (&unfilled_slots_obstack, trial);
+
+  return trial;
 }
 \f
 /* Delete INSN, a JUMP_INSN.  If it is a conditional jump, we must track down
@@ -1377,7 +1377,7 @@ mostly_true_jump (jump_insn, condition)
      always gives a correct answer.  */
   if (flag_branch_probabilities)
     {
-      rtx note = find_reg_note (jump_insn, REG_BR_PROB, 0);;
+      rtx note = find_reg_note (jump_insn, REG_BR_PROB, 0);
       if (note)
        {
          int prob = XINT (note, 0);
@@ -1624,6 +1624,31 @@ redirect_with_delay_list_safe_p (jump, newlabel, delay_list)
   return (li == NULL);
 }
 
+/* DELAY_LIST is a list of insns that have already been placed into delay
+   slots.  See if all of them have the same annulling status as ANNUL_TRUE_P.
+   If not, return 0; otherwise return 1.  */
+
+static int
+check_annul_list_true_false (annul_true_p, delay_list)
+     int annul_true_p;
+     rtx delay_list;
+{
+  rtx temp;
+
+  if (delay_list)
+    {
+      for (temp = delay_list; temp; temp = XEXP (temp, 1))
+        {
+          rtx trial = XEXP (temp, 0);
+          if ((annul_true_p && INSN_FROM_TARGET_P (trial))
+             || (!annul_true_p && !INSN_FROM_TARGET_P (trial)))
+           return 0;
+        }
+    }
+  return 1;
+}
+
 \f
 /* INSN branches to an insn whose pattern SEQ is a SEQUENCE.  Given that
    the condition tested by INSN is CONDITION and the resources shown in
@@ -1665,6 +1690,8 @@ steal_delay_list_from_target (insn, condition, seq, delay_list,
   rtx new_delay_list = 0;
   int must_annul = *pannul_p;
   int i;
+  int used_annul = 0;
+  struct resources cc_set;
 
   /* We can't do anything if there are more delay slots in SEQ than we
      can handle, or if we don't know that it will be a taken branch.
@@ -1674,7 +1701,23 @@ steal_delay_list_from_target (insn, condition, seq, delay_list,
      Also, exit if the branch has more than one set, since then it is computing
      other results that can't be ignored, e.g. the HPPA mov&branch instruction.
      ??? It may be possible to move other sets into INSN in addition to
-     moving the instructions in the delay slots.  */
+     moving the instructions in the delay slots.
+
+     We can not steal the delay list if one of the instructions in the
+     current delay_list modifies the condition codes and the jump in the 
+     sequence is a conditional jump. We can not do this because we can
+     not change the direction of the jump because the condition codes
+     will effect the direction of the jump in the sequence. */
+
+  CLEAR_RESOURCE (&cc_set);
+  for (temp = delay_list; temp; temp = XEXP (temp, 1))
+    {
+      rtx trial = XEXP (temp, 0);
+
+      mark_set_resources (trial, &cc_set, 0, 1);
+      if (insn_references_resource_p (XVECEXP (seq , 0, 0), &cc_set, 0))
+        return delay_list;
+    }
 
   if (XVECLEN (seq, 0) - 1 > slots_remaining
       || ! condition_dominates_p (condition, XVECEXP (seq, 0, 0))
@@ -1714,9 +1757,15 @@ steal_delay_list_from_target (insn, condition, seq, delay_list,
               || (! insn_sets_resource_p (trial, other_needed, 0)
                   && ! may_trap_p (PATTERN (trial)))))
          ? eligible_for_delay (insn, total_slots_filled, trial, flags)
-         : (must_annul = 1,
-            eligible_for_annul_false (insn, total_slots_filled, trial, flags)))
+         : (must_annul || (delay_list == NULL && new_delay_list == NULL))
+            && (must_annul = 1,
+                check_annul_list_true_false (0, delay_list)
+                && check_annul_list_true_false (0, new_delay_list)
+                && eligible_for_annul_false (insn, total_slots_filled,
+                                             trial, flags)))
        {
+         if (must_annul)
+           used_annul = 1;
          temp = copy_rtx (trial);
          INSN_FROM_TARGET_P (temp) = 1;
          new_delay_list = add_to_delay_list (temp, new_delay_list);
@@ -1735,7 +1784,8 @@ steal_delay_list_from_target (insn, condition, seq, delay_list,
   /* Add any new insns to the delay list and update the count of the
      number of slots filled.  */
   *pslots_filled = total_slots_filled;
-  *pannul_p = must_annul;
+  if (used_annul)
+    *pannul_p = 1;
 
   if (delay_list == 0)
     return new_delay_list;
@@ -1765,6 +1815,8 @@ steal_delay_list_from_fallthrough (insn, condition, seq,
 {
   int i;
   int flags;
+  int must_annul = *pannul_p;
+  int used_annul = 0;
 
   flags = get_jump_flags (insn, JUMP_LABEL (insn));
 
@@ -1798,14 +1850,17 @@ steal_delay_list_from_fallthrough (insn, condition, seq,
          continue;
        }
 
-      if (! *pannul_p
+      if (! must_annul
          && ((condition == const_true_rtx
               || (! insn_sets_resource_p (trial, other_needed, 0)
                   && ! may_trap_p (PATTERN (trial)))))
          ? eligible_for_delay (insn, *pslots_filled, trial, flags)
-         : (*pannul_p = 1,
-            eligible_for_annul_true (insn, *pslots_filled, trial, flags)))
+         : (must_annul || delay_list == NULL) && (must_annul = 1,
+            check_annul_list_true_false (1, delay_list)
+            && eligible_for_annul_true (insn, *pslots_filled, trial, flags)))
        {
+         if (must_annul)
+           used_annul = 1;
          delete_from_delay_slot (trial);
          delay_list = add_to_delay_list (trial, delay_list);
 
@@ -1816,8 +1871,11 @@ steal_delay_list_from_fallthrough (insn, condition, seq,
        break;
     }
 
+  if (used_annul)
+    *pannul_p = 1;
   return delay_list;
 }
+
 \f
 /* Try merging insns starting at THREAD which match exactly the insns in
    INSN's delay list.
@@ -1849,13 +1907,15 @@ try_merge_delay_insns (insn, thread)
   CLEAR_RESOURCE (&set);
 
   /* If this is not an annulling branch, take into account anything needed in
-     NEXT_TO_MATCH.  This prevents two increments from being incorrectly
+     INSN's delay slot.  This prevents two increments from being incorrectly
      folded into one.  If we are annulling, this would be the correct
      thing to do.  (The alternative, looking at things set in NEXT_TO_MATCH
      will essentially disable this optimization.  This method is somewhat of
      a kludge, but I don't see a better way.)  */
   if (! annul_p)
-    mark_referenced_resources (next_to_match, &needed, 1);
+    for (i = 1 ; i < num_slots ; i++)
+      if (XVECEXP (PATTERN (insn), 0, i))
+        mark_referenced_resources (XVECEXP (PATTERN (insn), 0, i), &needed, 1);
 
   for (trial = thread; !stop_search_p (trial, 1); trial = next_trial)
     {
@@ -1904,8 +1964,6 @@ try_merge_delay_insns (insn, thread)
            break;
 
          next_to_match = XVECEXP (PATTERN (insn), 0, slot_number);
-         if (! annul_p)
-           mark_referenced_resources (next_to_match, &needed, 1);
        }
 
       mark_set_resources (trial, &set, 0, 1);
@@ -1941,8 +1999,12 @@ try_merge_delay_insns (insn, thread)
            {
              if (! annul_p)
                {
+                 rtx new;
+
                  update_block (dtrial, thread);
-                 delete_from_delay_slot (dtrial);
+                 new = delete_from_delay_slot (dtrial);
+                 if (INSN_DELETED_P (thread))
+                   thread = new;
                  INSN_FROM_TARGET_P (next_to_match) = 0;
                }
              else
@@ -1954,6 +2016,13 @@ try_merge_delay_insns (insn, thread)
 
              next_to_match = XVECEXP (PATTERN (insn), 0, slot_number);
            }
+         else
+           {
+             /* Keep track of the set/referenced resources for the delay
+                slots of any trial insns we encounter.  */
+              mark_set_resources (dtrial, &set, 0, 1);
+              mark_referenced_resources (dtrial, &needed, 1);
+           }
        }
     }
 
@@ -1968,8 +2037,12 @@ try_merge_delay_insns (insn, thread)
        {
          if (GET_MODE (merged_insns) == SImode)
            {
+             rtx new;
+
              update_block (XEXP (merged_insns, 0), thread);
-             delete_from_delay_slot (XEXP (merged_insns, 0));
+             new = delete_from_delay_slot (XEXP (merged_insns, 0));
+             if (INSN_DELETED_P (thread))
+               thread = new;
            }
          else
            {
@@ -2526,14 +2599,6 @@ find_dead_or_set_registers (target, res, jump_target, jump_count, set, needed)
          AND_COMPL_HARD_REG_SET (res->regs, pending_dead_regs);
          CLEAR_HARD_REG_SET (pending_dead_regs);
 
-         if (CODE_LABEL_NUMBER (insn) < max_label_num_after_reload)
-           {
-             /* All spill registers are dead at a label, so kill all of the
-                ones that aren't needed also.  */
-             COPY_HARD_REG_SET (scratch, used_spill_regs);
-             AND_COMPL_HARD_REG_SET (scratch, needed.regs);
-             AND_COMPL_HARD_REG_SET (res->regs, scratch);
-           }
          continue;
 
        case BARRIER:
@@ -3022,8 +3087,20 @@ fill_simple_delay_slots (non_jumps_p)
       else
        flags = get_jump_flags (insn, NULL_RTX);
       slots_to_fill = num_delay_slots (insn);
+
+      /* Some machine description have defined instructions to have
+        delay slots only in certain circumstances which may depend on
+        nearby insns (which change due to reorg's actions).
+
+        For example, the PA port normally has delay slots for unconditional
+        jumps.
+
+        However, the PA port claims such jumps do not have a delay slot
+        if they are immediate successors of certain CALL_INSNs.  This
+        allows the port to favor filling the delay slot of the call with
+        the unconditional jump.  */
       if (slots_to_fill == 0)
-       abort ();
+       continue;
 
       /* This insn needs, or can use, some delay slots.  SLOTS_TO_FILL
         says how many.  After initialization, first try optimizing
@@ -3119,7 +3196,7 @@ fill_simple_delay_slots (non_jumps_p)
 #ifdef HAVE_cc0
                  /* Can't separate set of cc0 from its use.  */
                  && ! (reg_mentioned_p (cc0_rtx, pat)
-                       && ! sets_cc0_p (cc0_rtx, pat))
+                       && ! sets_cc0_p (pat))
 #endif
                  )
                {
@@ -3382,7 +3459,8 @@ fill_simple_delay_slots (non_jumps_p)
       SET_HARD_REG_BIT (needed.regs, HARD_FRAME_POINTER_REGNUM);
 #endif
 #ifdef EXIT_IGNORE_STACK
-      if (! EXIT_IGNORE_STACK)
+      if (! EXIT_IGNORE_STACK
+         || current_function_sp_is_unchanging)
 #endif
        SET_HARD_REG_BIT (needed.regs, STACK_POINTER_REGNUM);
     }
@@ -3588,9 +3666,10 @@ fill_slots_from_thread (insn, condition, thread, opposite_thread, likely,
          /* There are two ways we can win:  If TRIAL doesn't set anything
             needed at the opposite thread and can't trap, or if it can
             go into an annulled delay slot.  */
-         if (condition == const_true_rtx
-             || (! insn_sets_resource_p (trial, &opposite_needed, 1)
-                 && ! may_trap_p (pat)))
+         if (!must_annul
+             && (condition == const_true_rtx
+                 || (! insn_sets_resource_p (trial, &opposite_needed, 1)
+                     && ! may_trap_p (pat))))
            {
              old_trial = trial;
              trial = try_split (pat, trial, 0);
@@ -3618,9 +3697,11 @@ fill_slots_from_thread (insn, condition, thread, opposite_thread, likely,
              if (thread == old_trial)
                thread = trial;
              pat = PATTERN (trial);
-             if ((thread_if_true
-                  ? eligible_for_annul_false (insn, *pslots_filled, trial, flags)
-                  : eligible_for_annul_true (insn, *pslots_filled, trial, flags)))
+             if ((must_annul || delay_list == NULL) && (thread_if_true
+                  ? check_annul_list_true_false (0, delay_list)
+                    && eligible_for_annul_false (insn, *pslots_filled, trial, flags)
+                  : check_annul_list_true_false (1, delay_list)
+                    && eligible_for_annul_true (insn, *pslots_filled, trial, flags)))
                {
                  rtx temp;
 
@@ -3656,8 +3737,6 @@ fill_slots_from_thread (insn, condition, thread, opposite_thread, likely,
 
                  delay_list = add_to_delay_list (temp, delay_list);
 
-                 mark_set_resources (trial, &opposite_needed, 0, 1);
-
                  if (slots_to_fill == ++(*pslots_filled))
                    {
                      /* Even though we have filled all the slots, we
@@ -3735,9 +3814,7 @@ fill_slots_from_thread (insn, condition, thread, opposite_thread, likely,
     {
       /* If this is the `true' thread, we will want to follow the jump,
         so we can only do this if we have taken everything up to here.  */
-      if (thread_if_true && trial == new_thread
-         && ! insn_references_resource_p (XVECEXP (PATTERN (trial), 0, 0),
-                                          &opposite_needed, 0))
+      if (thread_if_true && trial == new_thread)
        delay_list
          = steal_delay_list_from_target (insn, condition, PATTERN (trial),
                                          delay_list, &set, &needed,
@@ -3798,8 +3875,7 @@ fill_slots_from_thread (insn, condition, thread, opposite_thread, likely,
                                   insn);
 
          if (recog_memoized (ninsn) < 0
-             || (insn_extract (ninsn),
-                 ! constrain_operands (INSN_CODE (ninsn), 1)))
+             || (extract_insn (ninsn), ! constrain_operands (1)))
            {
              delete_insn (ninsn);
              return 0;
@@ -3896,8 +3972,19 @@ fill_eager_delay_slots ()
        continue;
 
       slots_to_fill = num_delay_slots (insn);
+      /* Some machine description have defined instructions to have
+        delay slots only in certain circumstances which may depend on
+        nearby insns (which change due to reorg's actions).
+
+        For example, the PA port normally has delay slots for unconditional
+        jumps.
+
+        However, the PA port claims such jumps do not have a delay slot
+        if they are immediate successors of certain CALL_INSNs.  This
+        allows the port to favor filling the delay slot of the call with
+        the unconditional jump.  */
       if (slots_to_fill == 0)
-       abort ();
+        continue;
 
       slots_filled = 0;
       target_label = JUMP_LABEL (insn);
@@ -4076,7 +4163,7 @@ relax_delay_slots (first)
          && (other = prev_active_insn (insn)) != 0
          && (condjump_p (other) || condjump_in_parallel_p (other))
          && no_labels_between_p (other, insn)
-         && 0 < mostly_true_jump (other,
+         && 0 > mostly_true_jump (other,
                                   get_branch_condition (other,
                                                         JUMP_LABEL (other))))
        {
@@ -4113,6 +4200,40 @@ relax_delay_slots (first)
          continue;
        }
 
+      /* 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
+        effect in fewer instructions.
+
+        Only do so if optimizing for size since this results in slower, but
+        smaller code.  */
+      if (optimize_size
+         && GET_CODE (PATTERN (delay_insn)) == RETURN
+         && next
+         && GET_CODE (next) == JUMP_INSN
+         && GET_CODE (PATTERN (next)) == RETURN)
+       {
+         int i;
+
+         /* Delete the RETURN and just execute the delay list insns.
+
+            We do this by deleting the INSN containing the SEQUENCE, then
+            re-emitting the insns separately, and then deleting the RETURN.
+            This allows the count of the jump target to be properly
+            decremented.  */
+
+         /* Clear the from target bit, since these insns are no longer
+            in delay slots.  */
+         for (i = 0; i < XVECLEN (pat, 0); i++)
+           INSN_FROM_TARGET_P (XVECEXP (pat, 0, i)) = 0;
+
+         trial = PREV_INSN (insn);
+         delete_insn (insn);
+         emit_insn_after (pat, trial);
+         delete_scheduled_jump (delay_insn);
+         continue;
+       }
+
       /* Now look only at the cases where we have a filled JUMP_INSN.  */
       if (GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) != JUMP_INSN
          || ! (condjump_p (XVECEXP (PATTERN (insn), 0, 0))
@@ -4463,7 +4584,7 @@ dbr_schedule (first, file)
        epilogue_insn = insn;
     }
 
-  uid_to_ruid = (int *) alloca ((max_uid + 1) * sizeof (int *));
+  uid_to_ruid = (int *) alloca ((max_uid + 1) * sizeof (int));
   for (i = 0, insn = first; insn; i++, insn = NEXT_INSN (insn))
     uid_to_ruid[INSN_UID (insn)] = i;
   
@@ -4518,7 +4639,8 @@ dbr_schedule (first, file)
       SET_HARD_REG_BIT (end_of_function_needs.regs, HARD_FRAME_POINTER_REGNUM);
 #endif
 #ifdef EXIT_IGNORE_STACK
-      if (! EXIT_IGNORE_STACK)
+      if (! EXIT_IGNORE_STACK
+         || current_function_sp_is_unchanging)
 #endif
        SET_HARD_REG_BIT (end_of_function_needs.regs, STACK_POINTER_REGNUM);
     }
@@ -4660,6 +4782,13 @@ dbr_schedule (first, file)
     {
       int pred_flags;
 
+      if (GET_CODE (insn) == INSN)
+        {
+         rtx pat = PATTERN (insn);
+
+         if (GET_CODE (pat) == SEQUENCE)
+           insn = XVECEXP (pat, 0, 0);
+       }
       if (GET_CODE (insn) != JUMP_INSN)
        continue;