OSDN Git Service

* mn10300.md (adddi3, subdi3): Remove expanders and patterns.
[pf3gnuchains/gcc-fork.git] / gcc / reload1.c
index a7b4238..199ae68 100644 (file)
@@ -400,7 +400,7 @@ static void reload_cse_invalidate_mem       PROTO((rtx));
 static void reload_cse_invalidate_rtx  PROTO((rtx, rtx));
 static void reload_cse_regs            PROTO((rtx));
 static int reload_cse_regno_equal_p    PROTO((int, rtx, enum machine_mode));
-static int reload_cse_noop_set_p       PROTO((rtx));
+static int reload_cse_noop_set_p       PROTO((rtx, rtx));
 static void reload_cse_simplify_set    PROTO((rtx, rtx));
 static void reload_cse_check_clobber   PROTO((rtx, rtx));
 static void reload_cse_record_set      PROTO((rtx, rtx));
@@ -589,10 +589,18 @@ reload (first, global, dumpfile)
      as homes for pseudo registers.
      This is done here rather than (eg) in global_alloc
      because this point is reached even if not optimizing.  */
-
   for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++)
     mark_home_live (i);
 
+  /* A function that receives a nonlocal goto must save all call-saved
+     registers.  */
+  if (current_function_has_nonlocal_label)
+    for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+      {
+       if (! call_used_regs[i] && ! fixed_regs[i])
+         regs_ever_live[i] = 1;
+      }
+
   for (i = 0; i < scratch_list_length; i++)
     if (scratch_list[i])
       mark_scratch_live (scratch_list[i]);
@@ -7543,6 +7551,12 @@ count_occurrences (x, find)
 
 static rtx *reg_values;
 
+/* This is a preallocated REG rtx which we use as a temporary in
+   reload_cse_invalidate_regno, so that we don't need to allocate a
+   new one each time through a loop in that function.  */
+
+static rtx invalidate_regno_rtx;
+
 /* Invalidate any entries in reg_values which depend on REGNO,
    including those for REGNO itself.  This is called if REGNO is
    changing.  If CLOBBER is true, then always forget anything we
@@ -7586,7 +7600,7 @@ reload_cse_invalidate_regno (regno, mode, clobber)
       for (x = reg_values[i]; x; x = XEXP (x, 1))
        {
          if (XEXP (x, 0) != 0
-             && refers_to_regno_p (regno, endregno, XEXP (x, 0), NULL_RTX))
+             && refers_to_regno_p (regno, endregno, XEXP (x, 0), NULL_PTR))
            {
              /* If this is the only entry on the list, clear
                  reg_values[i].  Otherwise, just clear this entry on
@@ -7600,6 +7614,33 @@ reload_cse_invalidate_regno (regno, mode, clobber)
            }
        }
     }
+
+  /* We must look at earlier registers, in case REGNO is part of a
+     multi word value but is not the first register.  If an earlier
+     register has a value in a mode which overlaps REGNO, then we must
+     invalidate that earlier register.  Note that we do not need to
+     check REGNO or later registers (we must not check REGNO itself,
+     because we would incorrectly conclude that there was a conflict).  */
+
+  for (i = 0; i < regno; i++)
+    {
+      rtx x;
+
+      for (x = reg_values[i]; x; x = XEXP (x, 1))
+       {
+         if (XEXP (x, 0) != 0)
+           {
+             PUT_MODE (invalidate_regno_rtx, GET_MODE (x));
+             REGNO (invalidate_regno_rtx) = i;
+             if (refers_to_regno_p (regno, endregno, invalidate_regno_rtx,
+                                    NULL_PTR))
+               {
+                 reload_cse_invalidate_regno (i, VOIDmode, 1);
+                 break;
+               }
+           }
+       }
+    }
 }
 
 /* The memory at address (plus MEM_BASE MEM_OFFSET), where MEM_OFFSET
@@ -7622,7 +7663,6 @@ reload_cse_mem_conflict_p (mem_base, mem_offset, mem_mode, val)
     {
       /* Get rid of a few simple cases quickly. */
     case REG:
-    case SUBREG:
     case PC:
     case CC0:
     case SCRATCH:
@@ -7792,6 +7832,10 @@ reload_cse_regs (first)
      memory for a non-const call instruction.  */
   callmem = gen_rtx (MEM, BLKmode, const0_rtx);
 
