OSDN Git Service

* config/cris/cris.md ("*movdi_insn", "*mov_sidesisf_biap")
[pf3gnuchains/gcc-fork.git] / gcc / cselib.c
index 6fd4317..b7a8963 100644 (file)
@@ -1,6 +1,6 @@
 /* Common subexpression elimination library for GNU compiler.
    Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001, 2003, 2004 Free Software Foundation, Inc.
+   1999, 2000, 2001, 2003, 2004, 2005 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -50,18 +50,16 @@ static struct elt_loc_list *new_elt_loc_list (struct elt_loc_list *, rtx);
 static void unchain_one_value (cselib_val *);
 static void unchain_one_elt_list (struct elt_list **);
 static void unchain_one_elt_loc_list (struct elt_loc_list **);
-static void clear_table (void);
 static int discard_useless_locs (void **, void *);
 static int discard_useless_values (void **, void *);
 static void remove_useless_values (void);
 static rtx wrap_constant (enum machine_mode, rtx);
-static unsigned int hash_rtx (rtx, enum machine_mode, int);
+static unsigned int cselib_hash_rtx (rtx, enum machine_mode, int);
 static cselib_val *new_cselib_val (unsigned int, enum machine_mode);
 static void add_mem_for_addr (cselib_val *, cselib_val *, rtx);
 static cselib_val *cselib_lookup_mem (rtx, int);
 static void cselib_invalidate_regno (unsigned int, enum machine_mode);
 static void cselib_invalidate_mem (rtx);
-static void cselib_invalidate_rtx (rtx, rtx, void *);
 static void cselib_record_set (rtx, cselib_val *, cselib_val *);
 static void cselib_record_sets (rtx);
 
@@ -102,16 +100,16 @@ static int n_useless_values;
    which the register was set; if the mode is unknown or the value is
    no longer valid in that mode, ELT will be NULL for the first
    element.  */
-struct elt_list **reg_values;
-unsigned int reg_values_size;
+static struct elt_list **reg_values;
+static unsigned int reg_values_size;
 #define REG_VALUES(i) reg_values[i]
 
 /* The largest number of hard regs used by any entry added to the
-   REG_VALUES table.  Cleared on each clear_table() invocation.  */
+   REG_VALUES table.  Cleared on each cselib_clear_table() invocation.  */
 static unsigned int max_value_regs;
 
 /* Here the set of indices I with REG_VALUES(I) != 0 is saved.  This is used
-   in clear_table() for fast emptying.  */
+   in cselib_clear_table() for fast emptying.  */
 static unsigned int *used_regs;
 static unsigned int n_used_regs;
 
@@ -201,8 +199,8 @@ unchain_one_value (cselib_val *v)
    initialization.  If CLEAR_ALL isn't set, then only clear the entries
    which are known to have been used.  */
 
-static void
-clear_table (void)
+void
+cselib_clear_table (void)
 {
   unsigned int i;
 
@@ -235,9 +233,9 @@ entry_and_rtx_equal_p (const void *entry, const void *x_arg)
   rtx x = (rtx) x_arg;
   enum machine_mode mode = GET_MODE (x);
 
-  if (GET_CODE (x) == CONST_INT
-      || (mode == VOIDmode && GET_CODE (x) == CONST_DOUBLE))
-    abort ();
+  gcc_assert (GET_CODE (x) != CONST_INT
+             && (mode != VOIDmode || GET_CODE (x) != CONST_DOUBLE));
+  
   if (mode != GET_MODE (v->u.val_rtx))
     return 0;
 
@@ -257,8 +255,8 @@ entry_and_rtx_equal_p (const void *entry, const void *x_arg)
 }
 
 /* The hash function for our hash table.  The value is always computed with
-   hash_rtx when adding an element; this function just extracts the hash
-   value from a cselib_val structure.  */
+   cselib_hash_rtx when adding an element; this function just extracts the
+   hash value from a cselib_val structure.  */
 
 static hashval_t
 get_value_hash (const void *entry)
@@ -370,8 +368,7 @@ remove_useless_values (void)
 
   htab_traverse (hash_table, discard_useless_values, 0);
 
