OSDN Git Service

(load_multiple insn): If address register is among regs, don't load it
[pf3gnuchains/gcc-fork.git] / gcc / reorg.c
index ec21a35..edd76d5 100644 (file)
@@ -1,5 +1,5 @@
 /* Perform instruction reorganizations for delay slot filling.
-   Copyright (C) 1992, 1993, 1994 Free Software Foundation, Inc.
+   Copyright (C) 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
    Contributed by Richard Kenner (kenner@vlsi1.ultra.nyu.edu).
    Hacked by Michael Tiemann (tiemann@cygnus.com).
 
@@ -17,7 +17,8 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GNU CC; see the file COPYING.  If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
 
 /* Instruction reorganization pass.
 
@@ -162,6 +163,7 @@ static rtx *unfilled_firstobj;
 struct resources
 {
   char memory;                 /* Insn sets or needs a memory location.  */
+  char unch_memory;            /* Insn sets of needs a "unchanging" MEM. */
   char volatil;                        /* Insn sets or needs a volatile memory loc. */
   char cc;                     /* Insn sets or needs the condition codes.  */
   HARD_REG_SET regs;           /* Which registers are set or needed.  */
@@ -169,7 +171,7 @@ struct resources
 
 /* Macro to clear all resources.  */
 #define CLEAR_RESOURCE(RES)    \