+  /* This is used in reload_cse_invalidate_regno to avoid consing a
+     new REG in a loop in that function.  */
+  invalidate_regno_rtx = gen_rtx (REG, VOIDmode, 0);
+
   for (insn = first; insn; insn = NEXT_INSN (insn))
     {
       rtx body;
@@ -7836,11 +7880,8 @@ reload_cse_regs (first)
       body = PATTERN (insn);
       if (GET_CODE (body) == SET)
        {
-         if (reload_cse_noop_set_p (body))
+         if (reload_cse_noop_set_p (body, insn))
            {
-             /* If we were preserving death notes, then we would want
-                to remove any existing death note for the register
-                being set.  */
              PUT_CODE (insn, NOTE);
              NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
              NOTE_SOURCE_FILE (insn) = 0;
@@ -7860,13 +7901,10 @@ reload_cse_regs (first)
              the entire PARALLEL.  */
          for (i = XVECLEN (body, 0) - 1; i >= 0; --i)
            if (GET_CODE (XVECEXP (body, 0, i)) != SET
-               || ! reload_cse_noop_set_p (XVECEXP (body, 0, i)))
+               || ! reload_cse_noop_set_p (XVECEXP (body, 0, i), insn))
              break;
          if (i < 0)
            {
-             /* If we were preserving death notes, then we would want
-                to remove any existing death notes for the registers
-                being set.  */
              PUT_CODE (insn, NOTE);
              NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
              NOTE_SOURCE_FILE (insn) = 0;
@@ -7949,15 +7987,18 @@ reload_cse_regno_equal_p (regno, val, mode)
   return 0;
 }
 
-/* See whether a single SET instruction is a nooop.  */
+/* See whether a single set is a noop.  SET is the set instruction we
+   are should check, and INSN is the instruction from which it came.  */
 
 static int
-reload_cse_noop_set_p (set)
+reload_cse_noop_set_p (set, insn)
      rtx set;
+     rtx insn;
 {
   rtx src, dest;
   enum machine_mode dest_mode;
   int dreg, sreg;
+  int ret;
 
   src = SET_SRC (set);
   dest = SET_DEST (set);
@@ -7969,27 +8010,51 @@ reload_cse_noop_set_p (set)
   dreg = true_regnum (dest);
   sreg = true_regnum (src);
 
+  /* Check for setting a register to itself.  In this case, we don't
+     have to worry about REG_DEAD notes.  */
+  if (dreg >= 0 && dreg == sreg)
+    return 1;
+
+  ret = 0;
   if (dreg >= 0)
     {
       /* Check for setting a register to itself.  */
       if (dreg == sreg)
-       return 1;
+       ret = 1;
 
       /* Check for setting a register to a value which we already know
          is in the register.  */
-      if (reload_cse_regno_equal_p (dreg, src, dest_mode))
-       return 1;
+      else if (reload_cse_regno_equal_p (dreg, src, dest_mode))
+       ret = 1;
 
       /* Check for setting a register DREG to another register SREG
          where SREG is equal to a value which is already in DREG.  */
-      if (sreg >= 0)
+      else if (sreg >= 0)
        {
          rtx x;
 
          for (x = reg_values[sreg]; x; x = XEXP (x, 1))
-           if (XEXP (x, 0) != 0
-               && reload_cse_regno_equal_p (dreg, XEXP (x, 0), dest_mode))
-             return 1;
+           {
+             rtx tmp;
+
+             if (XEXP (x, 0) == 0)
+               continue;
+
+             if (dest_mode == GET_MODE (x))
+               tmp = XEXP (x, 0);
+             else if (GET_MODE_BITSIZE (dest_mode)
+                      < GET_MODE_BITSIZE (GET_MODE (x)))
+               tmp = gen_lowpart_common (dest_mode, XEXP (x, 0));
+             else
+               continue;
+
+             if (tmp
+                 && reload_cse_regno_equal_p (dreg, tmp, dest_mode))
+               {
+                 ret = 1;
+                 break;
+               }
+           }
        }
     }
   else if (GET_CODE (dest) == MEM)
@@ -7999,10 +8064,33 @@ reload_cse_noop_set_p (set)
       if (sreg >= 0
          && reload_cse_regno_equal_p (sreg, dest, dest_mode)
          && ! side_effects_p (dest))
-       return 1;
+       ret = 1;
     }
 
-  return 0;
+  /* If we can delete this SET, then we need to look for an earlier
+     REG_DEAD note on DREG, and remove it if it exists.  */
+  if (ret)
+    {
+      if (! find_regno_note (insn, REG_UNUSED, dreg))
+       {
+         rtx trial;
+
+         for (trial = prev_nonnote_insn (insn);
+              (trial
+               && GET_CODE (trial) != CODE_LABEL
+               && GET_CODE (trial) != BARRIER);
+              trial = prev_nonnote_insn (trial))
+           {
+             if (find_regno_note (trial, REG_DEAD, dreg))
+               {
+                 remove_death (dreg, trial);
+                 break;
+               }
+           }
+       }
+    }
+
+  return ret;
 }
 
 /* Try to simplify a single SET instruction.  SET is the set pattern.
@@ -8057,7 +8145,29 @@ reload_cse_simplify_set (set, insn)
          push_obstacks (&reload_obstack, &reload_obstack);
 
          if (validated)
-           return;
+           {
+             /* We need to look for an earlier REG_DEAD note on I,
+                and remove it if it exists.  */
+             if (! find_regno_note (insn, REG_UNUSED, i))
+               {
+                 rtx trial;
+
+                 for (trial = prev_nonnote_insn (insn);
+                      (trial
+                       && GET_CODE (trial) != CODE_LABEL
+                       && GET_CODE (trial) != BARRIER);
+                      trial = prev_nonnote_insn (trial))
+                   {
+                     if (find_regno_note (trial, REG_DEAD, i))
+                       {
+                         remove_death (i, trial);
+                         break;
+                       }
+                   }
+               }
+
+             return;
+           }
        }
     }
 }