-  if (n_useless_values != 0)
-    abort ();
+  gcc_assert (!n_useless_values);
 }
 
 /* Return the mode in which a register was last set.  If X is not a
@@ -524,7 +521,7 @@ rtx_equal_for_cselib_p (rtx x, rtx y)
             contain anything but integers and other rtx's,
             except for within LABEL_REFs and SYMBOL_REFs.  */
        default:
-         abort ();
+         gcc_unreachable ();
        }
     }
   return 1;
@@ -539,8 +536,7 @@ wrap_constant (enum machine_mode mode, rtx x)
   if (GET_CODE (x) != CONST_INT
       && (GET_CODE (x) != CONST_DOUBLE || GET_MODE (x) != VOIDmode))
     return x;
-  if (mode == VOIDmode)
-    abort ();
+  gcc_assert (mode != VOIDmode);
   return gen_rtx_CONST (mode, x);
 }
 
@@ -554,7 +550,7 @@ wrap_constant (enum machine_mode mode, rtx x)
    otherwise the mode of X is used.  */
 
 static unsigned int
-hash_rtx (rtx x, enum machine_mode mode, int create)
+cselib_hash_rtx (rtx x, enum machine_mode mode, int create)
 {
   cselib_val *e;
   int i, j;
@@ -600,7 +596,7 @@ hash_rtx (rtx x, enum machine_mode mode, int create)
        for (i = 0; i < units; ++i)
          {
            elt = CONST_VECTOR_ELT (x, i);
-           hash += hash_rtx (elt, GET_MODE (elt), 0);
+           hash += cselib_hash_rtx (elt, GET_MODE (elt), 0);
          }
 
        return hash;
@@ -643,40 +639,54 @@ hash_rtx (rtx x, enum machine_mode mode, int create)
   fmt = GET_RTX_FORMAT (code);
   for (; i >= 0; i--)
     {
-      if (fmt[i] == 'e')
+      switch (fmt[i])
        {
-         rtx tem = XEXP (x, i);
-         unsigned int tem_hash = hash_rtx (tem, 0, create);
-
-         if (tem_hash == 0)
-           return 0;
-
-         hash += tem_hash;
-       }
-      else if (fmt[i] == 'E')
-       for (j = 0; j < XVECLEN (x, i); j++)
+       case 'e':
          {
-           unsigned int tem_hash = hash_rtx (XVECEXP (x, i, j), 0, create);
-
+           rtx tem = XEXP (x, i);
+           unsigned int tem_hash = cselib_hash_rtx (tem, 0, create);
+           
            if (tem_hash == 0)
              return 0;
-
+           
            hash += tem_hash;
          }
-      else if (fmt[i] == 's')
-       {
-         const unsigned char *p = (const unsigned char *) XSTR (x, i);
+         break;
+       case 'E':
+         for (j = 0; j < XVECLEN (x, i); j++)
+           {
+             unsigned int tem_hash
+               = cselib_hash_rtx (XVECEXP (x, i, j), 0, create);
+             
+             if (tem_hash == 0)
+               return 0;
+             
+             hash += tem_hash;
+           }
+         break;
+
+       case 's':
+         {
+           const unsigned char *p = (const unsigned char *) XSTR (x, i);
+           
+           if (p)
+             while (*p)
+               hash += *p++;
+           break;
+         }
+         
+       case 'i':
+         hash += XINT (x, i);
+         break;
 
-         if (p)
-           while (*p)
-             hash += *p++;
+       case '0':
+       case 't':
+         /* unused */
+         break;
+         
+       default:
+         gcc_unreachable ();
        }
-      else if (fmt[i] == 'i')
-       hash += XINT (x, i);
-      else if (fmt[i] == '0' || fmt[i] == 't')
-       /* unused */;
-      else
-       abort ();
     }
 
   return hash ? hash : 1 + (unsigned int) GET_CODE (x);
@@ -690,14 +700,14 @@ new_cselib_val (unsigned int value, enum machine_mode mode)
 {
   cselib_val *e = pool_alloc (cselib_val_pool);
 
-#ifdef ENABLE_CHECKING
-  if (value == 0)
-    abort ();
-#endif
+  gcc_assert (value);
 
   e->value = value;
-  /* We use custom method to allocate this RTL construct because it accounts
-     about 8% of overall memory usage.  */
+  /* We use an alloc pool to allocate this RTL construct because it
+     accounts for about 8% of the overall memory usage.  We know
+     precisely when we can have VALUE RTXen (when cselib is active)
+     so we don't need to put them in garbage collected memory.
+     ??? Why should a VALUE be an RTX in the first place?  */
   e->u.val_rtx = pool_alloc (value_pool);
   memset (e->u.val_rtx, 0, RTX_HDR_SIZE);
   PUT_CODE (e->u.val_rtx, VALUE);
@@ -799,7 +809,7 @@ cselib_subst_to_values (rtx x)
        if (GET_MODE (l->elt->u.val_rtx) == GET_MODE (x))
          return l->elt->u.val_rtx;
 
-      abort ();
+      gcc_unreachable ();
 
     case MEM:
       e = cselib_lookup_mem (x, 0);
@@ -926,7 +936,7 @@ cselib_lookup (rtx x, enum machine_mode mode, int create)
   if (MEM_P (x))
     return cselib_lookup_mem (x, create);
 
-  hashval = hash_rtx (x, mode, create);
+  hashval = cselib_hash_rtx (x, mode, create);
   /* Can't even create if hashing is not possible.  */
   if (! hashval)
     return 0;
@@ -963,9 +973,8 @@ cselib_invalidate_regno (unsigned int regno, enum machine_mode mode)
   unsigned int i;
 
   /* If we see pseudos after reload, something is _wrong_.  */
-  if (reload_completed && regno >= FIRST_PSEUDO_REGISTER
-      && reg_renumber[regno] >= 0)
-    abort ();
+  gcc_assert (!reload_completed || regno < FIRST_PSEUDO_REGISTER
+             || reg_renumber[regno] < 0);
 
   /* Determine the range of registers that must be invalidated.  For
      pseudos, only REGNO is affected.  For hard regs, we must take MODE
@@ -973,8 +982,7 @@ cselib_invalidate_regno (unsigned int regno, enum machine_mode mode)
      if they contain values that overlap REGNO.  */
   if (regno < FIRST_PSEUDO_REGISTER)
     {
-      if (mode == VOIDmode)
-       abort ();
+      gcc_assert (mode != VOIDmode);
 
       if (regno < max_value_regs)
        i = 0;
@@ -1134,16 +1142,14 @@ cselib_invalidate_mem (rtx mem_rtx)
   *vp = &dummy_val;
 }
 
-/* Invalidate DEST, which is being assigned to or clobbered.  The second and
-   the third parameter exist so that this function can be passed to
-   note_stores; they are ignored.  */
+/* Invalidate DEST, which is being assigned to or clobbered.  */
 
-static void
-cselib_invalidate_rtx (rtx dest, rtx ignore ATTRIBUTE_UNUSED,
-                      void *data ATTRIBUTE_UNUSED)
+void
+cselib_invalidate_rtx (rtx dest)
 {
-  while (GET_CODE (dest) == STRICT_LOW_PART || GET_CODE (dest) == SIGN_EXTRACT
-        || GET_CODE (dest) == ZERO_EXTRACT || GET_CODE (dest) == SUBREG)
+  while (GET_CODE (dest) == SUBREG
+        || GET_CODE (dest) == ZERO_EXTRACT
+        || GET_CODE (dest) == STRICT_LOW_PART)
     dest = XEXP (dest, 0);
 
   if (REG_P (dest))
@@ -1156,7 +1162,16 @@ cselib_invalidate_rtx (rtx dest, rtx ignore ATTRIBUTE_UNUSED,
      invalidate the stack pointer correctly.  Note that invalidating
      the stack pointer is different from invalidating DEST.  */
   if (push_operand (dest, GET_MODE (dest)))
-    cselib_invalidate_rtx (stack_pointer_rtx, NULL_RTX, NULL);
+    cselib_invalidate_rtx (stack_pointer_rtx);
+}
+
+/* A wrapper for cselib_invalidate_rtx to be called via note_stores.  */
+
+static void
+cselib_invalidate_rtx_note_stores (rtx dest, rtx ignore ATTRIBUTE_UNUSED,
+                                  void *data ATTRIBUTE_UNUSED)
+{
+  cselib_invalidate_rtx (dest);
 }
 
 /* Record the result of a SET instruction.  DEST is being set; the source
@@ -1188,11 +1203,9 @@ cselib_record_set (rtx dest, cselib_val *src_elt, cselib_val *dest_addr_elt)
        }
       else
        {
-         if (REG_VALUES (dreg)->elt == 0)
-           REG_VALUES (dreg)->elt = src_elt;
-         else
-           /* The register should have been invalidated.  */
-           abort ();
+         /* The register should have been invalidated.  */
+         gcc_assert (REG_VALUES (dreg)->elt == 0);
+         REG_VALUES (dreg)->elt = src_elt;
        }
 
       if (src_elt->locs == 0)
@@ -1291,7 +1304,7 @@ cselib_record_sets (rtx insn)
   /* Invalidate all locations written by this insn.  Note that the elts we
      looked up in the previous loop aren't affected, just some of their
      locations may go away.  */
-  note_stores (body, cselib_invalidate_rtx, NULL);
+  note_stores (body, cselib_invalidate_rtx_note_stores, NULL);
 
   /* If this is an asm, look for duplicate sets.  This can happen when the
      user uses the same value as an output multiple times.  This is valid
@@ -1336,8 +1349,6 @@ cselib_process_insn (rtx insn)
 
   if (find_reg_note (insn, REG_LIBCALL, NULL))
     cselib_current_insn_in_libcall = true;
-  if (find_reg_note (insn, REG_RETVAL, NULL))
-    cselib_current_insn_in_libcall = false;
   cselib_current_insn = insn;
 
   /* Forget everything at a CODE_LABEL, a volatile asm, or a setjmp.  */
@@ -1348,12 +1359,16 @@ cselib_process_insn (rtx insn)
          && GET_CODE (PATTERN (insn)) == ASM_OPERANDS
          && MEM_VOLATILE_P (PATTERN (insn))))
     {
-      clear_table ();
+      if (find_reg_note (insn, REG_RETVAL, NULL))
+        cselib_current_insn_in_libcall = false;
+      cselib_clear_table ();
       return;
     }
 
   if (! INSN_P (insn))
     {
+      if (find_reg_note (insn, REG_RETVAL, NULL))
+        cselib_current_insn_in_libcall = false;
       cselib_current_insn = 0;
       return;
     }
