OSDN Git Service

* data.c (gfc_assign_data_value): Handle USE_MAPPED_LOCATION.
[pf3gnuchains/gcc-fork.git] / gcc / simplify-rtx.c
index e84beda..3f627e5 100644 (file)
@@ -590,12 +590,28 @@ simplify_unary_operation_1 (enum rtx_code code, enum machine_mode mode, rtx op)
       if (GET_CODE (op) == LT
          && XEXP (op, 1) == const0_rtx)
        {
+         enum machine_mode inner = GET_MODE (XEXP (op, 0));
+         int isize = GET_MODE_BITSIZE (inner);
          if (STORE_FLAG_VALUE == 1)
-           return simplify_gen_binary (ASHIFTRT, mode, XEXP (op, 0),
-                                       GEN_INT (GET_MODE_BITSIZE (mode) - 1));
+           {
+             temp = simplify_gen_binary (ASHIFTRT, inner, XEXP (op, 0),
+                                         GEN_INT (isize - 1));
+             if (mode == inner)
+               return temp;
+             if (GET_MODE_BITSIZE (mode) > isize)
+               return simplify_gen_unary (SIGN_EXTEND, mode, temp, inner);
+             return simplify_gen_unary (TRUNCATE, mode, temp, inner);
+           }
          else if (STORE_FLAG_VALUE == -1)
-           return simplify_gen_binary (LSHIFTRT, mode, XEXP (op, 0),
-                                       GEN_INT (GET_MODE_BITSIZE (mode) - 1));
+           {
+             temp = simplify_gen_binary (LSHIFTRT, inner, XEXP (op, 0),
+                                         GEN_INT (isize - 1));
+             if (mode == inner)
+               return temp;
+             if (GET_MODE_BITSIZE (mode) > isize)
+               return simplify_gen_unary (ZERO_EXTEND, mode, temp, inner);
+             return simplify_gen_unary (TRUNCATE, mode, temp, inner);
+           }
        }
       break;
 
@@ -631,14 +647,18 @@ simplify_unary_operation_1 (enum rtx_code code, enum machine_mode mode, rtx op)
                                   GET_MODE (XEXP (SUBREG_REG (op), 0)));
 
       /* If we know that the value is already truncated, we can
-         replace the TRUNCATE with a SUBREG if TRULY_NOOP_TRUNCATION
-         is nonzero for the corresponding modes.  But don't do this
-         for an (LSHIFTRT (MULT ...)) since this will cause problems
-         with the umulXi3_highpart patterns.  */
-      if (TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (mode),
+         replace the TRUNCATE with a SUBREG.  Note that this is also
+         valid if TRULY_NOOP_TRUNCATION is false for the corresponding
+         modes we just have to apply a different definition for
+         truncation.  But don't do this for an (LSHIFTRT (MULT ...)) 
+         since this will cause problems with the umulXi3_highpart
+         patterns.  */
+      if ((TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (mode),
                                 GET_MODE_BITSIZE (GET_MODE (op)))
-         && num_sign_bit_copies (op, GET_MODE (op))
-            >= (unsigned int) (GET_MODE_BITSIZE (mode) + 1)
+          ? (num_sign_bit_copies (op, GET_MODE (op))
+             > (unsigned int) (GET_MODE_BITSIZE (GET_MODE (op))
+                               - GET_MODE_BITSIZE (mode)))
+          : truncated_to_mode (mode, op))
          && ! (GET_CODE (op) == LSHIFTRT
                && GET_CODE (XEXP (op, 0)) == MULT))
        return rtl_hooks.gen_lowpart_no_emit (mode, op);
@@ -1072,6 +1092,7 @@ simplify_const_unary_operation (enum rtx_code code, enum machine_mode mode,
        case FLOAT_TRUNCATE:
        case SS_TRUNCATE:
        case US_TRUNCATE:
+       case SS_NEG:
          return 0;
 
        default:
@@ -1451,6 +1472,11 @@ simplify_binary_operation (enum rtx_code code, enum machine_mode mode,
   return simplify_binary_operation_1 (code, mode, op0, op1, trueop0, trueop1);
 }
 
+/* Subroutine of simplify_binary_operation.  Simplify a binary operation
+   CODE with result mode MODE, operating on OP0 and OP1.  If OP0 and/or
+   OP1 are constant pool references, TRUEOP0 and TRUEOP1 represent the
+   actual constants.  */
+
 static rtx
 simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
                             rtx op0, rtx op1, rtx trueop0, rtx trueop1)
@@ -1886,12 +1912,12 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
        return simplify_gen_binary (ASHIFT, mode, op0, GEN_INT (val));
 
       /* Likewise for multipliers wider than a word.  */
