OSDN Git Service

Merge from gomp-3_1-branch branch:
[pf3gnuchains/gcc-fork.git] / gcc / reload1.c
index 058b5e9..499412c 100644 (file)
@@ -250,6 +250,10 @@ static char *reload_insn_firstobj;
    examine.  */
 struct insn_chain *reload_insn_chain;
 
+/* TRUE if we potentially left dead insns in the insn stream and want to
+   run DCE immediately after reload, FALSE otherwise.  */
+static bool need_dce;
+
 /* List of all insns needing reloads.  */
 static struct insn_chain *insns_need_reload;
 \f
@@ -695,10 +699,11 @@ static int *temp_pseudo_reg_arr;
    If GLOBAL is zero, we do not have enough information to do that,
    so any pseudo reg that is spilled must go to the stack.
 
-   Return value is nonzero if reload failed
-   and we must not do any more for this function.  */
+   Return value is TRUE if reload likely left dead insns in the
+   stream and a DCE pass should be run to elimiante them.  Else the
+   return value is FALSE.  */
 
-int
+bool
 reload (rtx first, int global)
 {
   int i, n;
@@ -1329,7 +1334,9 @@ reload (rtx first, int global)
 
   gcc_assert (bitmap_empty_p (&spilled_pseudos));
 
-  return failure;
+  reload_completed = !failure;
+
+  return need_dce;
 }
 
 /* Yet another special case.  Unfortunately, reg-stack forces people to
@@ -2123,14 +2130,19 @@ delete_dead_insn (rtx insn)
   rtx prev = prev_active_insn (insn);
   rtx prev_dest;
 
-  /* If the previous insn sets a register that dies in our insn, delete it
-     too.  */
+  /* If the previous insn sets a register that dies in our insn make
+     a note that we want to run DCE immediately after reload.
+
+     We used to delete the previous insn & recurse, but that's wrong for
+     block local equivalences.  Instead of trying to figure out the exact
+     circumstances where we can delete the potentially dead insns, just
+     let DCE do the job.  */
   if (prev && GET_CODE (PATTERN (prev)) == SET
       && (prev_dest = SET_DEST (PATTERN (prev)), REG_P (prev_dest))
       && reg_mentioned_p (prev_dest, PATTERN (insn))
       && find_regno_note (insn, REG_DEAD, REGNO (prev_dest))
       && ! side_effects_p (SET_SRC (PATTERN (prev))))
-    delete_dead_insn (prev);
+    need_dce = 1;
 
   SET_INSN_DELETED (insn);
 }
