OSDN Git Service

PR c++/37877
[pf3gnuchains/gcc-fork.git] / gcc / cselib.c
index 69ad207..945a4a1 100644 (file)
@@ -1,6 +1,7 @@
 /* Common subexpression elimination library for GNU compiler.
    Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
+   1999, 2000, 2001, 2003, 2004, 2005, 2006, 2007, 2008
+   Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -142,7 +143,7 @@ static inline struct elt_list *
 new_elt_list (struct elt_list *next, cselib_val *elt)
 {
   struct elt_list *el;
-  el = pool_alloc (elt_list_pool);
+  el = (struct elt_list *) pool_alloc (elt_list_pool);
   el->next = next;
   el->elt = elt;
   return el;
@@ -155,7 +156,7 @@ static inline struct elt_loc_list *
 new_elt_loc_list (struct elt_loc_list *next, rtx loc)
 {
   struct elt_loc_list *el;
-  el = pool_alloc (elt_loc_list_pool);
+  el = (struct elt_loc_list *) pool_alloc (elt_loc_list_pool);
   el->next = next;
   el->loc = loc;
   el->setting_insn = cselib_current_insn;
@@ -232,7 +233,7 @@ entry_and_rtx_equal_p (const void *entry, const void *x_arg)
 {
   struct elt_loc_list *l;
   const cselib_val *const v = (const cselib_val *) entry;
-  rtx x = (rtx) x_arg;
+  rtx x = CONST_CAST_RTX ((const_rtx)x_arg);
   enum machine_mode mode = GET_MODE (x);
 
   gcc_assert (GET_CODE (x) != CONST_INT && GET_CODE (x) != CONST_FIXED
@@ -749,7 +750,7 @@ cselib_hash_rtx (rtx x, int create)
 static inline cselib_val *
 new_cselib_val (unsigned int value, enum machine_mode mode)
 {
-  cselib_val *e = pool_alloc (cselib_val_pool);
+  cselib_val *e = (cselib_val *) pool_alloc (cselib_val_pool);
 
   gcc_assert (value);
 
@@ -759,7 +760,7 @@ new_cselib_val (unsigned int value, enum machine_mode mode)
      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->val_rtx = pool_alloc (value_pool);
+  e->val_rtx = (rtx) pool_alloc (value_pool);
   memset (e->val_rtx, 0, RTX_HDR_SIZE);
   PUT_CODE (e->val_rtx, VALUE);
   PUT_MODE (e->val_rtx, mode);
@@ -865,12 +866,18 @@ expand_loc (struct elt_loc_list *p, bitmap regs_active, int max_depth)
        continue;
       else if (!REG_P (p->loc))
        {
-         rtx result;
+         rtx result, note;
          if (dump_file)
            {
              print_inline_rtx (dump_file, p->loc, 0);
              fprintf (dump_file, "\n");
            }
+         if (GET_CODE (p->loc) == LO_SUM
+             && GET_CODE (XEXP (p->loc, 1)) == SYMBOL_REF
+             && p->setting_insn
+             && (note = find_reg_note (p->setting_insn, REG_EQUAL, NULL_RTX))
+             && XEXP (note, 0) == XEXP (p->loc, 1))
+           return XEXP (p->loc, 1);
          result = cselib_expand_value_rtx (p->loc, regs_active, max_depth - 1);
          if (result)
            return result;
@@ -928,6 +935,7 @@ cselib_expand_value_rtx (rtx orig, bitmap regs_active, int max_depth)
   int i, j;
   RTX_CODE code;
   const char *format_ptr;
+  enum machine_mode mode;
 
   code = GET_CODE (orig);
 
@@ -1007,25 +1015,30 @@ cselib_expand_value_rtx (rtx orig, bitmap regs_active, int max_depth)
        return orig;
       break;
 
-
-    case VALUE:
+    case SUBREG:
       {
-       rtx result;
-       if (dump_file)
-         fprintf (dump_file, "expanding value %s into: ", GET_MODE_NAME (GET_MODE (orig)));
-       
-       result = expand_loc (CSELIB_VAL_PTR (orig)->locs, regs_active, max_depth);
-       if (result 
-           && GET_CODE (result) == CONST_INT
-           && GET_MODE (orig) != VOIDmode)
-         {
-           result = gen_rtx_CONST (GET_MODE (orig), result);
-           if (dump_file)
-             fprintf (dump_file, "  wrapping const_int result in const to preserve mode %s\n", 
-                      GET_MODE_NAME (GET_MODE (orig)));
-         }
-       return result;
+       rtx subreg = cselib_expand_value_rtx (SUBREG_REG (orig), regs_active,
+                                             max_depth - 1);
+       if (!subreg)
+         return NULL;
+       scopy = simplify_gen_subreg (GET_MODE (orig), subreg,
+                                    GET_MODE (SUBREG_REG (orig)),
+                                    SUBREG_BYTE (orig));
+       if (scopy == NULL
+           || (GET_CODE (scopy) == SUBREG
+               && !REG_P (SUBREG_REG (scopy))
+               && !MEM_P (SUBREG_REG (scopy))))
+         return shallow_copy_rtx (orig);
+       return scopy;
       }
+
+    case VALUE:
+      if (dump_file)
+       fprintf (dump_file, "expanding value %s into: ",
+                GET_MODE_NAME (GET_MODE (orig)));
+
+      return expand_loc (CSELIB_VAL_PTR (orig)->locs, regs_active, max_depth);
+
     default:
       break;
     }
@@ -1036,9 +1049,9 @@ cselib_expand_value_rtx (rtx orig, bitmap regs_active, int max_depth)
      us to explicitly document why we are *not* copying a flag.  */
   copy = shallow_copy_rtx (orig);
 
