OSDN Git Service

2008-05-03 H.J. Lu <hongjiu.lu@intel.com>
[pf3gnuchains/gcc-fork.git] / gcc / simplify-rtx.c
index 03fbc75..44f3ef5 100644 (file)
@@ -859,8 +859,8 @@ simplify_unary_operation_1 (enum rtx_code code, enum machine_mode mode, rtx op)
       if (GET_CODE (op) == SUBREG
          && SUBREG_PROMOTED_VAR_P (op)
          && ! SUBREG_PROMOTED_UNSIGNED_P (op)
-         && GET_MODE (XEXP (op, 0)) == mode)
-       return XEXP (op, 0);
+         && GET_MODE_SIZE (mode) <= GET_MODE_SIZE (GET_MODE (XEXP (op, 0))))
+       return rtl_hooks.gen_lowpart_no_emit (mode, op);
 
 #if defined(POINTERS_EXTEND_UNSIGNED) && !defined(HAVE_ptr_extend)
       if (! POINTERS_EXTEND_UNSIGNED
@@ -881,8 +881,8 @@ simplify_unary_operation_1 (enum rtx_code code, enum machine_mode mode, rtx op)
       if (GET_CODE (op) == SUBREG
          && SUBREG_PROMOTED_VAR_P (op)
          && SUBREG_PROMOTED_UNSIGNED_P (op) > 0
-         && GET_MODE (XEXP (op, 0)) == mode)
-       return XEXP (op, 0);
+         && GET_MODE_SIZE (mode) <= GET_MODE_SIZE (GET_MODE (XEXP (op, 0))))
+       return rtl_hooks.gen_lowpart_no_emit (mode, op);
 
 #if defined(POINTERS_EXTEND_UNSIGNED) && !defined(HAVE_ptr_extend)
       if (POINTERS_EXTEND_UNSIGNED > 0
@@ -5021,7 +5021,22 @@ simplify_subreg (enum machine_mode outermode, rtx op,
        return newx;
       if (validate_subreg (outermode, innermostmode,
                           SUBREG_REG (op), final_offset))
-        return gen_rtx_SUBREG (outermode, SUBREG_REG (op), final_offset);
+       {
+         newx = gen_rtx_SUBREG (outermode, SUBREG_REG (op), final_offset);
+         if (SUBREG_PROMOTED_VAR_P (op)
+             && SUBREG_PROMOTED_UNSIGNED_P (op) >= 0
+             && GET_MODE_CLASS (outermode) == MODE_INT
+             && IN_RANGE (GET_MODE_SIZE (outermode),
+                          GET_MODE_SIZE (innermode),
+                          GET_MODE_SIZE (innermostmode))
+             && subreg_lowpart_p (newx))
+           {
+             SUBREG_PROMOTED_VAR_P (newx) = 1;
+             SUBREG_PROMOTED_UNSIGNED_SET
+               (newx, SUBREG_PROMOTED_UNSIGNED_P (op));
+           }
+         return newx;
+       }
       return NULL_RTX;
     }
 
@@ -5224,6 +5239,22 @@ simplify_subreg (enum machine_mode outermode, rtx op,
     return simplify_gen_binary (ASHIFT, outermode,
                                XEXP (XEXP (op, 0), 0), XEXP (op, 1));
 
+  /* Recognize a word extraction from a multi-word subreg.  */
+  if ((GET_CODE (op) == LSHIFTRT
+       || GET_CODE (op) == ASHIFTRT)
+      && SCALAR_INT_MODE_P (outermode)
+      && GET_MODE_BITSIZE (outermode) >= BITS_PER_WORD
+      && GET_MODE_BITSIZE (innermode) >= (2 * GET_MODE_BITSIZE (outermode))
+      && GET_CODE (XEXP (op, 1)) == CONST_INT
+      && (INTVAL (XEXP (op, 1)) & (GET_MODE_BITSIZE (outermode) - 1)) == 0
+      && 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));
+    }
+
   return NULL_RTX;
 }