OSDN Git Service

(c_sizeof, build_c_cast): Set TREE_OVERFLOW in addition
[pf3gnuchains/gcc-fork.git] / gcc / reload.c
index aa4744c..35fe843 100644 (file)
@@ -1,5 +1,5 @@
 /* Search an insn for pseudo regs that must be in hard regs and are not.
-   Copyright (C) 1987, 1988, 1989, 1992 Free Software Foundation, Inc.
+   Copyright (C) 1987, 1988, 1989, 1992, 1993 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -616,9 +616,12 @@ push_reload (in, out, inloc, outloc, class,
      really reload just the inside expression in its own mode.
      If we have (SUBREG:M1 (REG:M2 ...) ...) with M1 wider than M2 and the
      register is a pseudo, this will become the same as the above case.
-     Do the same for (SUBREG:M1 (REG:M2 ...) ...) for a hard register R where
+     Similar issue for (SUBREG:M1 (REG:M2 ...) ...) for a hard register R where
      either M1 is not valid for R or M2 is wider than a word but we only
      need one word to store an M2-sized quantity in R.
+     (However, if OUT is nonzero, we need to reload the reg *and*
+     the subreg, so do nothing here, and let following statement handle it.)
+
      Note that the case of (SUBREG (CONST_INT...)...) is handled elsewhere;
      we can't handle it here because CONST_INT does not indicate a mode.
 
@@ -635,8 +638,10 @@ push_reload (in, out, inloc, outloc, class,
              && REGNO (SUBREG_REG (in)) >= FIRST_PSEUDO_REGISTER
              && (GET_MODE_SIZE (inmode)
                  > GET_MODE_SIZE (GET_MODE (SUBREG_REG (in)))))
-         || (GET_CODE (SUBREG_REG (in)) == REG
-             && REGNO (SUBREG_REG (in)) < FIRST_PSEUDO_REGISTER
+         || (REGNO (SUBREG_REG (in)) < FIRST_PSEUDO_REGISTER
+             /* The case where out is nonzero
+                is handled differently in the following statement.  */
+             && (out == 0 || SUBREG_WORD (in) == 0)
              && (! HARD_REGNO_MODE_OK (REGNO (SUBREG_REG (in)), inmode)
                  || (GET_MODE_SIZE (inmode) <= UNITS_PER_WORD
                      && (GET_MODE_SIZE (GET_MODE (SUBREG_REG (in)))
@@ -657,14 +662,40 @@ push_reload (in, out, inloc, outloc, class,
       in_subreg_loc = inloc;
       inloc = &SUBREG_REG (in);
       in = *inloc;
+#if ! defined(BYTE_LOADS_ZERO_EXTEND) && ! defined(BYTE_LOADS_SIGN_EXTEND)
       if (GET_CODE (in) == MEM)
        /* This is supposed to happen only for paradoxical subregs made by
           combine.c.  (SUBREG (MEM)) isn't supposed to occur other ways.  */
        if (GET_MODE_SIZE (GET_MODE (in)) > GET_MODE_SIZE (inmode))
          abort ();
+#endif
       inmode = GET_MODE (in);
     }
 
+  /* Similar issue for (SUBREG:M1 (REG:M2 ...) ...) for a hard register R where
+     either M1 is not valid for R or M2 is wider than a word but we only
+     need one word to store an M2-sized quantity in R.
+
+     However, we must reload the inner reg *as well as* the subreg in
+     that case.  */
+
+  if (in != 0 && GET_CODE (in) == SUBREG
+      && GET_CODE (SUBREG_REG (in)) == REG
+      && REGNO (SUBREG_REG (in)) < FIRST_PSEUDO_REGISTER
+      && (! HARD_REGNO_MODE_OK (REGNO (SUBREG_REG (in)), inmode)
+         || (GET_MODE_SIZE (inmode) <= UNITS_PER_WORD
+             && (GET_MODE_SIZE (GET_MODE (SUBREG_REG (in)))
+                 > UNITS_PER_WORD)
+             && ((GET_MODE_SIZE (GET_MODE (SUBREG_REG (in)))
+                  / UNITS_PER_WORD)
+                 != HARD_REGNO_NREGS (REGNO (SUBREG_REG (in)),
+                                      GET_MODE (SUBREG_REG (in)))))))
+    {
+      push_reload (SUBREG_REG (in), NULL_RTX, &SUBREG_REG (in), NULL_PTR,
+                  GENERAL_REGS, VOIDmode, VOIDmode, 0, 0, opnum, type);
+    }
+
+
   /* Similarly for paradoxical and problematical SUBREGs on the output.
      Note that there is no reason we need worry about the previous value
      of SUBREG_REG (out); even if wider than out,
@@ -699,10 +730,12 @@ push_reload (in, out, inloc, outloc, class,
     {
       out_subreg_loc = outloc;
       outloc = &SUBREG_REG (out);
-      out = *outloc;
-      if (GET_CODE (out) == MEM
+      out = *outloc; 
+#if ! defined(BYTE_LOADS_ZERO_EXTEND) && ! defined(BYTE_LOADS_SIGN_EXTEND)
+     if (GET_CODE (out) == MEM
          && GET_MODE_SIZE (GET_MODE (out)) > GET_MODE_SIZE (outmode))
        abort ();
+#endif
       outmode = GET_MODE (out);
     }
 
@@ -1259,6 +1292,18 @@ push_reload (in, out, inloc, outloc, class,
                                                + HARD_REGNO_NREGS (regno,
                                                                    inmode)),
                                               PATTERN (this_insn), inloc)
+           /* If this is also an output reload, IN cannot be used as
+              the reload register if it is set in this insn unless IN
+              is also OUT.  */
+           && (out == 0 || in == out
+               || ! hard_reg_set_here_p (regno,
+                                         (regno
+                                          + HARD_REGNO_NREGS (regno,
+                                                              inmode)),
+                                         PATTERN (this_insn)))
+           /* ??? Why is this code so different from the previous?
+              Is there any simple coherent way to describe the two together?
+              What's going on here.  */
            && (in != out
                || (GET_CODE (in) == SUBREG
                    && (((GET_MODE_SIZE (GET_MODE (in)) + (UNITS_PER_WORD - 1))
@@ -3461,7 +3506,9 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
       for (j = 0; j < n_reloads; j++)
        if (i != j && reload_in[j] != 0 && reload_out[j] == 0
            && reload_when_needed[j] == reload_when_needed[i]
-           && MATCHES (reload_in[i], reload_in[j]))
+           && MATCHES (reload_in[i], reload_in[j])
+           && reload_reg_class[i] == reload_reg_class[j]
+           && !reload_nocombine[i] && !reload_nocombine[j])
          {
            reload_opnum[i] = MIN (reload_opnum[i], reload_opnum[j]);
            transfer_replacements (i, j);
@@ -3749,6 +3796,9 @@ find_reloads_toplev (x, opnum, type, ind_levels, is_set_dest)
   return x;
 }
 
+/* Return a mem ref for the memory equivalent of reg REGNO.
+   This mem ref is not shared with anything.  */
+
 static rtx
 make_memloc (ad, regno)
      rtx ad;
@@ -3756,9 +3806,16 @@ make_memloc (ad, regno)
 {
   register int i;
   rtx tem = reg_equiv_address[regno];
+
+#if 0 /* We cannot safely reuse a memloc made here;
+        if the pseudo appears twice, and its mem needs a reload,
+        it gets two separate reloads assigned, but it only
+        gets substituted with the second of them;
+        then it can get used before that reload reg gets loaded up.  */
   for (i = 0; i < n_memlocs; i++)
     if (rtx_equal_p (tem, XEXP (memlocs[i], 0)))
       return memlocs[i];
+#endif
 
   /* If TEM might contain a pseudo, we must copy it to avoid
      modifying it when we do the substitution for the reload.  */
@@ -3831,10 +3888,16 @@ find_reloads_address (mode, memrefloc, ad, loc, opnum, type, ind_levels)
        }
 
       /* We can avoid a reload if the register's equivalent memory expression
-        is valid as an indirect memory address. */
+        is valid as an indirect memory address.
+        But not all addresses are valid in a mem used as an indirect address:
+        only reg or reg+constant.  */
 
       else if (reg_equiv_mem[regno] != 0 && ind_levels > 0
-              && strict_memory_address_p (mode, reg_equiv_mem[regno]))
+              && strict_memory_address_p (mode, reg_equiv_mem[regno])
+              && (GET_CODE (XEXP (reg_equiv_mem[regno], 0)) == REG
+                  || (GET_CODE (XEXP (reg_equiv_mem[regno], 0)) == PLUS
+                      && GET_CODE (XEXP (XEXP (reg_equiv_mem[regno], 0), 0)) == REG
+                      && CONSTANT_P (XEXP (XEXP (reg_equiv_mem[regno], 0), 0)))))
        return 0;
 
       /* The only remaining case where we can avoid a reload is if this is a
@@ -4138,6 +4201,13 @@ form_sum (x, y)
      rtx x, y;
 {
   rtx tem;
+  enum machine_mode mode = GET_MODE (x);
+
+  if (mode == VOIDmode)
+    mode = GET_MODE (y);
+
+  if (mode == VOIDmode)
+    mode = Pmode;
 
   if (GET_CODE (x) == CONST_INT)
     return plus_constant (y, INTVAL (x));
@@ -4163,10 +4233,10 @@ form_sum (x, y)
       if (GET_CODE (y) == CONST)
        y = XEXP (y, 0);
 
-      return gen_rtx (CONST, VOIDmode, gen_rtx (PLUS, Pmode, x, y));
+      return gen_rtx (CONST, VOIDmode, gen_rtx (PLUS, mode, x, y));
     }
 
-  return gen_rtx (PLUS, Pmode, x, y);
+  return gen_rtx (PLUS, mode, x, y);
 }
 \f
 /* If ADDR is a sum containing a pseudo register that should be
@@ -4937,7 +5007,7 @@ find_equiv_reg (goal, insn, class, other, reload_reg_p, goalreg, mode)
      enum machine_mode mode;
 {
   register rtx p = insn;
-  rtx valtry, value, where;
+  rtx goaltry, valtry, value, where;
   register rtx pat;
   register int regno = -1;
   int valueno;
@@ -5043,7 +5113,9 @@ find_equiv_reg (goal, insn, class, other, reload_reg_p, goalreg, mode)
                      && GET_CODE (XEXP (tem, 0)) == CONST_DOUBLE
                      && GET_MODE_CLASS (GET_MODE (XEXP (tem, 0))) == MODE_FLOAT
                      && GET_CODE (goal) == CONST_INT
-                     && INTVAL (goal) == CONST_DOUBLE_LOW (XEXP (tem, 0))
+                     && 0 != (goaltry = operand_subword (XEXP (tem, 0), 0, 0,
+                                                         VOIDmode))
+                     && rtx_equal_p (goal, goaltry)
                      && (valtry = operand_subword (SET_DEST (pat), 0, 0,
                                                    VOIDmode))
                      && (valueno = true_regnum (valtry)) >= 0)
@@ -5053,7 +5125,9 @@ find_equiv_reg (goal, insn, class, other, reload_reg_p, goalreg, mode)
                      && GET_CODE (XEXP (tem, 0)) == CONST_DOUBLE
                      && GET_MODE_CLASS (GET_MODE (XEXP (tem, 0))) == MODE_FLOAT
                      && GET_CODE (goal) == CONST_INT
-                     && INTVAL (goal) == CONST_DOUBLE_HIGH (XEXP (tem, 0))
+                     && 0 != (goaltry = operand_subword (XEXP (tem, 0), 1, 0,
+                                                         VOIDmode))
+                     && rtx_equal_p (goal, goaltry)
                      && (valtry
                          = operand_subword (SET_DEST (pat), 1, 0, VOIDmode))
                      && (valueno = true_regnum (valtry)) >= 0)))
@@ -5149,7 +5223,9 @@ find_equiv_reg (goal, insn, class, other, reload_reg_p, goalreg, mode)
     }
 
   if (goal_mem)
-    goal_mem_addr_varies = rtx_addr_varies_p (goal);
+    /* We must treat frame pointer as varying here,
+       since it can vary--in a nonlocal goto as generated by expand_goto.  */
+    goal_mem_addr_varies = !CONSTANT_ADDRESS_P (XEXP (goal, 0));
 
   /* Now verify that the values of GOAL and VALUE remain unaltered
      until INSN is reached.  */