- do { (RES)->memory = (RES)->volatil = (RES)->cc = 0;  \
+ do { (RES)->memory = (RES)->unch_memory = (RES)->volatil = (RES)->cc = 0; \
       CLEAR_HARD_REG_SET ((RES)->regs); } while (0)
 
 /* Indicates what resources are required at the beginning of the epilogue.  */
@@ -310,7 +312,9 @@ mark_referenced_resources (x, res, include_delayed_effects)
     case MEM:
       /* If this memory shouldn't change, it really isn't referencing
         memory.  */
-      if (! RTX_UNCHANGING_P (x))
+      if (RTX_UNCHANGING_P (x))
+       res->unch_memory = 1;
+      else
        res->memory = 1;
       res->volatil = MEM_VOLATILE_P (x);
 
@@ -379,11 +383,13 @@ mark_referenced_resources (x, res, include_delayed_effects)
          rtx insn = PREV_INSN (x);
          rtx sequence = 0;
          int seq_size = 0;
+         rtx next = NEXT_INSN (x);
          int i;
 
          /* If we are part of a delay slot sequence, point at the SEQUENCE. */
          if (NEXT_INSN (insn) != x)
            {
+             next = NEXT_INSN (NEXT_INSN (insn));
              sequence = PATTERN (NEXT_INSN (insn));
              seq_size = XVECLEN (sequence, 0);
              if (GET_CODE (sequence) != SEQUENCE)
@@ -404,6 +410,18 @@ mark_referenced_resources (x, res, include_delayed_effects)
            if (global_regs[i])
              SET_HARD_REG_BIT (res->regs, i);
 
+         /* Check for a NOTE_INSN_SETJMP.  If it exists, then we must
+            assume that this call can need any register.
+
+            This is done to be more conservative about how we handle setjmp.
+            We assume that they both use and set all registers.  Using all
+            registers ensures that a register will not be considered dead
+            just because it crosses a setjmp call.  A register should be
+            considered dead only if the setjmp call returns non-zero.  */
+         if (next && GET_CODE (next) == NOTE
+             && NOTE_LINE_NUMBER (next) == NOTE_INSN_SETJMP)
+           SET_HARD_REG_SET (res->regs);
+
          {
            rtx link;
 
@@ -602,6 +620,7 @@ mark_set_resources (x, res, in_dest, include_delayed_effects)
       if (in_dest)
        {
          res->memory = 1;
+         res->unch_memory = RTX_UNCHANGING_P (x);
          res->volatil = MEM_VOLATILE_P (x);
        }
 
@@ -693,6 +712,7 @@ resource_conflicts_p (res1, res2)
      struct resources *res1, *res2;
 {
   if ((res1->cc && res2->cc) || (res1->memory && res2->memory)
+      || (res1->unch_memory && res2->unch_memory)
       || res1->volatil || res2->volatil)
     return 1;
 
@@ -1352,7 +1372,7 @@ mostly_true_jump (jump_insn, condition)
          return 1;
     }
 
-  /* Look at the relative rarities of the fallthough and destination.  If
+  /* Look at the relative rarities of the fallthrough and destination.  If
      they differ, we can predict the branch that way. */
 
   switch (rare_fallthrough - rare_dest)
@@ -1592,12 +1612,17 @@ steal_delay_list_from_target (insn, condition, seq, delay_list,
 
   /* 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.
-
      We know that it will be a taken branch if it is either an unconditional
-     branch or a conditional branch with a stricter branch condition.  */
+     branch or a conditional branch with a stricter branch condition.
+
+     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.  */
 
   if (XVECLEN (seq, 0) - 1 > slots_remaining
-      || ! condition_dominates_p (condition, XVECEXP (seq, 0, 0)))
+      || ! condition_dominates_p (condition, XVECEXP (seq, 0, 0))
+      || ! single_set (XVECEXP (seq, 0, 0)))
     return delay_list;
 
   for (i = 1; i < XVECLEN (seq, 0); i++)
@@ -2014,6 +2039,7 @@ redundant_insn (insn, target, delay_list)
   /* Insns we pass may not set either NEEDED or SET, so merge them for
      simpler tests.  */
   needed.memory |= set.memory;
+  needed.unch_memory |= set.unch_memory;
   IOR_HARD_REG_SET (needed.regs, set.regs);
 
   /* This insn isn't redundant if it conflicts with an insn that either is
@@ -2435,7 +2461,7 @@ mark_target_live_regs (target, res)
 
   /* We have to assume memory is needed, but the CC isn't.  */
   res->memory = 1;
-  res->volatil = 0;
+  res->volatil = res->unch_memory = 0;
   res->cc = 0;
 
   /* See if we have computed this value already.  */
@@ -2831,12 +2857,24 @@ fill_simple_delay_slots (first, non_jumps_p)
          && eligible_for_delay (insn, slots_filled, trial, flags)
          && no_labels_between_p (insn, trial))
        {
+         rtx *tmp;
          slots_filled++;
          delay_list = add_to_delay_list (trial, delay_list);
+
+         /* TRIAL may have had its delay slot filled, then unfilled.  When
+            the delay slot is unfilled, TRIAL is placed back on the unfilled
+            slots obstack.  Unfortunately, it is placed on the end of the
+            obstack, not in its original location.  Therefore, we must search
+            from entry i + 1 to the end of the unfilled slots obstack to
+            try and find TRIAL.  */
+         tmp = &unfilled_slots_base[i + 1];
+         while (*tmp != trial && tmp != unfilled_slots_next)
+           tmp++;
+
          /* Remove the unconditional jump from consideration for delay slot
-            filling and unthread it.  */
-         if (unfilled_slots_base[i + 1] == trial)
-           unfilled_slots_base[i + 1] = 0;
+            filling and unthread it.   */
+         if (*tmp == trial)
+           *tmp = 0;
          {
            rtx next = NEXT_INSN (trial);
            rtx prev = PREV_INSN (trial);
@@ -2936,14 +2974,12 @@ fill_simple_delay_slots (first, non_jumps_p)
         is a CALL_INSN (or a CALL_INSN is passed), cannot trap (because the
         call might not return).
 
-        If this is a conditional jump, see if it merges back to us early
-        enough for us to pick up insns from the merge point.  Don't do
-        this if there is another branch to our label unless we pass all of
-        them.
-
-        Another similar merge is if we jump to the same place that a
-        later unconditional jump branches to.  In that case, we don't
-        care about the number of uses of our label.  */
+        There used to be code which continued past the target label if
+        we saw all uses of the target label.  This code did not work,
+        because it failed to account for some instructions which were
+        both annulled and marked as from the target.  This can happen as a
+        result of optimize_skip.  Since this code was redundant with
+        fill_eager_delay_slots anyways, it was just deleted.  */
 
       if (slots_filled != slots_to_fill
           && (GET_CODE (insn) != JUMP_INSN
@@ -2953,8 +2989,6 @@ fill_simple_delay_slots (first, non_jumps_p)
        {
          rtx target = 0;
          int maybe_never = 0;
-         int passed_label = 0;
-         int target_uses;
          struct resources needed_at_jump;
 
          CLEAR_RESOURCE (&needed);
@@ -2971,13 +3005,7 @@ fill_simple_delay_slots (first, non_jumps_p)
              mark_set_resources (insn, &set, 0, 1);
              mark_referenced_resources (insn, &needed, 1);
              if (GET_CODE (insn) == JUMP_INSN)
-               {
-                 /* Get our target and show how many more uses we want to
-                    see before we hit the label.  */
-                 target = JUMP_LABEL (insn);
-                 target_uses = LABEL_NUSES (target) - 1;
-               }
-               
+               target = JUMP_LABEL (insn);
            }
 
          for (trial = next_nonnote_insn (insn); trial; trial = next_trial)
@@ -2986,22 +3014,8 @@ fill_simple_delay_slots (first, non_jumps_p)
 
              next_trial = next_nonnote_insn (trial);
 
-             if (GET_CODE (trial) == CODE_LABEL)
-               {
-                 passed_label = 1;
-
-                 /* If this is our target, see if we have seen all its uses.
-                    If so, indicate we have passed our target and ignore it.
-                    All other labels cause us to stop our search.  */
-                 if (trial == target && target_uses == 0)
-                   {
-                     target = 0;
-                     continue;
-                   }
-                 else
-                   break;
-               }
-             else if (GET_CODE (trial) == BARRIER)
+             if (GET_CODE (trial) == CODE_LABEL
+                 || GET_CODE (trial) == BARRIER)
                break;
 
              /* We must have an INSN, JUMP_INSN, or CALL_INSN.  */
@@ -3026,14 +3040,13 @@ fill_simple_delay_slots (first, non_jumps_p)
                {
                  if (target == 0)
                    break;
-                 else if (JUMP_LABEL (trial_delay) == target)
-                   target_uses--;
-                 else
+                 else if (JUMP_LABEL (trial_delay) != target)
                    {
                      mark_target_live_regs
                        (next_active_insn (JUMP_LABEL (trial_delay)),
                         &needed_at_jump);
                      needed.memory |= needed_at_jump.memory;
+                     needed.unch_memory |= needed_at_jump.unch_memory;
                      IOR_HARD_REG_SET (needed.regs, needed_at_jump.regs);
                    }
                }
@@ -3060,8 +3073,6 @@ fill_simple_delay_slots (first, non_jumps_p)
                    link_cc0_insns (trial);
 #endif
 
-                 if (passed_label)
-                   update_block (trial, trial);
                  delete_insn (trial);
                  if (slots_to_fill == ++slots_filled)
                    break;
@@ -3077,14 +3088,16 @@ fill_simple_delay_slots (first, non_jumps_p)
              set.cc = 1;
 
              /* If this is a call or jump, we might not get here.  */
-             if (GET_CODE (trial) == CALL_INSN
-                 || GET_CODE (trial) == JUMP_INSN)
+             if (GET_CODE (trial_delay) == CALL_INSN
+                 || GET_CODE (trial_delay) == JUMP_INSN)
                maybe_never = 1;
            }
 
          /* If there are slots left to fill and our search was stopped by an
             unconditional branch, try the insn at the branch target.  We can
-            redirect the branch if it works.  */
+            redirect the branch if it works. 
+
+            Don't do this if the insn at the branch target is a branch.  */
          if (slots_to_fill != slots_filled
              && trial
              && GET_CODE (trial) == JUMP_INSN
@@ -3093,6 +3106,7 @@ fill_simple_delay_slots (first, non_jumps_p)
              && (next_trial = next_active_insn (JUMP_LABEL (trial))) != 0
              && ! (GET_CODE (next_trial) == INSN
                    && GET_CODE (PATTERN (next_trial)) == SEQUENCE)
+             && GET_CODE (next_trial) != JUMP_INSN
              && ! insn_references_resource_p (next_trial, &set, 1)
              && ! insn_sets_resource_p (next_trial, &set, 1)
              && ! insn_sets_resource_p (next_trial, &needed, 1)
@@ -3146,9 +3160,27 @@ fill_simple_delay_slots (first, non_jumps_p)
     return;
 
   slots_filled = 0;
-  needed = end_of_function_needs;
   CLEAR_RESOURCE (&set);
 
+  /* The frame pointer and stack pointer are needed at the beginning of
+     the epilogue, so instructions setting them can not be put in the
+     epilogue delay slot.  However, everything else needed at function
+     end is safe, so we don't want to use end_of_function_needs here.  */
+  CLEAR_RESOURCE (&needed);
+  if (frame_pointer_needed)
+    {
+      SET_HARD_REG_BIT (needed.regs, FRAME_POINTER_REGNUM);
+#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)
+#endif
+       SET_HARD_REG_BIT (needed.regs, STACK_POINTER_REGNUM);
+    }
+  else
+    SET_HARD_REG_BIT (needed.regs, STACK_POINTER_REGNUM);
+
   for (trial = get_last_insn (); ! stop_search_p (trial, 1);
        trial = PREV_INSN (trial))
     {
@@ -3160,6 +3192,7 @@ fill_simple_delay_slots (first, non_jumps_p)
 
       if (! insn_references_resource_p (trial, &set, 1)
          && ! insn_sets_resource_p (trial, &needed, 1)
+         && ! insn_sets_resource_p (trial, &set, 1)
 #ifdef HAVE_cc0
          /* Don't want to mess with cc0 here.  */
          && ! reg_mentioned_p (cc0_rtx, pat)
@@ -3365,6 +3398,8 @@ fill_slots_from_thread (insn, condition, thread, opposite_thread, likely,
              trial = try_split (pat, trial, 0);
              if (new_thread == old_trial)
                new_thread = trial;
+             if (thread == old_trial)
+               thread = trial;
              pat = PATTERN (trial);
              if ((thread_if_true
                   ? eligible_for_annul_false (insn, *pslots_filled, trial, flags)
@@ -3628,7 +3663,7 @@ fill_eager_delay_slots (first)
       if (condition == 0)
        continue;
 
-      /* Get the next active fallthough and target insns and see if we own
+      /* Get the next active fallthrough and target insns and see if we own
         them.  Then see whether the branch is likely true.  We don't need
         to do a lot of this for unconditional branches.  */
 
@@ -3846,7 +3881,12 @@ relax_delay_slots (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);
-         trial = prev_label (next_active_insn (trial));
+         /* 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 = find_end_label ();
 
@@ -3972,6 +4012,17 @@ relax_delay_slots (first)
 
              if (invert_jump (delay_insn, label))
                {
+                 int i;
+
+                 /* Must update the INSN_FROM_TARGET_P bits now that
+                    the branch is reversed, so that mark_target_live_regs
+                    will handle the delay slot insn correctly.  */
+                 for (i = 1; i < XVECLEN (PATTERN (insn), 0); i++)
+                   {
+                     rtx slot = XVECEXP (PATTERN (insn), 0, i);
+                     INSN_FROM_TARGET_P (slot) = ! INSN_FROM_TARGET_P (slot);
+                   }
+
                  delete_insn (next);
                  next = insn;
                }
@@ -4203,6 +4254,7 @@ dbr_schedule (first, file)
 
   end_of_function_needs.cc = 0;
   end_of_function_needs.memory = 1;
+  end_of_function_needs.unch_memory = 0;
   CLEAR_HARD_REG_SET (end_of_function_needs.regs);
 
   if (frame_pointer_needed)
@@ -4257,14 +4309,15 @@ dbr_schedule (first, file)
   target_hash_table
     = (struct target_info **) alloca ((TARGET_HASH_PRIME
                                       * sizeof (struct target_info *)));
-  bzero (target_hash_table, TARGET_HASH_PRIME * sizeof (struct target_info *));
+  bzero ((char *) target_hash_table,
+        TARGET_HASH_PRIME * sizeof (struct target_info *));
 
   bb_ticks = (int *) alloca (n_basic_blocks * sizeof (int));
-  bzero (bb_ticks, n_basic_blocks * sizeof (int));
+  bzero ((char *) bb_ticks, n_basic_blocks * sizeof (int));
 
   /* Initialize the statistics for this function.  */
-  bzero (num_insns_needing_delays, sizeof num_insns_needing_delays);
-  bzero (num_filled_delays, sizeof num_filled_delays);
+  bzero ((char *) num_insns_needing_delays, sizeof num_insns_needing_delays);
+  bzero ((char *) num_filled_delays, sizeof num_filled_delays);
 
   /* Now do the delay slot filling.  Try everything twice in case earlier
      changes make more slots fillable.  */