OSDN Git Service

* Makefile.in (DRIVER_DEFINES): Remove last change.
[pf3gnuchains/gcc-fork.git] / gcc / sched.c
index a06044e..5fbf760 100644 (file)
@@ -1,5 +1,5 @@
 /* Instruction scheduling pass.
-   Copyright (C) 1992, 93-96, 1997 Free Software Foundation, Inc.
+   Copyright (C) 1992, 93-97, 1998 Free Software Foundation, Inc.
    Contributed by Michael Tiemann (tiemann@cygnus.com)
    Enhanced by, and currently maintained by, Jim Wilson (wilson@cygnus.com)
 
@@ -118,7 +118,7 @@ Boston, MA 02111-1307, USA.  */
    beginning of basic blocks that have been scheduled.  */
 \f
 #include "config.h"
-#include <stdio.h>
+#include "system.h"
 #include "rtl.h"
 #include "basic-block.h"
 #include "regs.h"
@@ -127,10 +127,17 @@ Boston, MA 02111-1307, USA.  */
 #include "insn-config.h"
 #include "insn-attr.h"
 
+#ifndef INSN_SCHEDULING
+void
+schedule_insns (dump_file)
+     FILE *dump_file ATTRIBUTE_UNUSED;
+{
+}
+#else /* INSN_SCHEDULING -- rest of file */
+
 extern char *reg_known_equiv_p;
 extern rtx *reg_known_value;
 
-#ifdef INSN_SCHEDULING
 /* Arrays set up by scheduling for the same respective purposes as
    similar-named arrays set up by flow analysis.  We work with these
    arrays during the scheduling pass so we can compare values against
@@ -179,7 +186,7 @@ static unsigned int *insn_blockage;
 #define UNIT_BLOCKED(B) ((B) >> (2 * BLOCKAGE_BITS))
 #define BLOCKAGE_RANGE(B) \
   (((((B) >> BLOCKAGE_BITS) & BLOCKAGE_MASK) << (HOST_BITS_PER_INT / 2)) \
-   | (B) & BLOCKAGE_MASK)
+   | ((B) & BLOCKAGE_MASK))
 
 /* Encodings of the `<name>_unit_blockage_range' function.  */
 #define MIN_BLOCKAGE_COST(R) ((R) >> (HOST_BITS_PER_INT / 2))
@@ -264,7 +271,7 @@ static rtx dead_notes;
    The transition (R->S) is implemented in the scheduling loop in
    `schedule_block' when the best insn to schedule is chosen.
    The transition (R->Q) is implemented in `schedule_select' when an