@@ -2828,8 +2840,7 @@ eliminate_regs_1 (rtx x, enum machine_mode mem_mode, rtx insn,
         eliminated version of the memory location because push_reload
         may do the replacement in certain circumstances.  */
       if (REG_P (SUBREG_REG (x))
-         && (GET_MODE_SIZE (GET_MODE (x))
-             <= GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))))
+         && !paradoxical_subreg_p (x)
          && reg_equivs
          && reg_equiv_memory_loc (REGNO (SUBREG_REG (x))) != 0)
        {
@@ -4161,6 +4172,9 @@ init_eliminable_invariants (rtx first, bool do_subregs)
                }
              else if (function_invariant_p (x))
                {
+                 enum machine_mode mode;
+
+                 mode = GET_MODE (SET_DEST (set));
                  if (GET_CODE (x) == PLUS)
                    {
                      /* This is PLUS of frame pointer and a constant,
@@ -4173,12 +4187,11 @@ init_eliminable_invariants (rtx first, bool do_subregs)
                      reg_equiv_invariant (i) = x;
                      num_eliminable_invariants++;
                    }
-                 else if (LEGITIMATE_CONSTANT_P (x))
+                 else if (targetm.legitimate_constant_p (mode, x))
                    reg_equiv_constant (i) = x;
                  else
                    {
-                     reg_equiv_memory_loc (i)
-                       = force_const_mem (GET_MODE (SET_DEST (set)), x);
+                     reg_equiv_memory_loc (i) = force_const_mem (mode, x);
                      if (! reg_equiv_memory_loc (i))
                        reg_equiv_init (i) = NULL_RTX;
                    }
@@ -4213,10 +4226,8 @@ free_reg_equiv (void)
   int i;
 
 
-  if (offsets_known_at)
-    free (offsets_known_at);
-  if (offsets_at)
-    free (offsets_at);
+  free (offsets_known_at);
+  free (offsets_at);
   offsets_at = 0;
   offsets_known_at = 0;
 
@@ -4471,6 +4482,40 @@ scan_paradoxical_subregs (rtx x)
        }
     }
 }
+
+/* *OP_PTR and *OTHER_PTR are two operands to a conceptual reload.
+   If *OP_PTR is a paradoxical subreg, try to remove that subreg
+   and apply the corresponding narrowing subreg to *OTHER_PTR.
+   Return true if the operands were changed, false otherwise.  */
+
+static bool
+strip_paradoxical_subreg (rtx *op_ptr, rtx *other_ptr)
+{
+  rtx op, inner, other, tem;
+
+  op = *op_ptr;
+  if (!paradoxical_subreg_p (op))
+    return false;
+  inner = SUBREG_REG (op);
+
+  other = *other_ptr;
+  tem = gen_lowpart_common (GET_MODE (inner), other);
+  if (!tem)
+    return false;
+
+  /* If the lowpart operation turned a hard register into a subreg,
+     rather than simplifying it to another hard register, then the
+     mode change cannot be properly represented.  For example, OTHER
+     might be valid in its current mode, but not in the new one.  */
+  if (GET_CODE (tem) == SUBREG
+      && REG_P (other)
+      && HARD_REGISTER_P (other))
+    return false;
+
+  *op_ptr = inner;
+  *other_ptr = tem;
+  return true;
+}
 \f
 /* A subroutine of reload_as_needed.  If INSN has a REG_EH_REGION note,
    examine all of the reload insns between PREV and NEXT exclusive, and
@@ -4807,6 +4852,13 @@ reload_as_needed (int live_known)
        {
          AND_COMPL_HARD_REG_SET (reg_reloaded_valid, call_used_reg_set);
          AND_COMPL_HARD_REG_SET (reg_reloaded_valid, reg_reloaded_call_part_clobbered);
+
+         /* If this is a call to a setjmp-type function, we must not
+            reuse any reload reg contents across the call; that will
+            just be clobbered by other uses of the register in later
+            code, before the longjmp.  */
+         if (find_reg_note (insn, REG_SETJMP, NULL_RTX))
+           CLEAR_HARD_REG_SET (reg_reloaded_valid);
        }
     }
 
@@ -5538,7 +5590,7 @@ gen_reload_chain_without_interm_reg_p (int r1, int r2)
      chain reloads or do need an intermediate hard registers.  */
   bool result = true;
   int regno, n, code;
-  rtx out, in, tem, insn;
+  rtx out, in, insn;
   rtx last = get_last_insn ();
 
   /* Make r2 a component of r1.  */
@@ -5557,11 +5609,7 @@ gen_reload_chain_without_interm_reg_p (int r1, int r2)
 
   /* If IN is a paradoxical SUBREG, remove it and try to put the
      opposite SUBREG on OUT.  Likewise for a paradoxical SUBREG on OUT.  */
