OSDN Git Service

Declare __fixunsxfdi.
[pf3gnuchains/gcc-fork.git] / gcc / reorg.c
index 83bbdda..9806216 100644 (file)
@@ -1,5 +1,5 @@
 /* Perform instruction reorganizations for delay slot filling.
-   Copyright (C) 1992 Free Software Foundation, Inc.
+   Copyright (C) 1992, 1993 Free Software Foundation, Inc.
    Contributed by Richard Kenner (kenner@nyu.edu).
    Hacked by Michael Tiemann (tiemann@cygnus.com).
 
@@ -248,6 +248,7 @@ static int redundant_insn_p PROTO((rtx, rtx, rtx));
 static int own_thread_p                PROTO((rtx, rtx, int));
 static int find_basic_block    PROTO((rtx));
 static void update_block       PROTO((rtx, rtx));
+static int reorg_redirect_jump PROTO((rtx, rtx));
 static void update_reg_dead_notes PROTO((rtx, rtx));
 static void update_live_status PROTO((rtx, rtx));
 static rtx next_insn_no_annul  PROTO((rtx));
@@ -737,8 +738,26 @@ find_end_label ()
                 || GET_CODE (PATTERN (insn)) == CLOBBER)))
     insn = PREV_INSN (insn);
 
-  if (GET_CODE (insn) == CODE_LABEL)
-   end_of_function_label = insn;
+  /* 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)
+    {
+      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. */
+      while (GET_CODE (temp) == USE)
+       temp = PREV_INSN (temp);
+
+      emit_label_after (end_of_function_label, temp);
+    }
+
+  else if (GET_CODE (insn) == CODE_LABEL)
+    end_of_function_label = insn;
   else
     {
       /* Otherwise, make a new label and emit a RETURN and BARRIER,
@@ -750,8 +769,8 @@ find_end_label ()
       if (HAVE_return)
        {
          /* The return we make may have delay slots too.  */
-         rtx insn = gen_return();
-         emit_jump_insn (insn);
+         rtx insn = gen_return ();
+         insn = emit_jump_insn (insn);
          emit_barrier ();
           if (num_delay_slots (insn) > 0)
            obstack_ptr_grow (&unfilled_slots_obstack, insn);
@@ -879,9 +898,24 @@ add_to_delay_list (insn, delay_list)
      rtx insn;
      rtx delay_list;
 {
-  /* If we have an empty list, just make a new list element.  */
+  /* 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
+     be moving the insn to a new block.  */
+
   if (delay_list == 0)
-    return gen_rtx (INSN_LIST, VOIDmode, insn, NULL_RTX);
+    {
+      struct target_info *tinfo;
+      
+      for (tinfo = target_hash_table[INSN_UID (insn) % TARGET_HASH_PRIME];
+          tinfo; tinfo = tinfo->next)
+       if (tinfo->uid == INSN_UID (insn))
+         break;
+
+      if (tinfo)
+       tinfo->block = -1;
+
+      return gen_rtx (INSN_LIST, VOIDmode, insn, NULL_RTX);
+    }
 
   /* Otherwise this must be an INSN_LIST.  Add INSN to the end of the
      list.  */
@@ -1106,7 +1140,7 @@ optimize_skip (insn)
          target_label = JUMP_LABEL (next_trial);
          if (target_label == 0)
            target_label = find_end_label ();
-         redirect_jump (insn, target_label);
+         reorg_redirect_jump (insn, target_label);
        }
 
       INSN_ANNULLED_BRANCH_P (insn) = 1;
@@ -1322,7 +1356,8 @@ mostly_true_jump (jump_insn, condition)
   /* Predict backward branches usually take, forward branches usually not.  If
      we don't know whether this is forward or backward, assume the branch
      will be taken, since most are.  */
-  return (INSN_UID (jump_insn) > max_uid || INSN_UID (target_label) > max_uid
+  return (target_label == 0 || INSN_UID (jump_insn) > max_uid
+         || INSN_UID (target_label) > max_uid
          || (uid_to_ruid[INSN_UID (jump_insn)]
              > uid_to_ruid[INSN_UID (target_label)]));;
 }
@@ -1396,6 +1431,42 @@ condition_dominates_p (condition, insn)
 
   return comparison_dominates_p (code, other_code);
 }