-      else if (GET_CODE (trueop1) == CONST_DOUBLE
-              && (GET_MODE (trueop1) == VOIDmode
-                  || GET_MODE_CLASS (GET_MODE (trueop1)) == MODE_INT)
-              && GET_MODE (op0) == mode
-              && CONST_DOUBLE_LOW (trueop1) == 0
-              && (val = exact_log2 (CONST_DOUBLE_HIGH (trueop1))) >= 0)
+      if (GET_CODE (trueop1) == CONST_DOUBLE
+         && (GET_MODE (trueop1) == VOIDmode
+             || GET_MODE_CLASS (GET_MODE (trueop1)) == MODE_INT)
+         && GET_MODE (op0) == mode
+         && CONST_DOUBLE_LOW (trueop1) == 0
+         && (val = exact_log2 (CONST_DOUBLE_HIGH (trueop1))) >= 0)
        return simplify_gen_binary (ASHIFT, mode, op0,
                                    GEN_INT (val + HOST_BITS_PER_WIDE_INT));
 
@@ -1906,10 +1932,27 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
          if (REAL_VALUES_EQUAL (d, dconst2))
            return simplify_gen_binary (PLUS, mode, op0, copy_rtx (op0));
 
-         if (REAL_VALUES_EQUAL (d, dconstm1))
+         if (!HONOR_SNANS (mode)
+             && REAL_VALUES_EQUAL (d, dconstm1))
            return simplify_gen_unary (NEG, mode, op0, mode);
        }
 