@@ -8089,7 +8199,7 @@ reload_cse_record_set (set, body)
      rtx set;
      rtx body;
 {
-  rtx dest, src;
+  rtx dest, src, x;
   int dreg, sreg;
   enum machine_mode dest_mode;
 
@@ -8099,6 +8209,23 @@ reload_cse_record_set (set, body)
   sreg = true_regnum (src);
   dest_mode = GET_MODE (dest);
 
+  /* Some machines don't define AUTO_INC_DEC, but they still use push
+     instructions.  We need to catch that case here in order to
+     invalidate the stack pointer correctly.  Note that invalidating
+     the stack pointer is different from invalidating DEST.  */
+  x = dest;
+  while (GET_CODE (x) == SUBREG
+        || GET_CODE (x) == ZERO_EXTRACT
+        || GET_CODE (x) == SIGN_EXTRACT
+        || GET_CODE (x) == STRICT_LOW_PART)
+    x = XEXP (x, 0);
+  if (push_operand (x, GET_MODE (x)))
+    {
+      reload_cse_invalidate_rtx (stack_pointer_rtx, NULL_RTX);
+      reload_cse_invalidate_rtx (dest, NULL_RTX);
+      return;
+    }
+
   /* We can only handle an assignment to a register, or a store of a
      register to a memory location.  For other cases, we just clobber
      the destination.  We also have to just clobber if there are side
@@ -8154,7 +8281,29 @@ reload_cse_record_set (set, body)
       /* This is an assignment to a register.  Update the value we
          have stored for the register.  */
       if (sreg >= 0)
-       reg_values[dreg] = reg_values[sreg];
+       {
+         rtx x;
+
+         /* This is a copy from one register to another.  Any values
+            which were valid for SREG are now valid for DREG.  If the
+            mode changes, we use gen_lowpart_common to extract only
+            the part of the value that is copied.  */
+         reg_values[dreg] = 0;
+         for (x = reg_values[sreg]; x; x = XEXP (x, 1))
+           {
+             rtx tmp;
+
+             if (XEXP (x, 0) == 0)
+               continue;
+             if (dest_mode == GET_MODE (XEXP (x, 0)))
+               tmp = XEXP (x, 0);
+             else
+               tmp = gen_lowpart_common (dest_mode, XEXP (x, 0));
+             if (tmp)
+               reg_values[dreg] = gen_rtx (EXPR_LIST, dest_mode, tmp,
+                                           reg_values[dreg]);
+           }         
+       }
       else
        reg_values[dreg] = gen_rtx (EXPR_LIST, dest_mode, src, NULL_RTX);