@@ -1364,7 +1379,10 @@ cselib_process_insn (rtx insn)
   if (CALL_P (insn))
     {
       for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
-       if (call_used_regs[i])
+       if (call_used_regs[i]
+           || (REG_VALUES (i) && REG_VALUES (i)->elt
+               && HARD_REGNO_CALL_PART_CLOBBERED (i, 
+                     GET_MODE (REG_VALUES (i)->elt->u.val_rtx))))
          cselib_invalidate_regno (i, reg_raw_mode[i]);
 
       if (! CONST_OR_PURE_CALL_P (insn))
@@ -1379,7 +1397,7 @@ cselib_process_insn (rtx insn)
      unlikely to help.  */
   for (x = REG_NOTES (insn); x; x = XEXP (x, 1))
     if (REG_NOTE_KIND (x) == REG_INC)
-      cselib_invalidate_rtx (XEXP (x, 0), NULL_RTX, NULL);
+      cselib_invalidate_rtx (XEXP (x, 0));
 #endif
 
   /* Look for any CLOBBERs in CALL_INSN_FUNCTION_USAGE, but only
@@ -1387,8 +1405,10 @@ cselib_process_insn (rtx insn)
   if (CALL_P (insn))
     for (x = CALL_INSN_FUNCTION_USAGE (insn); x; x = XEXP (x, 1))
       if (GET_CODE (XEXP (x, 0)) == CLOBBER)
-       cselib_invalidate_rtx (XEXP (XEXP (x, 0), 0), NULL_RTX, NULL);
+       cselib_invalidate_rtx (XEXP (XEXP (x, 0), 0));
 
+  if (find_reg_note (insn, REG_RETVAL, NULL))
+    cselib_current_insn_in_libcall = false;
   cselib_current_insn = 0;
 
   if (n_useless_values > MAX_USELESS_VALUES)
@@ -1443,7 +1463,7 @@ cselib_finish (void)
   free_alloc_pool (elt_loc_list_pool);
   free_alloc_pool (cselib_val_pool);
   free_alloc_pool (value_pool);
-  clear_table ();
+  cselib_clear_table ();
   htab_delete (hash_table);
   free (used_regs);
   used_regs = 0;