+      /* Optimize -x * -x as x * x.  */
+      if (FLOAT_MODE_P (mode)
+         && GET_CODE (op0) == NEG
+         && GET_CODE (op1) == NEG
+         && rtx_equal_p (XEXP (op0, 0), XEXP (op1, 0))
+         && !side_effects_p (XEXP (op0, 0)))
+       return simplify_gen_binary (MULT, mode, XEXP (op0, 0), XEXP (op1, 0));
+
+      /* Likewise, optimize abs(x) * abs(x) as x * x.  */
+      if (SCALAR_FLOAT_MODE_P (mode)
+         && GET_CODE (op0) == ABS
+         && GET_CODE (op1) == ABS
+         && rtx_equal_p (XEXP (op0, 0), XEXP (op1, 0))
+         && !side_effects_p (XEXP (op0, 0)))
+       return simplify_gen_binary (MULT, mode, XEXP (op0, 0), XEXP (op1, 0));
+
       /* Reassociate multiplication, but for floating point MULTs
         only when the user specifies unsafe math optimizations.  */
       if (! FLOAT_MODE_P (mode)
@@ -2393,20 +2436,45 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
     case ROTATERT:
     case ROTATE:
     case ASHIFTRT:
+      if (trueop1 == CONST0_RTX (mode))
+       return op0;
+      if (trueop0 == CONST0_RTX (mode) && ! side_effects_p (op1))
+       return op0;
       /* Rotating ~0 always results in ~0.  */
       if (GET_CODE (trueop0) == CONST_INT && width <= HOST_BITS_PER_WIDE_INT
          && (unsigned HOST_WIDE_INT) INTVAL (trueop0) == GET_MODE_MASK (mode)
          && ! side_effects_p (op1))
        return op0;
-
-      /* Fall through....  */
+      break;
 
     case ASHIFT:
+    case SS_ASHIFT:
+      if (trueop1 == CONST0_RTX (mode))
+       return op0;
+      if (trueop0 == CONST0_RTX (mode) && ! side_effects_p (op1))
+       return op0;
+      break;
+
     case LSHIFTRT:
       if (trueop1 == CONST0_RTX (mode))
        return op0;
       if (trueop0 == CONST0_RTX (mode) && ! side_effects_p (op1))
        return op0;
+      /* Optimize (lshiftrt (clz X) C) as (eq X 0).  */
+      if (GET_CODE (op0) == CLZ
+         && GET_CODE (trueop1) == CONST_INT
+         && STORE_FLAG_VALUE == 1
+         && INTVAL (trueop1) < (HOST_WIDE_INT)width)
+       {
+         enum machine_mode imode = GET_MODE (XEXP (op0, 0));
+         unsigned HOST_WIDE_INT zero_val = 0;
+
+         if (CLZ_DEFINED_VALUE_AT_ZERO (imode, zero_val)
+             && zero_val == GET_MODE_BITSIZE (imode)
+             && INTVAL (trueop1) == exact_log2 (zero_val))
+           return simplify_gen_relational (EQ, mode, imode,
+                                           XEXP (op0, 0), const0_rtx);
+       }
       break;
 
     case SMIN:
@@ -3090,6 +3158,7 @@ simplify_const_binary_operation (enum rtx_code code, enum machine_mode mode,
        case US_PLUS:
        case SS_MINUS:
        case US_MINUS:
+       case SS_ASHIFT:
          /* ??? There are simplifications that can be done.  */
          return 0;
          
@@ -3301,8 +3370,21 @@ simplify_plus_minus (enum rtx_code code, enum machine_mode mode, rtx op0,
                else if (swap_commutative_operands_p (lhs, rhs))
                  tem = lhs, lhs = rhs, rhs = tem;
 
-               tem = simplify_binary_operation (ncode, mode, lhs, rhs);
+               if ((GET_CODE (lhs) == CONST || GET_CODE (lhs) == CONST_INT)
+                   && (GET_CODE (rhs) == CONST || GET_CODE (rhs) == CONST_INT))
+                 {
+                   rtx tem_lhs, tem_rhs;
 
+                   tem_lhs = GET_CODE (lhs) == CONST ? XEXP (lhs, 0) : lhs;
+                   tem_rhs = GET_CODE (rhs) == CONST ? XEXP (rhs, 0) : rhs;
+                   tem = simplify_binary_operation (ncode, mode, tem_lhs, tem_rhs);
+
+                   if (tem && !CONSTANT_P (tem))
+                     tem = gen_rtx_CONST (GET_MODE (tem), tem);
+                 }
+               else
+                 tem = simplify_binary_operation (ncode, mode, lhs, rhs);
+               
                /* Reject "simplifications" that just wrap the two
                   arguments in a CONST.  Failure to do so can result
                   in infinite recursion with simplify_binary_operation
@@ -3485,8 +3567,7 @@ simplify_relational_operation (enum rtx_code code, enum machine_mode mode,
     return simplify_relational_operation (code, mode, VOIDmode,
                                          XEXP (op0, 0), XEXP (op0, 1));
 
-  if (mode == VOIDmode
-      || GET_MODE_CLASS (cmp_mode) == MODE_CC
+  if (GET_MODE_CLASS (cmp_mode) == MODE_CC
       || CC0_P (op0))
     return NULL_RTX;
 
@@ -3569,18 +3650,21 @@ simplify_relational_operation_1 (enum rtx_code code, enum machine_mode mode,
     return simplify_gen_relational (code, mode, cmp_mode,
                                    XEXP (op0, 0), XEXP (op0, 1));
 
-  /* (eq/ne (xor x y) x) simplifies to (eq/ne x 0).  */
+  /* (eq/ne (xor x y) x) simplifies to (eq/ne y 0).  */
   if ((code == EQ || code == NE)
       && op0code == XOR
       && rtx_equal_p (XEXP (op0, 0), op1)
-      && !side_effects_p (XEXP (op0, 1)))
-    return simplify_gen_relational (code, mode, cmp_mode, op1, const0_rtx);
-  /* Likewise (eq/ne (xor x y) y) simplifies to (eq/ne y 0).  */
+      && !side_effects_p (XEXP (op0, 0)))
+    return simplify_gen_relational (code, mode, cmp_mode,
+                                   XEXP (op0, 1), const0_rtx);
+
+  /* Likewise (eq/ne (xor x y) y) simplifies to (eq/ne x 0).  */
   if ((code == EQ || code == NE)
       && op0code == XOR
       && rtx_equal_p (XEXP (op0, 1), op1)
-      && !side_effects_p (XEXP (op0, 0)))
-    return simplify_gen_relational (code, mode, cmp_mode, op1, const0_rtx);
+      && !side_effects_p (XEXP (op0, 1)))
+    return simplify_gen_relational (code, mode, cmp_mode,
+                                   XEXP (op0, 0), const0_rtx);
 
   /* (eq/ne (xor x C1) C2) simplifies to (eq/ne x (C1^C2)).  */
   if ((code == EQ || code == NE)
@@ -4514,7 +4598,22 @@ simplify_subreg (enum machine_mode outermode, rtx op,
       if (HARD_REGNO_MODE_OK (final_regno, outermode)
          || ! HARD_REGNO_MODE_OK (regno, innermode))
        {
-         rtx x = gen_rtx_REG_offset (op, outermode, final_regno, byte);
+         rtx x;
+         int final_offset = byte;
+
+         /* Adjust offset for paradoxical subregs.  */
+         if (byte == 0
+             && GET_MODE_SIZE (innermode) < GET_MODE_SIZE (outermode))
+           {
+             int difference = (GET_MODE_SIZE (innermode)
+                               - GET_MODE_SIZE (outermode));
+             if (WORDS_BIG_ENDIAN)
+               final_offset += (difference / UNITS_PER_WORD) * UNITS_PER_WORD;
+             if (BYTES_BIG_ENDIAN)
+               final_offset += difference % UNITS_PER_WORD;
+           }
+
+         x = gen_rtx_REG_offset (op, outermode, final_regno, final_offset);
 
          /* Propagate original regno.  We don't have any way to specify
             the offset inside original regno, so do so only for lowpart.