-  format_ptr = GET_RTX_FORMAT (GET_CODE (copy));
+  format_ptr = GET_RTX_FORMAT (code);
 
-  for (i = 0; i < GET_RTX_LENGTH (GET_CODE (copy)); i++)
+  for (i = 0; i < GET_RTX_LENGTH (code); i++)
     switch (*format_ptr++)
       {
       case 'e':
@@ -1082,6 +1095,70 @@ cselib_expand_value_rtx (rtx orig, bitmap regs_active, int max_depth)
        gcc_unreachable ();
       }
 
+  mode = GET_MODE (copy);
+  /* If an operand has been simplified into CONST_INT, which doesn't
+     have a mode and the mode isn't derivable from whole rtx's mode,
+     try simplify_*_operation first with mode from original's operand
+     and as a fallback wrap CONST_INT into gen_rtx_CONST.  */
+  scopy = copy;
+  switch (GET_RTX_CLASS (code))
+    {
+    case RTX_UNARY:
+      if (CONST_INT_P (XEXP (copy, 0))
+         && GET_MODE (XEXP (orig, 0)) != VOIDmode)
+       {
+         scopy = simplify_unary_operation (code, mode, XEXP (copy, 0),
+                                           GET_MODE (XEXP (orig, 0)));
+         if (scopy)
+           return scopy;
+       }
+      break;
+    case RTX_COMM_ARITH:
+    case RTX_BIN_ARITH:
+      /* These expressions can derive operand modes from the whole rtx's mode.  */
+      break;
+    case RTX_TERNARY:
+    case RTX_BITFIELD_OPS:
+      if (CONST_INT_P (XEXP (copy, 0))
+         && GET_MODE (XEXP (orig, 0)) != VOIDmode)
+       {
+         scopy = simplify_ternary_operation (code, mode,
+                                             GET_MODE (XEXP (orig, 0)),
+                                             XEXP (copy, 0), XEXP (copy, 1),
+                                             XEXP (copy, 2));
+         if (scopy)
+           return scopy;
+       }
+      break;
+    case RTX_COMPARE:
+    case RTX_COMM_COMPARE:
+      if (CONST_INT_P (XEXP (copy, 0))
+         && GET_MODE (XEXP (copy, 1)) == VOIDmode
+         && (GET_MODE (XEXP (orig, 0)) != VOIDmode
+             || GET_MODE (XEXP (orig, 1)) != VOIDmode))
+       {
+         scopy = simplify_relational_operation (code, mode,
+                                                (GET_MODE (XEXP (orig, 0))
+                                                 != VOIDmode)
+                                                ? GET_MODE (XEXP (orig, 0))
+                                                : GET_MODE (XEXP (orig, 1)),
+                                                XEXP (copy, 0),
+                                                XEXP (copy, 1));
+         if (scopy)
+           return scopy;
+       }
+      break;
+    default:
+      break;
+    }
+  if (scopy == NULL_RTX)
+    {
+      XEXP (copy, 0)
+       = gen_rtx_CONST (GET_MODE (XEXP (orig, 0)), XEXP (copy, 0));
+      if (dump_file)
+       fprintf (dump_file, "  wrapping const_int result in const to preserve mode %s\n",
+                GET_MODE_NAME (GET_MODE (XEXP (copy, 0))));
+    }
   scopy = simplify_rtx (copy);
   if (scopy)
     return scopy;
@@ -1581,6 +1658,17 @@ cselib_record_sets (rtx insn)
        }
     }
 
+  if (n_sets == 1
+      && MEM_P (sets[0].src)
+      && !cselib_record_memory
+      && MEM_READONLY_P (sets[0].src))
+    {
+      rtx note = find_reg_equal_equiv_note (insn);
+
+      if (note && CONSTANT_P (XEXP (note, 0)))
+       sets[0].src = XEXP (note, 0);
+    }
+
   /* Look up the values that are read.  Do this before invalidating the
      locations that are written.  */
   for (i = 0; i < n_sets; i++)