OSDN Git Service

2009-10-13 Steve Ellcey <sje@cup.hp.com>
[pf3gnuchains/gcc-fork.git] / gcc / simplify-rtx.c
index 782d717..4e87d04 100644 (file)
@@ -202,6 +202,106 @@ avoid_constant_pool_reference (rtx x)
   return x;
 }
 \f
+/* Simplify a MEM based on its attributes.  This is the default
+   delegitimize_address target hook, and it's recommended that every
+   overrider call it.  */
+
+rtx
+delegitimize_mem_from_attrs (rtx x)
+{
+  if (MEM_P (x)
+      && MEM_EXPR (x)
+      && (!MEM_OFFSET (x)
+         || GET_CODE (MEM_OFFSET (x)) == CONST_INT))
+    {
+      tree decl = MEM_EXPR (x);
+      enum machine_mode mode = GET_MODE (x);
+      HOST_WIDE_INT offset = 0;
+
+      switch (TREE_CODE (decl))
+       {
+       default:
+         decl = NULL;
+         break;
+
+       case VAR_DECL:
+         break;
+
+       case ARRAY_REF:
+       case ARRAY_RANGE_REF:
+       case COMPONENT_REF:
+       case BIT_FIELD_REF:
+       case REALPART_EXPR:
+       case IMAGPART_EXPR:
+       case VIEW_CONVERT_EXPR:
+         {
+           HOST_WIDE_INT bitsize, bitpos;
+           tree toffset;
+           int unsignedp = 0, volatilep = 0;
+
+           decl = get_inner_reference (decl, &bitsize, &bitpos, &toffset,
+                                       &mode, &unsignedp, &volatilep, false);
+           if (bitsize != GET_MODE_BITSIZE (mode)
+               || (bitpos % BITS_PER_UNIT)
+               || (toffset && !host_integerp (toffset, 0)))
+             decl = NULL;
+           else
+             {
+               offset += bitpos / BITS_PER_UNIT;
+               if (toffset)
+                 offset += TREE_INT_CST_LOW (toffset);
+             }
+           break;
+         }
+       }
+
+      if (decl
+         && mode == GET_MODE (x)
+         && TREE_CODE (decl) == VAR_DECL
+         && (TREE_STATIC (decl)
+             || DECL_THREAD_LOCAL_P (decl))
+         && DECL_RTL_SET_P (decl)
+         && MEM_P (DECL_RTL (decl)))
+       {
+         rtx newx;
+
+         if (MEM_OFFSET (x))
+           offset += INTVAL (MEM_OFFSET (x));
+
+         newx = DECL_RTL (decl);
+
+         if (MEM_P (newx))
+           {
+             rtx n = XEXP (newx, 0), o = XEXP (x, 0);
+
+             /* Avoid creating a new MEM needlessly if we already had
+                the same address.  We do if there's no OFFSET and the
+                old address X is identical to NEWX, or if X is of the
+                form (plus NEWX OFFSET), or the NEWX is of the form
+                (plus Y (const_int Z)) and X is that with the offset
+                added: (plus Y (const_int Z+OFFSET)).  */
+             if (!((offset == 0
+                    || (GET_CODE (o) == PLUS
+                        && GET_CODE (XEXP (o, 1)) == CONST_INT
+                        && (offset == INTVAL (XEXP (o, 1))
+                            || (GET_CODE (n) == PLUS
+                                && GET_CODE (XEXP (n, 1)) == CONST_INT
+                                && (INTVAL (XEXP (n, 1)) + offset
+                                    == INTVAL (XEXP (o, 1)))
+                                && (n = XEXP (n, 0))))
+                        && (o = XEXP (o, 0))))
+                   && rtx_equal_p (o, n)))
+               x = adjust_address_nv (newx, mode, offset);
+           }
+         else if (GET_MODE (x) == GET_MODE (newx)
+                  && offset == 0)
+           x = newx;
+       }
+    }
+
+  return x;
+}
+\f
 /* Make a unary operation by first seeing if it folds and otherwise making
    the specified operation.  */
 
@@ -265,8 +365,8 @@ simplify_replace_rtx (rtx x, const_rtx old_rtx, rtx new_rtx)
      to build a new expression substituting recursively.  If we can't do
      anything, return our input.  */
 
-  if (x == old_rtx)
-    return new_rtx;
+  if (rtx_equal_p (x, old_rtx))
+    return copy_rtx (new_rtx);
 
   switch (GET_RTX_CLASS (code))
     {
@@ -345,11 +445,6 @@ simplify_replace_rtx (rtx x, const_rtx old_rtx, rtx new_rtx)
            return x;
          return gen_rtx_LO_SUM (mode, op0, op1);
        }
-      else if (code == REG)
-       {
-         if (rtx_equal_p (x, old_rtx))
-           return new_rtx;
-       }
       break;
 
     default:
@@ -1997,6 +2092,7 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
       /* x*2 is x+x and x*(-1) is -x */
       if (GET_CODE (trueop1) == CONST_DOUBLE
          && SCALAR_FLOAT_MODE_P (GET_MODE (trueop1))
+         && !DECIMAL_FLOAT_MODE_P (GET_MODE (trueop1))
          && GET_MODE (op0) == mode)
        {
          REAL_VALUE_TYPE d;
@@ -2336,6 +2432,18 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
          return simplify_gen_unary (ZERO_EXTEND, mode, tem, imode);
        }
 
+      /* Transform (and (truncate X) C) into (truncate (and X C)).  This way
+        we might be able to further simplify the AND with X and potentially
+        remove the truncation altogether.  */
+      if (GET_CODE (op0) == TRUNCATE && CONST_INT_P (trueop1))
+       {
+         rtx x = XEXP (op0, 0);
+         enum machine_mode xmode = GET_MODE (x);
+         tem = simplify_gen_binary (AND, xmode, x,
+                                    gen_int_mode (INTVAL (trueop1), xmode));
+         return simplify_gen_unary (TRUNCATE, mode, tem, xmode);
+       }
+
       /* Canonicalize (A | C1) & C2 as (A & C2) | (C1 & C2).  */
       if (GET_CODE (op0) == IOR
          && CONST_INT_P (trueop1)
@@ -5250,13 +5358,15 @@ simplify_subreg (enum machine_mode outermode, rtx op,
       && GET_MODE_BITSIZE (innermode) >= (2 * GET_MODE_BITSIZE (outermode))
       && CONST_INT_P (XEXP (op, 1))
       && (INTVAL (XEXP (op, 1)) & (GET_MODE_BITSIZE (outermode) - 1)) == 0
+      && INTVAL (XEXP (op, 1)) >= 0
       && INTVAL (XEXP (op, 1)) < GET_MODE_BITSIZE (innermode)      
       && byte == subreg_lowpart_offset (outermode, innermode))
     {
       int shifted_bytes = INTVAL (XEXP (op, 1)) / BITS_PER_UNIT;
       return simplify_gen_subreg (outermode, XEXP (op, 0), innermode,
                                  (WORDS_BIG_ENDIAN
-                                  ? byte - shifted_bytes : byte + shifted_bytes));
+                                  ? byte - shifted_bytes
+                                  : byte + shifted_bytes));
     }
 
   return NULL_RTX;