+
+/* Return non-zero if redirecting JUMP to NEWLABEL does not invalidate
+   any insns already in the delay slot of JUMP.  */
+
+static int
+redirect_with_delay_slots_safe_p (jump, newlabel, seq)
+     rtx jump, newlabel, seq;
+{
+  int flags, slots, i;
+  rtx pat = PATTERN (seq);
+
+  /* Make sure all the delay slots of this jump would still
+     be valid after threading the jump.  If they are still
+     valid, then return non-zero.  */
+
+  flags = get_jump_flags (jump, newlabel);
+  for (i = 1; i < XVECLEN (pat, 0); i++)
+    if (! (
+#ifdef ANNUL_IFFALSE_SLOTS
+          (INSN_ANNULLED_BRANCH_P (jump)
+           && INSN_FROM_TARGET_P (XVECEXP (pat, 0, i)))
+          ? eligible_for_annul_false (jump, i - 1,
+                                      XVECEXP (pat, 0, i), flags) :
+#endif
+#ifdef ANNUL_IFTRUE_SLOTS
+          (INSN_ANNULLED_BRANCH_P (jump)
+           && ! INSN_FROM_TARGET_P (XVECEXP (pat, 0, i)))
+          ? eligible_for_annul_true (jump, i - 1,
+                                     XVECEXP (pat, 0, i), flags) :
+#endif
+          eligible_for_delay (jump, i -1, XVECEXP (pat, 0, i), flags)))
+      break;
+
+  return (i == XVECLEN (pat, 0));
+}
+
 \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
@@ -1610,7 +1681,7 @@ try_merge_delay_insns (insn, thread)
   int i;
   int flags;
 
-  flags = get_jump_flags (insn, JUMP_LABEL (insn));
+  flags = get_jump_flags (delay_insn, JUMP_LABEL (delay_insn));
 
   CLEAR_RESOURCE (&needed);
   CLEAR_RESOURCE (&set);
@@ -2061,6 +2132,22 @@ update_block (insn, where)
     bb_ticks[b]++;
 }
 
+/* Similar to REDIRECT_JUMP except that we update the BB_TICKS entry for
+   the basic block containing the jump.  */
+
+static int
+reorg_redirect_jump (jump, nlabel)
+     rtx jump;
+     rtx nlabel;
+{
+  int b = find_basic_block (jump);
+
+  if (b != -1)
+    bb_ticks[b]++;
+
+  return redirect_jump (jump, nlabel);
+}
+
 /* Called when INSN is being moved forward into a delay slot of DELAYED_INSN.
    We check every instruction between INSN and DELAYED_INSN for REG_DEAD notes
    that reference values used in INSN.  If we find one, then we move the
@@ -2585,7 +2672,10 @@ fill_simple_delay_slots (first, non_jumps_p)
          || (GET_CODE (insn) != JUMP_INSN && ! non_jumps_p))
        continue;
      
-      flags = get_jump_flags (insn, JUMP_LABEL (insn));
+      if (GET_CODE (insn) == JUMP_INSN)
+       flags = get_jump_flags (insn, JUMP_LABEL (insn));
+      else
+       flags = get_jump_flags (insn, NULL_RTX);
       slots_to_fill = num_delay_slots (insn);
       if (slots_to_fill == 0)
        abort ();
@@ -2602,13 +2692,16 @@ fill_simple_delay_slots (first, non_jumps_p)
         the unconditional jump.  This is done first to avoid having the
         delay slot of the call filled in the backward scan.  Also, since
         the unconditional jump is likely to also have a delay slot, that
-        insn must exist when it is subsequently scanned.  */
+        insn must exist when it is subsequently scanned.
+
+        This is tried on each insn with delay slots as some machines
+        have insns which perform calls, but are not represented as 
+        CALL_INSNs.  */
 
       slots_filled = 0;
       delay_list = 0;
 
