OSDN Git Service

PR fortran/27553
[pf3gnuchains/gcc-fork.git] / gcc / simplify-rtx.c
index 5a5c5ca..962c2de 100644 (file)
@@ -1,6 +1,6 @@
 /* RTL simplification functions for GNU compiler.
    Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -584,6 +584,35 @@ simplify_unary_operation_1 (enum rtx_code code, enum machine_mode mode, rtx op)
          && XEXP (op, 1) == const1_rtx
          && nonzero_bits (XEXP (op, 0), mode) == 1)
        return plus_constant (XEXP (op, 0), -1);
+
+      /* (neg (lt x 0)) is (ashiftrt X C) if STORE_FLAG_VALUE is 1.  */
+      /* (neg (lt x 0)) is (lshiftrt X C) if STORE_FLAG_VALUE is -1.  */
+      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)
+           {
+             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)
+           {
+             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;
 
     case TRUNCATE:
@@ -609,22 +638,27 @@ simplify_unary_operation_1 (enum rtx_code code, enum machine_mode mode, rtx op)
        return simplify_gen_unary (GET_CODE (op), mode,
                                   XEXP (XEXP (op, 0), 0), mode);
 
-      /* (truncate:SI (subreg:DI (truncate:SI X) 0)) is
-        (truncate:SI x).  */
+      /* (truncate:A (subreg:B (truncate:C X) 0)) is
+        (truncate:A X).  */
       if (GET_CODE (op) == SUBREG
          && GET_CODE (SUBREG_REG (op)) == TRUNCATE
          && subreg_lowpart_p (op))
-       return SUBREG_REG (op);
+       return simplify_gen_unary (TRUNCATE, mode, XEXP (SUBREG_REG (op), 0),
+                                  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);
@@ -1058,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:
@@ -2388,6 +2423,7 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
       /* Fall through....  */
 
     case ASHIFT:
+    case SS_ASHIFT:
     case LSHIFTRT:
       if (trueop1 == CONST0_RTX (mode))
        return op0;
@@ -3076,6 +3112,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;
          
@@ -3287,8 +3324,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
@@ -3471,8 +3521,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;
 
@@ -3498,7 +3547,8 @@ simplify_relational_operation_1 (enum rtx_code code, enum machine_mode mode,
     {
       if (INTVAL (op1) == 0 && COMPARISON_P (op0))
        {
-         /* If op0 is a comparison, extract the comparison arguments form it.  */
+         /* If op0 is a comparison, extract the comparison arguments
+            from it.  */
          if (code == NE)
            {
              if (GET_MODE (op0) == mode)
@@ -3547,6 +3597,37 @@ simplify_relational_operation_1 (enum rtx_code code, enum machine_mode mode,
           ? simplify_gen_unary (ZERO_EXTEND, mode, op0, cmp_mode)
           : lowpart_subreg (mode, op0, cmp_mode);
 
+  /* (eq/ne (xor x y) 0) simplifies to (eq/ne x y).  */
+  if ((code == EQ || code == NE)
+      && op1 == const0_rtx
+      && op0code == XOR)
+    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).  */
+  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).  */
+  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);
+
+  /* (eq/ne (xor x C1) C2) simplifies to (eq/ne x (C1^C2)).  */
+  if ((code == EQ || code == NE)
+      && op0code == XOR
+      && (GET_CODE (op1) == CONST_INT
+         || GET_CODE (op1) == CONST_DOUBLE)
+      && (GET_CODE (XEXP (op0, 1)) == CONST_INT
+         || GET_CODE (XEXP (op0, 1)) == CONST_DOUBLE))
+    return simplify_gen_relational (code, mode, cmp_mode, XEXP (op0, 0),
+                                   simplify_gen_binary (XOR, cmp_mode,
+                                                        XEXP (op0, 1), op1));
+
   return NULL_RTX;
 }
 
@@ -4425,6 +4506,14 @@ simplify_subreg (enum machine_mode outermode, rtx op,
       return NULL_RTX;
     }
 
+  /* Merge implicit and explicit truncations.  */
+
+  if (GET_CODE (op) == TRUNCATE
+      && GET_MODE_SIZE (outermode) < GET_MODE_SIZE (innermode)
+      && subreg_lowpart_offset (outermode, innermode) == byte)
+    return simplify_gen_unary (TRUNCATE, outermode, XEXP (op, 0),
+                              GET_MODE (XEXP (op, 0)));
+
   /* SUBREG of a hard register => just change the register number
      and/or mode.  If the hard register is not valid in that mode,
      suppress this simplification.  If the hard register is the stack,