OSDN Git Service

Daily bump.
[pf3gnuchains/gcc-fork.git] / gcc / rtl.c
index 0c46c60..dda701e 100644 (file)
--- a/gcc/rtl.c
+++ b/gcc/rtl.c
@@ -1,12 +1,12 @@
 /* RTL utility routines.
    Copyright (C) 1987, 1988, 1991, 1994, 1997, 1998, 1999, 2000, 2001, 2002,
-   2003, 2004, 2005 Free Software Foundation, Inc.
+   2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
 GCC is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free
-Software Foundation; either version 2, or (at your option) any later
+Software Foundation; either version 3, or (at your option) any later
 version.
 
 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
@@ -15,9 +15,8 @@ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 for more details.
 
 You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING.  If not, write to the Free
-Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA.  */
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
 
 /* This file is compiled twice: once for the generator programs
    once for the compiler.  */
@@ -31,7 +30,6 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "coretypes.h"
 #include "tm.h"
 #include "rtl.h"
-#include "real.h"
 #include "ggc.h"
 #ifdef GENERATOR_FILE
 # include "errors.h"
@@ -109,9 +107,9 @@ const enum rtx_class rtx_class[NUM_RTX_CODE] = {
 
 /* Indexed by rtx code, gives the size of the rtx in bytes.  */
 
-const unsigned char rtx_size[NUM_RTX_CODE] = {
+const unsigned char rtx_code_size[NUM_RTX_CODE] = {
 #define DEF_RTL_EXPR(ENUM, NAME, FORMAT, CLASS)                                \
-  ((ENUM) == CONST_INT || (ENUM) == CONST_DOUBLE                       \
+  ((ENUM) == CONST_INT || (ENUM) == CONST_DOUBLE || (ENUM) == CONST_FIXED\
    ? RTX_HDR_SIZE + (sizeof FORMAT - 1) * sizeof (HOST_WIDE_INT)       \
    : RTX_HDR_SIZE + (sizeof FORMAT - 1) * sizeof (rtunion)),
 
@@ -119,15 +117,10 @@ const unsigned char rtx_size[NUM_RTX_CODE] = {
 #undef DEF_RTL_EXPR
 };
 
-/* Make sure all NOTE_INSN_* values are negative.  */
-extern char NOTE_INSN_MAX_isnt_negative_adjust_NOTE_INSN_BIAS
-[NOTE_INSN_MAX < 0 ? 1 : -1];
-
 /* Names for kinds of NOTEs and REG_NOTEs.  */
 
-const char * const note_insn_name[NOTE_INSN_MAX - NOTE_INSN_BIAS] =
+const char * const note_insn_name[NOTE_INSN_MAX] =
 {
-  "",
 #define DEF_INSN_NOTE(NAME) #NAME,
 #include "insn-notes.def"
 #undef DEF_INSN_NOTE
@@ -170,6 +163,30 @@ rtvec_alloc (int n)
   return rt;
 }
 
+/* Create a bitwise copy of VEC.  */
+
+rtvec
+shallow_copy_rtvec (rtvec vec)
+{
+  rtvec newvec;
+  int n;
+
+  n = GET_NUM_ELEM (vec);
+  newvec = rtvec_alloc (n);
+  memcpy (&newvec->elem[0], &vec->elem[0], sizeof (rtx) * n);
+  return newvec;
+}
+
+/* Return the number of bytes occupied by rtx value X.  */
+
+unsigned int
+rtx_size (const_rtx x)
+{
+  if (GET_CODE (x) == SYMBOL_REF && SYMBOL_REF_HAS_BLOCK_INFO_P (x))
+    return RTX_HDR_SIZE + sizeof (struct block_symbol);
+  return RTX_CODE_SIZE (GET_CODE (x));
+}
+
 /* Allocate an rtx of code CODE.  The CODE is stored in the rtx;
    all the rest is initialized to zero.  */
 
@@ -178,7 +195,7 @@ rtx_alloc_stat (RTX_CODE code MEM_STAT_DECL)
 {
   rtx rt;
 
-  rt = (rtx) ggc_alloc_zone_pass_stat (RTX_SIZE (code), &rtl_zone);
+  rt = (rtx) ggc_alloc_zone_pass_stat (RTX_CODE_SIZE (code), &rtl_zone);
 
   /* We want to clear everything up to the FLD array.  Normally, this
      is one int, but we don't want to assume that and it isn't very
@@ -189,13 +206,28 @@ rtx_alloc_stat (RTX_CODE code MEM_STAT_DECL)
 
 #ifdef GATHER_STATISTICS
   rtx_alloc_counts[code]++;
-  rtx_alloc_sizes[code] += RTX_SIZE (code);
+  rtx_alloc_sizes[code] += RTX_CODE_SIZE (code);
 #endif
 
   return rt;
 }
 
 \f
+/* Return true if ORIG is a sharable CONST.  */
+
+bool
+shared_const_p (const_rtx orig)
+{
+  gcc_assert (GET_CODE (orig) == CONST);
+
+  /* CONST can be shared if it contains a SYMBOL_REF.  If it contains
+     a LABEL_REF, it isn't sharable.  */
+  return (GET_CODE (XEXP (orig, 0)) == PLUS
+         && GET_CODE (XEXP (XEXP (orig, 0), 0)) == SYMBOL_REF
+         && CONST_INT_P(XEXP (XEXP (orig, 0), 1)));
+}
+
+
 /* Create a new copy of an rtx.
    Recursively copies the operands of the rtx,
    except for those few rtx codes that are sharable.  */
@@ -213,8 +245,11 @@ copy_rtx (rtx orig)
   switch (code)
     {
     case REG:
+    case DEBUG_EXPR:
+    case VALUE:
     case CONST_INT:
     case CONST_DOUBLE:
+    case CONST_FIXED:
     case CONST_VECTOR:
     case SYMBOL_REF:
     case CODE_LABEL:
@@ -229,11 +264,7 @@ copy_rtx (rtx orig)
       break;
 
     case CONST:
-      /* CONST can be shared if it contains a SYMBOL_REF.  If it contains
-        a LABEL_REF, it isn't sharable.  */
-      if (GET_CODE (XEXP (orig, 0)) == PLUS
-         && GET_CODE (XEXP (XEXP (orig, 0), 0)) == SYMBOL_REF
-         && GET_CODE (XEXP (XEXP (orig, 0), 1)) == CONST_INT)
+      if (shared_const_p (orig))
        return orig;
       break;
 
@@ -246,13 +277,11 @@ copy_rtx (rtx orig)
       break;
     }
 
-  copy = rtx_alloc (code);
-
-  /* Copy the various flags, and other information.  We assume that
-     all fields need copying, and then clear the fields that should
+  /* Copy the various flags, fields, and other information.  We assume
+     that all fields need copying, and then clear the fields that should
      not be copied.  That is the sensible default behavior, and forces
      us to explicitly document why we are *not* copying a flag.  */
-  memcpy (copy, orig, RTX_HDR_SIZE);
+  copy = shallow_copy_rtx (orig);
 
   /* We do not copy the USED flag, which is used as a mark bit during
      walks over the RTL.  */
@@ -267,69 +296,192 @@ copy_rtx (rtx orig)
   format_ptr = GET_RTX_FORMAT (GET_CODE (copy));
 
   for (i = 0; i < GET_RTX_LENGTH (GET_CODE (copy)); i++)
+    switch (*format_ptr++)
+      {
+      case 'e':
+       if (XEXP (orig, i) != NULL)
+         XEXP (copy, i) = copy_rtx (XEXP (orig, i));
+       break;
+
+      case 'E':
+      case 'V':
+       if (XVEC (orig, i) != NULL)
+         {
+           XVEC (copy, i) = rtvec_alloc (XVECLEN (orig, i));
+           for (j = 0; j < XVECLEN (copy, i); j++)
+             XVECEXP (copy, i, j) = copy_rtx (XVECEXP (orig, i, j));
+         }
+       break;
+
+      case 't':
+      case 'w':
+      case 'i':
+      case 's':
+      case 'S':
+      case 'T':
+      case 'u':
+      case 'B':
+      case '0':
+       /* These are left unchanged.  */
+       break;
+
+      default:
+       gcc_unreachable ();
+      }
+  return copy;
+}
+
+/* Create a new copy of an rtx.  Only copy just one level.  */
+
+rtx
+shallow_copy_rtx_stat (const_rtx orig MEM_STAT_DECL)
+{
+  const unsigned int size = rtx_size (orig);
+  rtx const copy = (rtx) ggc_alloc_zone_pass_stat (size, &rtl_zone);
+  return (rtx) memcpy (copy, orig, size);
+}
+\f
+/* Nonzero when we are generating CONCATs.  */
+int generating_concat_p;
+
+/* Nonzero when we are expanding trees to RTL.  */
+int currently_expanding_to_rtl;
+
+\f
+
+/* Same as rtx_equal_p, but call CB on each pair of rtx if CB is not NULL.
+   When the callback returns true, we continue with the new pair.
+   Whenever changing this function check if rtx_equal_p below doesn't need
+   changing as well.  */
+
+int
+rtx_equal_p_cb (const_rtx x, const_rtx y, rtx_equal_p_callback_function cb)
+{
+  int i;
+  int j;
+  enum rtx_code code;
+  const char *fmt;
+  rtx nx, ny;
+
+  if (x == y)
+    return 1;
+  if (x == 0 || y == 0)
+    return 0;
+
+  /* Invoke the callback first.  */
+  if (cb != NULL
+      && ((*cb) (&x, &y, &nx, &ny)))
+    return rtx_equal_p_cb (nx, ny, cb);
+
+  code = GET_CODE (x);
+  /* Rtx's of different codes cannot be equal.  */
+  if (code != GET_CODE (y))
+    return 0;
+
+  /* (MULT:SI x y) and (MULT:HI x y) are NOT equivalent.
+     (REG:SI x) and (REG:HI x) are NOT equivalent.  */
+
+  if (GET_MODE (x) != GET_MODE (y))
+    return 0;
+
+  /* MEMs refering to different address space are not equivalent.  */
+  if (code == MEM && MEM_ADDR_SPACE (x) != MEM_ADDR_SPACE (y))
+    return 0;
+
+  /* Some RTL can be compared nonrecursively.  */
+  switch (code)
+    {
+    case REG:
+      return (REGNO (x) == REGNO (y));
+
+    case LABEL_REF:
+      return XEXP (x, 0) == XEXP (y, 0);
+
+    case SYMBOL_REF:
+      return XSTR (x, 0) == XSTR (y, 0);
+
+    case DEBUG_EXPR:
+    case VALUE:
+    case SCRATCH:
+    case CONST_DOUBLE:
+    case CONST_INT:
+    case CONST_FIXED:
+      return 0;
+
+    default:
+      break;
+    }
+
+  /* Compare the elements.  If any pair of corresponding elements
+     fail to match, return 0 for the whole thing.  */
+
+  fmt = GET_RTX_FORMAT (code);
+  for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
     {
-      copy->u.fld[i] = orig->u.fld[i];
-      switch (*format_ptr++)
+      switch (fmt[i])
        {
-       case 'e':
-         if (XEXP (orig, i) != NULL)
-           XEXP (copy, i) = copy_rtx (XEXP (orig, i));
+       case 'w':
+         if (XWINT (x, i) != XWINT (y, i))
+           return 0;
+         break;
+
+       case 'n':
+       case 'i':
+         if (XINT (x, i) != XINT (y, i))
+           return 0;
          break;
 
-       case 'E':
        case 'V':
-         if (XVEC (orig, i) != NULL)
-           {
-             XVEC (copy, i) = rtvec_alloc (XVECLEN (orig, i));
-             for (j = 0; j < XVECLEN (copy, i); j++)
-               XVECEXP (copy, i, j) = copy_rtx (XVECEXP (orig, i, j));
-           }
+       case 'E':
+         /* Two vectors must have the same length.  */
+         if (XVECLEN (x, i) != XVECLEN (y, i))
+           return 0;
+
+         /* And the corresponding elements must match.  */
+         for (j = 0; j < XVECLEN (x, i); j++)
+           if (rtx_equal_p_cb (XVECEXP (x, i, j),
+                                XVECEXP (y, i, j), cb) == 0)
+             return 0;
+         break;
+
+       case 'e':
+         if (rtx_equal_p_cb (XEXP (x, i), XEXP (y, i), cb) == 0)
+           return 0;
          break;
 
-       case 't':
-       case 'w':
-       case 'i':
-       case 's':
        case 'S':
-       case 'T':
+       case 's':
+         if ((XSTR (x, i) || XSTR (y, i))
+             && (! XSTR (x, i) || ! XSTR (y, i)
+                 || strcmp (XSTR (x, i), XSTR (y, i))))
+           return 0;
+         break;
+
        case 'u':
-       case 'B':
+         /* These are just backpointers, so they don't matter.  */
+         break;
+
        case '0':
-         /* These are left unchanged.  */
+       case 't':
          break;
 
+         /* It is believed that rtx's at this level will never
+            contain anything but integers and other rtx's,
+            except for within LABEL_REFs and SYMBOL_REFs.  */
        default:
          gcc_unreachable ();
        }
     }
-  return copy;
+  return 1;
 }
 
-/* Create a new copy of an rtx.  Only copy just one level.  */
-
-rtx
-shallow_copy_rtx_stat (rtx orig MEM_STAT_DECL)
-{
-  rtx copy;
-
-  copy = (rtx) ggc_alloc_zone_pass_stat (RTX_SIZE (GET_CODE (orig)),
-                                        &rtl_zone);
-  memcpy (copy, orig, RTX_SIZE (GET_CODE (orig)));
-  return copy;
-}
-\f
-/* Nonzero when we are generating CONCATs.  */
-int generating_concat_p;
-
-/* Nonzero when we are expanding trees to RTL.  */
-int currently_expanding_to_rtl;
-
-\f
 /* Return 1 if X and Y are identical-looking rtx's.
-   This is the Lisp function EQUAL for rtx arguments.  */
+   This is the Lisp function EQUAL for rtx arguments.
+   Whenever changing this function check if rtx_equal_p_cb above doesn't need
+   changing as well.  */
 
 int
-rtx_equal_p (rtx x, rtx y)
+rtx_equal_p (const_rtx x, const_rtx y)
 {
   int i;
   int j;
@@ -352,6 +504,10 @@ rtx_equal_p (rtx x, rtx y)
   if (GET_MODE (x) != GET_MODE (y))
     return 0;
 
+  /* MEMs refering to different address space are not equivalent.  */
+  if (code == MEM && MEM_ADDR_SPACE (x) != MEM_ADDR_SPACE (y))
+    return 0;
+
   /* Some RTL can be compared nonrecursively.  */
   switch (code)
     {
@@ -364,9 +520,12 @@ rtx_equal_p (rtx x, rtx y)
     case SYMBOL_REF:
       return XSTR (x, 0) == XSTR (y, 0);
 
+    case DEBUG_EXPR:
+    case VALUE:
     case SCRATCH:
     case CONST_DOUBLE:
     case CONST_INT:
+    case CONST_FIXED:
       return 0;
 
     default:
@@ -400,7 +559,7 @@ rtx_equal_p (rtx x, rtx y)
 
          /* And the corresponding elements must match.  */
          for (j = 0; j < XVECLEN (x, i); j++)
-           if (rtx_equal_p (XVECEXP (x, i, j), XVECEXP (y, i, j)) == 0)
+           if (rtx_equal_p (XVECEXP (x, i, j),  XVECEXP (y, i, j)) == 0)
              return 0;
          break;
 
@@ -435,7 +594,8 @@ rtx_equal_p (rtx x, rtx y)
   return 1;
 }
 
-void dump_rtx_statistics (void)
+void
+dump_rtx_statistics (void)
 {
 #ifdef GATHER_STATISTICS
   int i;
@@ -462,12 +622,12 @@ void dump_rtx_statistics (void)
   fprintf (stderr, "%-20s %7d %10d\n",
            "Total", total_counts, total_sizes);
   fprintf (stderr, "---------------------------------------\n");
-#endif  
+#endif
 }
 \f
 #if defined ENABLE_RTL_CHECKING && (GCC_VERSION >= 2007)
 void
-rtl_check_failed_bounds (rtx r, int n, const char *file, int line,
+rtl_check_failed_bounds (const_rtx r, int n, const char *file, int line,
                         const char *func)
 {
   internal_error
@@ -477,7 +637,7 @@ rtl_check_failed_bounds (rtx r, int n, const char *file, int line,
 }
 
 void
-rtl_check_failed_type1 (rtx r, int n, int c1, const char *file, int line,
+rtl_check_failed_type1 (const_rtx r, int n, int c1, const char *file, int line,
                        const char *func)
 {
   internal_error
@@ -487,7 +647,7 @@ rtl_check_failed_type1 (rtx r, int n, int c1, const char *file, int line,
 }
 
 void
-rtl_check_failed_type2 (rtx r, int n, int c1, int c2, const char *file,
+rtl_check_failed_type2 (const_rtx r, int n, int c1, int c2, const char *file,
                        int line, const char *func)
 {
   internal_error
@@ -497,7 +657,7 @@ rtl_check_failed_type2 (rtx r, int n, int c1, int c2, const char *file,
 }
 
 void
-rtl_check_failed_code1 (rtx r, enum rtx_code code, const char *file,
+rtl_check_failed_code1 (const_rtx r, enum rtx_code code, const char *file,
                        int line, const char *func)
 {
   internal_error ("RTL check: expected code '%s', have '%s' in %s, at %s:%d",
@@ -506,7 +666,7 @@ rtl_check_failed_code1 (rtx r, enum rtx_code code, const char *file,
 }
 
 void
-rtl_check_failed_code2 (rtx r, enum rtx_code code1, enum rtx_code code2,
+rtl_check_failed_code2 (const_rtx r, enum rtx_code code1, enum rtx_code code2,
                        const char *file, int line, const char *func)
 {
   internal_error
@@ -515,9 +675,35 @@ rtl_check_failed_code2 (rtx r, enum rtx_code code1, enum rtx_code code2,
      func, trim_filename (file), line);
 }
 
+void
+rtl_check_failed_code_mode (const_rtx r, enum rtx_code code, enum machine_mode mode,
+                           bool not_mode, const char *file, int line,
+                           const char *func)
+{
+  internal_error ((not_mode
+                  ? ("RTL check: expected code '%s' and not mode '%s', "
+                     "have code '%s' and mode '%s' in %s, at %s:%d")
+                  : ("RTL check: expected code '%s' and mode '%s', "
+                     "have code '%s' and mode '%s' in %s, at %s:%d")),
+                 GET_RTX_NAME (code), GET_MODE_NAME (mode),
+                 GET_RTX_NAME (GET_CODE (r)), GET_MODE_NAME (GET_MODE (r)),
+                 func, trim_filename (file), line);
+}
+
+/* Report that line LINE of FILE tried to access the block symbol fields
+   of a non-block symbol.  FUNC is the function that contains the line.  */
+
+void
+rtl_check_failed_block_symbol (const char *file, int line, const char *func)
+{
+  internal_error
+    ("RTL check: attempt to treat non-block symbol as a block symbol "
+     "in %s, at %s:%d", func, trim_filename (file), line);
+}
+
 /* XXX Maybe print the vector?  */
 void
-rtvec_check_failed_bounds (rtvec r, int n, const char *file, int line,
+rtvec_check_failed_bounds (const_rtvec r, int n, const char *file, int line,
                           const char *func)
 {
   internal_error
@@ -528,7 +714,7 @@ rtvec_check_failed_bounds (rtvec r, int n, const char *file, int line,
 
 #if defined ENABLE_RTL_FLAG_CHECKING
 void
-rtl_check_failed_flag (const char *name, rtx r, const char *file,
+rtl_check_failed_flag (const char *name, const_rtx r, const char *file,
                       int line, const char *func)
 {
   internal_error