-      if (GET_CODE (insn) == CALL_INSN
-         && (trial = next_active_insn (insn))
+      if ((trial = next_active_insn (insn))
          && GET_CODE (trial) == JUMP_INSN
          && simplejump_p (trial)
          && eligible_for_delay (insn, slots_filled, trial, flags)
@@ -2892,12 +2985,12 @@ fill_simple_delay_slots (first, non_jumps_p)
              delay_list 
                = add_to_delay_list (copy_rtx (next_trial), delay_list);
              slots_filled++;
-             redirect_jump (trial, new_label);
+             reorg_redirect_jump (trial, new_label);
 
              /* If we merged because we both jumped to the same place,
                 redirect the original insn also.  */
              if (target)
-               redirect_jump (insn, new_label);
+               reorg_redirect_jump (insn, new_label);
            }
        }
 
@@ -3062,7 +3155,7 @@ fill_slots_from_thread (insn, condition, thread, opposite_thread, likely,
        ! stop_search_p (trial, ! thread_if_true) && (! lose || own_thread);
        trial = next_nonnote_insn (trial))
     {
-      rtx pat;
+      rtx pat, old_trial;
 
       /* If we have passed a label, we no longer own this thread.  */
       if (GET_CODE (trial) == CODE_LABEL)
@@ -3109,7 +3202,10 @@ fill_slots_from_thread (insn, condition, thread, opposite_thread, likely,
              || (! insn_sets_resource_p (trial, &opposite_needed, 1)
                  && ! may_trap_p (pat)))
            {
+             old_trial = trial;
              trial = try_split (pat, trial, 0);
+             if (new_thread == old_trial)
+               new_thread = trial;
              pat = PATTERN (trial);
              if (eligible_for_delay (insn, *pslots_filled, trial, flags))
                goto winner;
@@ -3123,7 +3219,10 @@ fill_slots_from_thread (insn, condition, thread, opposite_thread, likely,
 #endif
                   )
            {
+             old_trial = trial;
              trial = try_split (pat, trial, 0);
+             if (new_thread == old_trial)
+               new_thread = trial;
              pat = PATTERN (trial);
              if ((thread_if_true
                   ? eligible_for_annul_false (insn, *pslots_filled, trial, flags)
@@ -3198,9 +3297,11 @@ fill_slots_from_thread (insn, condition, thread, opposite_thread, likely,
         but it doesn't seem worth it.  It might also be a good idea to try
         to swap the two insns.  That might do better.
 
-        We can't do this if the next insn modifies our source, because that
-        would make the replacement into the insn invalid.  This also
-        prevents updating the contents of a PRE_INC.  */
+        We can't do this if the next insn modifies our destination, because
+        that would make the replacement into the insn invalid.  We also can't
+        do this if it modifies our source, because it might be an earlyclobber
+        operand.  This latter test also prevents updating the contents of
+        a PRE_INC.  */
 
       if (GET_CODE (trial) == INSN && GET_CODE (pat) == SET
          && GET_CODE (SET_SRC (pat)) == REG
@@ -3211,6 +3312,7 @@ fill_slots_from_thread (insn, condition, thread, opposite_thread, likely,
          if (next && GET_CODE (next) == INSN
              && GET_CODE (PATTERN (next)) != USE
              && ! reg_set_p (SET_DEST (pat), next)
+             && ! reg_set_p (SET_SRC (pat), next)
              && reg_referenced_p (SET_DEST (pat), PATTERN (next)))
            validate_replace_rtx (SET_DEST (pat), SET_SRC (pat), next);
        }
@@ -3331,7 +3433,7 @@ fill_slots_from_thread (insn, condition, thread, opposite_thread, likely,
       else
        label = get_label_before (new_thread);
 
-      redirect_jump (insn, label);
+      reorg_redirect_jump (insn, label);
     }
 
   return delay_list;
@@ -3497,7 +3599,7 @@ relax_delay_slots (first)
            }
 
          if (target_label != JUMP_LABEL (insn))
-           redirect_jump (insn, target_label);
+           reorg_redirect_jump (insn, target_label);
 
          /* See if this jump branches around a unconditional jump.
             If so, invert this jump and point it to the target of the
@@ -3554,6 +3656,7 @@ relax_delay_slots (first)
                                                         JUMP_LABEL (other))))
        {
          rtx other_target = JUMP_LABEL (other);
+         target_label = JUMP_LABEL (insn);
 
          /* Increment the count of OTHER_TARGET, so it doesn't get deleted
             as we move the label.  */
@@ -3561,7 +3664,7 @@ relax_delay_slots (first)
            ++LABEL_NUSES (other_target);
 
          if (invert_jump (other, target_label))
-           redirect_jump (insn, other_target);
+           reorg_redirect_jump (insn, other_target);
 
          if (other_target)
            --LABEL_NUSES (other_target);
@@ -3601,9 +3704,10 @@ relax_delay_slots (first)
          if (trial == 0 && target_label != 0)
            trial = find_end_label ();
 
-         if (trial != target_label)
+         if (trial != target_label 
+             && redirect_with_delay_slots_safe_p (delay_insn, trial, insn))
            {
-             redirect_jump (delay_insn, trial);
+             reorg_redirect_jump (delay_insn, trial);
              target_label = trial;
            }
 
@@ -3618,7 +3722,7 @@ relax_delay_slots (first)
                target_label = find_end_label ();
              else
                target_label = get_label_before (trial);
-             redirect_jump (delay_insn, target_label);
+             reorg_redirect_jump (delay_insn, target_label);
              next = insn;
              continue;
            }
@@ -3635,9 +3739,14 @@ relax_delay_slots (first)
              target_label = JUMP_LABEL (XVECEXP (PATTERN (trial), 0, 0));
              if (target_label == 0)
                target_label = find_end_label ();
-             redirect_jump (delay_insn, target_label);
-             next = insn;
-             continue;
+
+             if (redirect_with_delay_slots_safe_p (delay_insn, target_label, 
+                                                   insn))
+               {
+                 reorg_redirect_jump (delay_insn, target_label);
+                 next = insn;
+                 continue;
+               }
            }
        }
 
@@ -3706,20 +3815,24 @@ relax_delay_slots (first)
          if (label == 0)
            label = find_end_label ();
 
-         /* Be careful how we do this to avoid deleting code or labels
-            that are momentarily dead.  See similar optimization in jump.c  */
-         if (old_label)
-           ++LABEL_NUSES (old_label);
-
-         if (invert_jump (delay_insn, label))
+         if (redirect_with_delay_slots_safe_p (delay_insn, label, insn))
            {
-             delete_insn (next);
-             next = insn;
-           }
+             /* Be careful how we do this to avoid deleting code or labels
+                that are momentarily dead.  See similar optimization in
+                jump.c  */
+             if (old_label)
+               ++LABEL_NUSES (old_label);
 
-         if (old_label && --LABEL_NUSES (old_label) == 0)
-           delete_insn (old_label);
-         continue;
+             if (invert_jump (delay_insn, label))
+               {
+                 delete_insn (next);
+                 next = insn;
+               }
+
+             if (old_label && --LABEL_NUSES (old_label) == 0)
+               delete_insn (old_label);
+             continue;
+           }
        }
 
       /* If we own the thread opposite the way this insn branches, see if we
@@ -3785,9 +3898,9 @@ make_return_insns (first)
 
       /* If we can't make the jump into a RETURN, redirect it to the best
         RETURN and go on to the next insn.  */
-      if (! redirect_jump (jump_insn, NULL_RTX))
+      if (! reorg_redirect_jump (jump_insn, NULL_RTX))
        {
-         redirect_jump (jump_insn, real_return_label);
+         reorg_redirect_jump (jump_insn, real_return_label);
          continue;
        }
 
@@ -3843,7 +3956,7 @@ make_return_insns (first)
       else
        /* It is probably more efficient to keep this with its current
           delay slot as a branch to a RETURN.  */
-       redirect_jump (jump_insn, real_return_label);
+       reorg_redirect_jump (jump_insn, real_return_label);
     }
 
   /* Now delete REAL_RETURN_LABEL if we never used it.  Then try to fill any
@@ -3877,6 +3990,11 @@ dbr_schedule (first, file)
   flag_no_peephole = old_flag_no_peephole;
 #endif
 
+  /* If the current function has no insns other than the prologue and 
+     epilogue, then do not try to fill any delay slots.  */
+  if (n_basic_blocks == 0)
+    return;
+
   /* Find the highest INSN_UID and allocate and initialize our map from
      INSN_UID's to position in code.  */
   for (max_uid = 0, insn = first; insn; insn = NEXT_INSN (insn))