-   insn is found to to have a function unit conflict with the already
+   insn is found to have a function unit conflict with the already
    committed insns.
    The transitions (P->R and P->Q) are implemented in `schedule_insn' as
    insns move from the ready list to the scheduled list.
@@ -319,7 +326,7 @@ static void sched_analyze_2         PROTO((rtx, rtx));
 static void sched_analyze_insn         PROTO((rtx, rtx, rtx));
 static int sched_analyze               PROTO((rtx, rtx));
 static void sched_note_set             PROTO((int, rtx, int));
-static int rank_for_schedule           PROTO((rtx *, rtx *));
+static int rank_for_schedule           PROTO((const GENERIC_PTR, const GENERIC_PTR));
 static void swap_sort                  PROTO((rtx *, int));
 static void queue_insn                 PROTO((rtx, int));
 static int birthing_insn_p             PROTO((rtx));
@@ -342,8 +349,6 @@ static void update_flow_info                PROTO((rtx, rtx, rtx, rtx));
 
 /* Main entry point of this file.  */
 void schedule_insns    PROTO((FILE *));
-
-#endif /* INSN_SCHEDULING */
 \f
 #define SIZE_FOR_MODE(X) (GET_MODE_SIZE (GET_MODE (X)))
 
@@ -431,17 +436,19 @@ remove_dependence (insn, elem)
   rtx prev, link;
   int found = 0;
 
-  for (prev = 0, link = LOG_LINKS (insn); link;
-       prev = link, link = XEXP (link, 1))
+  for (prev = 0, link = LOG_LINKS (insn); link; link = XEXP (link, 1))
     {
       if (XEXP (link, 0) == elem)
        {
+         RTX_INTEGRATED_P (link) = 1;
          if (prev)
            XEXP (prev, 1) = XEXP (link, 1);
          else
            LOG_LINKS (insn) = XEXP (link, 1);
          found = 1;
        }
+      else
+       prev = link;
     }
 
   if (! found)
@@ -449,13 +456,6 @@ remove_dependence (insn, elem)
   return;
 }
 \f
-#ifndef INSN_SCHEDULING
-void
-schedule_insns (dump_file)
-     FILE *dump_file;
-{
-}
-#else
 #ifndef __GNUC__
 #define __inline
 #endif
@@ -745,9 +745,9 @@ actual_hazard (unit, insn, clock, cost)
       int instance = unit;
       int best_cost = actual_hazard_this_instance (unit, instance, insn,
                                                   clock, cost);
+#if MAX_MULTIPLICITY > 1
       int this_cost;
 
-#if MAX_MULTIPLICITY > 1
       if (best_cost > cost)
        {
          for (i = function_units[unit].multiplicity - 1; i > 0; i--)
@@ -919,6 +919,11 @@ priority (insn)
        {
          rtx x = XEXP (prev, 0);
 
+         /* If this was a duplicate of a dependence we already deleted,
+            ignore it.  */
+         if (RTX_INTEGRATED_P (prev))
+           continue;
+
          /* A dependence pointing to a note or deleted insn is always
             obsolete, because sched_analyze_insn will have created any
             necessary new dependences which replace it.  Notes and deleted
@@ -1326,8 +1331,8 @@ sched_analyze_2 (x, insn)
            while (--i >= 0)
              {
                reg_last_uses[regno + i]
-                 = gen_rtx (INSN_LIST, VOIDmode,
-                            insn, reg_last_uses[regno + i]);
+                 = gen_rtx_INSN_LIST (VOIDmode,
+                                      insn, reg_last_uses[regno + i]);
                if (reg_last_sets[regno + i])
                  add_dependence (insn, reg_last_sets[regno + i], 0);
                if ((call_used_regs[regno + i] || global_regs[regno + i])
@@ -1339,7 +1344,7 @@ sched_analyze_2 (x, insn)
        else
          {
            reg_last_uses[regno]
-             = gen_rtx (INSN_LIST, VOIDmode, insn, reg_last_uses[regno]);
+             = gen_rtx_INSN_LIST (VOIDmode, insn, reg_last_uses[regno]);
            if (reg_last_sets[regno])
              add_dependence (insn, reg_last_sets[regno], 0);
 
@@ -1676,14 +1681,14 @@ sched_analyze (head, tail)
 
              /* Add a pair of fake REG_NOTEs which we will later
                 convert back into a NOTE_INSN_SETJMP note.  See
-                reemit_notes for why we use a pair of of NOTEs.  */
-
-             REG_NOTES (insn) = gen_rtx (EXPR_LIST, REG_DEAD,
-                                         GEN_INT (0),
-                                         REG_NOTES (insn));
-             REG_NOTES (insn) = gen_rtx (EXPR_LIST, REG_DEAD,
-                                         GEN_INT (NOTE_INSN_SETJMP),
-                                         REG_NOTES (insn));
+                reemit_notes for why we use a pair of NOTEs.  */
+
+             REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_DEAD,
+                                                   GEN_INT (0),
+                                                   REG_NOTES (insn));
+             REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_DEAD,
+                                                   GEN_INT (NOTE_INSN_SETJMP),
+                                                   REG_NOTES (insn));
            }
          else
            {
@@ -1730,13 +1735,17 @@ sched_analyze (head, tail)
                   || NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END
                   || NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG
                   || NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_END
+                  || NOTE_LINE_NUMBER (insn) == NOTE_INSN_RANGE_START
+                  || NOTE_LINE_NUMBER (insn) == NOTE_INSN_RANGE_END
                   || (NOTE_LINE_NUMBER (insn) == NOTE_INSN_SETJMP
                       && GET_CODE (PREV_INSN (insn)) != CALL_INSN)))
        {
-         loop_notes = gen_rtx (EXPR_LIST, REG_DEAD,
-                               GEN_INT (NOTE_BLOCK_NUMBER (insn)), loop_notes);
-         loop_notes = gen_rtx (EXPR_LIST, REG_DEAD,
-                               GEN_INT (NOTE_LINE_NUMBER (insn)), loop_notes);
+         loop_notes = gen_rtx_EXPR_LIST (REG_DEAD,
+                                         GEN_INT (NOTE_BLOCK_NUMBER (insn)),
+                                         loop_notes);
+         loop_notes = gen_rtx_EXPR_LIST (REG_DEAD,
+                                         GEN_INT (NOTE_LINE_NUMBER (insn)),
+                                         loop_notes);
          CONST_CALL_P (loop_notes) = CONST_CALL_P (insn);
        }
 
@@ -1848,16 +1857,17 @@ sched_note_set (b, x, death)
 
 static int
 rank_for_schedule (x, y)
-     rtx *x, *y;
+     const GENERIC_PTR x;
+     const GENERIC_PTR y;
 {
-  rtx tmp = *y;
-  rtx tmp2 = *x;
+  rtx tmp = *(rtx *)y;
+  rtx tmp2 = *(rtx *)x;
   rtx link;
   int tmp_class, tmp2_class;
   int value;
 
   /* Choose the instruction with the highest priority, if different.  */
-  if (value = INSN_PRIORITY (tmp) - INSN_PRIORITY (tmp2))
+  if ((value = INSN_PRIORITY (tmp) - INSN_PRIORITY (tmp2)))
     return value;
 
   if (last_scheduled_insn)
@@ -1883,7 +1893,7 @@ rank_for_schedule (x, y)
       else
        tmp2_class = 2;
 
-      if (value = tmp_class - tmp2_class)
+      if ((value = tmp_class - tmp2_class))
        return value;
     }
 
@@ -2211,6 +2221,12 @@ create_reg_dead_note (reg, insn)
                                           GET_MODE (XEXP (link, 0))));
       while (reg_note_regs < regs_killed)
        {
+         /* LINK might be zero if we killed more registers after scheduling
+            than before, and the last hard register we kill is actually
+            multiple hard regs.  */
+         if (link == NULL_RTX)
+           abort ();
+  
          link = XEXP (link, 1);
          reg_note_regs += (REGNO (XEXP (link, 0)) >= FIRST_PSEUDO_REGISTER ? 1
                            : HARD_REGNO_NREGS (REGNO (XEXP (link, 0)),
@@ -2223,7 +2239,7 @@ create_reg_dead_note (reg, insn)
        {
          rtx temp_reg, temp_link;
 
-         temp_reg = gen_rtx (REG, word_mode, 0);
+         temp_reg = gen_rtx_REG (word_mode, 0);
          temp_link = rtx_alloc (EXPR_LIST);
          PUT_REG_NOTE_KIND (temp_link, REG_DEAD);
          XEXP (temp_link, 0) = temp_reg;
@@ -2327,12 +2343,7 @@ attach_deaths (x, insn, set_p)
 #endif
                && regno != STACK_POINTER_REGNUM)
              {
-               /* ??? It is perhaps a dead_or_set_p bug that it does
-                  not check for REG_UNUSED notes itself.  This is necessary
-                  for the case where the SET_DEST is a subreg of regno, as
-                  dead_or_set_p handles subregs specially.  */
-               if (! all_needed && ! dead_or_set_p (insn, x)
-                   && ! find_reg_note (insn, REG_UNUSED, x))
+               if (! all_needed && ! dead_or_set_p (insn, x))
                  {
                    /* Check for the case where the register dying partially
                       overlaps the register set by this insn.  */
@@ -2359,9 +2370,8 @@ attach_deaths (x, insn, set_p)
                             i >= 0; i--)
                          if (! REGNO_REG_SET_P (old_live_regs, regno + i)
                              && ! dead_or_set_regno_p (insn, regno + i))
-                           create_reg_dead_note (gen_rtx (REG,
-                                                          reg_raw_mode[regno + i],
-                                                          regno + i),
+                           create_reg_dead_note (gen_rtx_REG (reg_raw_mode[regno + i],
+                                                              regno + i),
                                                  insn);
                      }
                  }
@@ -2391,17 +2401,20 @@ attach_deaths (x, insn, set_p)
       return;
 
     case SUBREG:
+      attach_deaths (SUBREG_REG (x), insn,
+                    set_p && ((GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))
+                              <= UNITS_PER_WORD)
+                              || (GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))
+                                  == GET_MODE_SIZE (GET_MODE ((x))))));
+      return;
+
     case STRICT_LOW_PART:
-      /* These two cases preserve the value of SET_P, so handle them
-        separately.  */
-      attach_deaths (XEXP (x, 0), insn, set_p);
+      attach_deaths (XEXP (x, 0), insn, 0);
       return;
 
     case ZERO_EXTRACT:
     case SIGN_EXTRACT:
-      /* This case preserves the value of SET_P for the first operand, but
-        clears it for the other two.  */
-      attach_deaths (XEXP (x, 0), insn, set_p);
+      attach_deaths (XEXP (x, 0), insn, 0);
       attach_deaths (XEXP (x, 1), insn, 0);
       attach_deaths (XEXP (x, 2), insn, 0);
       return;
@@ -2503,6 +2516,8 @@ unlink_notes (insn, tail)
       else if (NOTE_LINE_NUMBER (insn) != NOTE_INSN_SETJMP
               && NOTE_LINE_NUMBER (insn) != NOTE_INSN_LOOP_BEG
               && NOTE_LINE_NUMBER (insn) != NOTE_INSN_LOOP_END
+              && NOTE_LINE_NUMBER (insn) != NOTE_INSN_RANGE_START
+              && NOTE_LINE_NUMBER (insn) != NOTE_INSN_RANGE_END
               && NOTE_LINE_NUMBER (insn) != NOTE_INSN_EH_REGION_BEG
               && NOTE_LINE_NUMBER (insn) != NOTE_INSN_EH_REGION_END)
        {
@@ -2649,6 +2664,14 @@ schedule_block (b, file)
   reg_pending_sets_all = 0;
   clear_units ();
 
+#if 0
+  /* We used to have code to avoid getting parameters moved from hard
+     argument registers into pseudos.
+
+     However, it was removed when it proved to be of marginal benefit and
+     caused problems because of different notions of what the "head" insn
+     was.  */
+
   /* Remove certain insns at the beginning from scheduling,
      by advancing HEAD.  */
 
@@ -2679,6 +2702,7 @@ schedule_block (b, file)
          head = NEXT_INSN (head);
        }
     }
+#endif
 
   /* Don't include any notes or labels at the beginning of the
      basic block, or notes at the ends of basic blocks.  */
@@ -3167,7 +3191,7 @@ schedule_block (b, file)
          register int stalls;
 
          for (stalls = 1; stalls < INSN_QUEUE_SIZE; stalls++)
-           if (insn = insn_queue[NEXT_Q_AFTER (q_ptr, stalls)])
+           if ((insn = insn_queue[NEXT_Q_AFTER (q_ptr, stalls)]))
              {
                for (; insn; insn = NEXT_INSN (insn))
                  {
@@ -3551,12 +3575,12 @@ regno_use_in (regno, x)
     {
       if (fmt[i] == 'e')
        {
-         if (tem = regno_use_in (regno, XEXP (x, i)))
+         if ((tem = regno_use_in (regno, XEXP (x, i))))
            return tem;
        }
       else if (fmt[i] == 'E')
        for (j = XVECLEN (x, i) - 1; j >= 0; j--)
-         if (tem = regno_use_in (regno , XVECEXP (x, i, j)))
+         if ((tem = regno_use_in (regno , XVECEXP (x, i, j))))
            return tem;
     }
 
@@ -3633,6 +3657,13 @@ new_insn_dead_notes (pat, insn, last, orig_insn)
 
   if (GET_CODE (dest) == REG)
     {
+      /* If the original insn already used this register, we may not add new
+         notes for it.  One example for a split that needs this test is
+        when a multi-word memory access with register-indirect addressing
+        is split into multiple memory accesses with auto-increment and
+        one adjusting add instruction for the address register.  */
+      if (reg_referenced_p (dest, PATTERN (orig_insn)))
+       return;
       for (tem = last; tem != insn; tem = PREV_INSN (tem))
        {
          if (GET_RTX_CLASS (GET_CODE (tem)) == 'i'
@@ -3837,6 +3868,14 @@ update_flow_info (notes, first, last, orig_insn)
          break;
 
        case REG_WAS_0:
+         /* If the insn that set the register to 0 was deleted, this
+            note cannot be relied on any longer.  The destination might
+            even have been moved to memory.
+             This was observed for SH4 with execute/920501-6.c compilation,
+            -O2 -fomit-frame-pointer -finline-functions .  */
+         if (GET_CODE (XEXP (note, 0)) == NOTE
+             || INSN_DELETED_P (XEXP (note, 0)))
+           break;
          /* This note applies to the dest of the original insn.  Find the
             first new insn that now has the same dest, and move the note
             there.  */
@@ -3982,8 +4021,9 @@ update_flow_info (notes, first, last, orig_insn)
          for (insn = first; insn != NEXT_INSN (last); insn = NEXT_INSN (insn))
            if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
                && reg_mentioned_p (XEXP (note, 0), PATTERN (insn)))
-             REG_NOTES (insn) = gen_rtx (EXPR_LIST, REG_LABEL,
-                                         XEXP (note, 0), REG_NOTES (insn));
+             REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_LABEL,
+                                                   XEXP (note, 0),
+                                                   REG_NOTES (insn));
          break;
 
        case REG_CC_SETTER:
@@ -4223,7 +4263,6 @@ schedule_insns (dump_file)
 {
   int max_uid = MAX_INSNS_PER_SPLIT * (get_max_uid () + 1);
   int b;
-  int i;
   rtx insn;
 
   /* Taking care of this degenerate case makes the rest of
@@ -4233,8 +4272,8 @@ schedule_insns (dump_file)
 
   /* Create an insn here so that we can hang dependencies off of it later.  */
   sched_before_next_call
-    = gen_rtx (INSN, VOIDmode, 0, NULL_RTX, NULL_RTX,
-              NULL_RTX, 0, NULL_RTX, NULL_RTX);
+    = gen_rtx_INSN (VOIDmode, 0, NULL_RTX, NULL_RTX,
+                   NULL_RTX, 0, NULL_RTX, NULL_RTX);
 
   /* Initialize the unused_*_lists.  We can't use the ones left over from
      the previous function, because gcc has freed that memory.  We can use
@@ -4252,14 +4291,18 @@ schedule_insns (dump_file)
      remember how far we can cut back the stack on exit.  */
 
   /* Allocate data for this pass.  See comments, above,
-     for what these vectors do.  */
-  insn_luid = (int *) alloca (max_uid * sizeof (int));
-  insn_priority = (int *) alloca (max_uid * sizeof (int));
-  insn_tick = (int *) alloca (max_uid * sizeof (int));
-  insn_costs = (short *) alloca (max_uid * sizeof (short));
-  insn_units = (short *) alloca (max_uid * sizeof (short));
-  insn_blockage = (unsigned int *) alloca (max_uid * sizeof (unsigned int));
-  insn_ref_count = (int *) alloca (max_uid * sizeof (int));
+     for what these vectors do.
+
+     We use xmalloc instead of alloca, because max_uid can be very large
+     when there is a lot of function inlining.  If we used alloca, we could
+     exceed stack limits on some hosts for some inputs.  */
+  insn_luid = (int *) xmalloc (max_uid * sizeof (int));
+  insn_priority = (int *) xmalloc (max_uid * sizeof (int));
+  insn_tick = (int *) xmalloc (max_uid * sizeof (int));
+  insn_costs = (short *) xmalloc (max_uid * sizeof (short));
+  insn_units = (short *) xmalloc (max_uid * sizeof (short));
+  insn_blockage = (unsigned int *) xmalloc (max_uid * sizeof (unsigned int));
+  insn_ref_count = (int *) xmalloc (max_uid * sizeof (int));
 
   if (reload_completed == 0)
     {
@@ -4283,7 +4326,7 @@ schedule_insns (dump_file)
     {
       rtx line;
 
-      line_note = (rtx *) alloca (max_uid * sizeof (rtx));
+      line_note = (rtx *) xmalloc (max_uid * sizeof (rtx));
       bzero ((char *) line_note, max_uid * sizeof (rtx));
       line_note_head = (rtx *) alloca (n_basic_blocks * sizeof (rtx));
       bzero ((char *) line_note_head, n_basic_blocks * sizeof (rtx));
@@ -4520,6 +4563,17 @@ schedule_insns (dump_file)
          }
     }
 
+  free (insn_luid);
+  free (insn_priority);
+  free (insn_tick);
+  free (insn_costs);
+  free (insn_units);
+  free (insn_blockage);
+  free (insn_ref_count);
+
+  if (write_symbols != NO_DEBUG)
+    free (line_note);
+
   if (reload_completed == 0)
     {
       FREE_REG_SET (bb_dead_regs);