-  if (GET_CODE (in) == SUBREG
-      && (GET_MODE_SIZE (GET_MODE (in))
-         > GET_MODE_SIZE (GET_MODE (SUBREG_REG (in))))
-      && (tem = gen_lowpart_common (GET_MODE (SUBREG_REG (in)), out)) != 0)
-    in = SUBREG_REG (in), out = tem;
+  strip_paradoxical_subreg (&in, &out);
 
   if (GET_CODE (in) == PLUS
       && (REG_P (XEXP (in, 0))
@@ -6433,6 +6481,8 @@ choose_reload_regs (struct insn_chain *chain)
 
              if (regno >= 0
                  && reg_last_reload_reg[regno] != 0
+                 && (GET_MODE_SIZE (GET_MODE (reg_last_reload_reg[regno]))
+                     >= GET_MODE_SIZE (mode) + byte)
 #ifdef CANNOT_CHANGE_MODE_CLASS
                  /* Verify that the register it's in can be used in
                     mode MODE.  */
@@ -6444,24 +6494,12 @@ choose_reload_regs (struct insn_chain *chain)
                {
                  enum reg_class rclass = rld[r].rclass, last_class;
                  rtx last_reg = reg_last_reload_reg[regno];
-                 enum machine_mode need_mode;
 
                  i = REGNO (last_reg);
                  i += subreg_regno_offset (i, GET_MODE (last_reg), byte, mode);
                  last_class = REGNO_REG_CLASS (i);
 
-                 if (byte == 0)
-                   need_mode = mode;
-                 else
-                   need_mode
-                     = smallest_mode_for_size
-                       (GET_MODE_BITSIZE (mode) + byte * BITS_PER_UNIT,
-                        GET_MODE_CLASS (mode) == MODE_PARTIAL_INT
-                        ? MODE_INT : GET_MODE_CLASS (mode));
-
-                 if ((GET_MODE_SIZE (GET_MODE (last_reg))
-                      >= GET_MODE_SIZE (need_mode))
-                     && reg_reloaded_contents[i] == regno
+                 if (reg_reloaded_contents[i] == regno
                      && TEST_HARD_REG_BIT (reg_reloaded_valid, i)
                      && HARD_REGNO_MODE_OK (i, rld[r].mode)
                      && (TEST_HARD_REG_BIT (reg_class_contents[(int) rclass], i)
@@ -7557,7 +7595,6 @@ emit_output_reload_insns (struct insn_chain *chain, struct reload *rl,
              if (tertiary_icode != CODE_FOR_nothing)
                {
                  rtx third_reloadreg = rld[tertiary_reload].reg_rtx;
-                 rtx tem;
 
                  /* Copy primary reload reg to secondary reload reg.
                     (Note that these have been swapped above, then
@@ -7566,13 +7603,7 @@ emit_output_reload_insns (struct insn_chain *chain, struct reload *rl,
                  /* If REAL_OLD is a paradoxical SUBREG, remove it
                     and try to put the opposite SUBREG on
                     RELOADREG.  */
-                 if (GET_CODE (real_old) == SUBREG
-                     && (GET_MODE_SIZE (GET_MODE (real_old))
-                         > GET_MODE_SIZE (GET_MODE (SUBREG_REG (real_old))))
-                     && 0 != (tem = gen_lowpart_common
-                              (GET_MODE (SUBREG_REG (real_old)),
-                               reloadreg)))
-                   real_old = SUBREG_REG (real_old), reloadreg = tem;
+                 strip_paradoxical_subreg (&real_old, &reloadreg);
 
                  gen_reload (reloadreg, second_reloadreg,
                              rl->opnum, rl->when_needed);
@@ -8388,16 +8419,8 @@ gen_reload (rtx out, rtx in, int opnum, enum reload_type type)
 
   /* If IN is a paradoxical SUBREG, remove it and try to put the
      opposite SUBREG on OUT.  Likewise for a paradoxical SUBREG on OUT.  */
-  if (GET_CODE (in) == SUBREG
-      && (GET_MODE_SIZE (GET_MODE (in))
-         > GET_MODE_SIZE (GET_MODE (SUBREG_REG (in))))
-      && (tem = gen_lowpart_common (GET_MODE (SUBREG_REG (in)), out)) != 0)
-    in = SUBREG_REG (in), out = tem;
-  else if (GET_CODE (out) == SUBREG
-          && (GET_MODE_SIZE (GET_MODE (out))
-              > GET_MODE_SIZE (GET_MODE (SUBREG_REG (out))))
-          && (tem = gen_lowpart_common (GET_MODE (SUBREG_REG (out)), in)) != 0)
-    out = SUBREG_REG (out), in = tem;
+  if (!strip_paradoxical_subreg (&in, &out))
+    strip_paradoxical_subreg (&out, &in);
 
   /* How to do this reload can get quite tricky.  Normally, we are being
      asked to reload a simple operand, such as a MEM, a constant, or a pseudo