[ARM/AArch64][2/2] Crypto intrinsics tuning for Cortex-A53 - pipeline description
[gcc.git] / gcc / simplify-rtx.c
index 791f91a34a87b5a0ed1a96e8ce421fe23dcf38aa..04af01e6ea2420bc0a93326f2c7870176e523f7e 100644 (file)
@@ -1,5 +1,5 @@
 /* RTL simplification functions for GNU compiler.
-   Copyright (C) 1987-2013 Free Software Foundation, Inc.
+   Copyright (C) 1987-2014 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -24,6 +24,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tm.h"
 #include "rtl.h"
 #include "tree.h"
+#include "varasm.h"
 #include "tm_p.h"
 #include "regs.h"
 #include "hard-reg-set.h"
@@ -298,13 +299,13 @@ delegitimize_mem_from_attrs (rtx x)
                                        &mode, &unsignedp, &volatilep, false);
            if (bitsize != GET_MODE_BITSIZE (mode)
                || (bitpos % BITS_PER_UNIT)
-               || (toffset && !host_integerp (toffset, 0)))
+               || (toffset && !tree_fits_shwi_p (toffset)))
              decl = NULL;
            else
              {
                offset += bitpos / BITS_PER_UNIT;
                if (toffset)
-                 offset += TREE_INT_CST_LOW (toffset);
+                 offset += tree_to_shwi (toffset);
              }
            break;
          }
@@ -639,11 +640,16 @@ simplify_truncation (enum machine_mode mode, rtx op,
                                   XEXP (op, 0), origmode);
     }
 
-  /* Simplify (truncate:SI (op:DI (x:DI) (y:DI)))
-     to (op:SI (truncate:SI (x:DI)) (truncate:SI (x:DI))).  */
-  if (GET_CODE (op) == PLUS
-      || GET_CODE (op) == MINUS
-      || GET_CODE (op) == MULT)
+  /* If the machine can perform operations in the truncated mode, distribute
+     the truncation, i.e. simplify (truncate:QI (op:SI (x:SI) (y:SI))) into
+     (op:QI (truncate:QI (x:SI)) (truncate:QI (y:SI))).  */
+  if (1
+#ifdef WORD_REGISTER_OPERATIONS
+      && precision >= BITS_PER_WORD
+#endif
+      && (GET_CODE (op) == PLUS
+         || GET_CODE (op) == MINUS
+         || GET_CODE (op) == MULT))
     {
       rtx op0 = simplify_gen_unary (TRUNCATE, mode, XEXP (op, 0), op_mode);
       if (op0)
@@ -825,7 +831,8 @@ simplify_unary_operation_1 (enum rtx_code code, enum machine_mode mode, rtx op)
 
       /* Similarly, (not (neg X)) is (plus X -1).  */
       if (GET_CODE (op) == NEG)
-       return plus_constant (mode, XEXP (op, 0), -1);
+       return simplify_gen_binary (PLUS, mode, XEXP (op, 0),
+                                   CONSTM1_RTX (mode));
 
       /* (not (xor X C)) for C constant is (xor X D) with D = ~C.  */
       if (GET_CODE (op) == XOR
@@ -858,7 +865,6 @@ simplify_unary_operation_1 (enum rtx_code code, enum machine_mode mode, rtx op)
       /* (not (ashiftrt foo C)) where C is the number of bits in FOO
         minus 1 is (ge foo (const_int 0)) if STORE_FLAG_VALUE is -1,
         so we can perform the above simplification.  */
-
       if (STORE_FLAG_VALUE == -1
          && GET_CODE (op) == ASHIFTRT
          && GET_CODE (XEXP (op, 1))
@@ -890,7 +896,6 @@ simplify_unary_operation_1 (enum rtx_code code, enum machine_mode mode, rtx op)
         with negating logical insns (and-not, nand, etc.).  If result has
         only one NOT, put it first, since that is how the patterns are
         coded.  */
-
       if (GET_CODE (op) == IOR || GET_CODE (op) == AND)
        {
          rtx in1 = XEXP (op, 0), in2 = XEXP (op, 1);
@@ -913,6 +918,13 @@ simplify_unary_operation_1 (enum rtx_code code, enum machine_mode mode, rtx op)
          return gen_rtx_fmt_ee (GET_CODE (op) == IOR ? AND : IOR,
                                 mode, in1, in2);
        }
+
+      /* (not (bswap x)) -> (bswap (not x)).  */
+      if (GET_CODE (op) == BSWAP)
+       {
+         rtx x = simplify_gen_unary (NOT, mode, XEXP (op, 0), mode);
+         return simplify_gen_unary (BSWAP, mode, x, mode);
+       }
       break;
 
     case NEG:
@@ -927,7 +939,8 @@ simplify_unary_operation_1 (enum rtx_code code, enum machine_mode mode, rtx op)
 
       /* Similarly, (neg (not X)) is (plus X 1).  */
       if (GET_CODE (op) == NOT)
-       return plus_constant (mode, XEXP (op, 0), 1);
+       return simplify_gen_binary (PLUS, mode, XEXP (op, 0),
+                                   CONST1_RTX (mode));
 
       /* (neg (minus X Y)) can become (minus Y X).  This transformation
         isn't safe for modes with signed zeros, since if X and Y are
@@ -1465,6 +1478,29 @@ simplify_unary_operation_1 (enum rtx_code code, enum machine_mode mode, rtx op)
            }
        }
 
+      /* (zero_extend:M (subreg:N <X:O>)) is <X:O> (for M == O) or
+        (zero_extend:M <X:O>), if X doesn't have any non-zero bits outside
+        of mode N.  E.g.
+        (zero_extend:SI (subreg:QI (and:SI (reg:SI) (const_int 63)) 0)) is
+        (and:SI (reg:SI) (const_int 63)).  */
+      if (GET_CODE (op) == SUBREG
+         && GET_MODE_PRECISION (GET_MODE (op))
+            < GET_MODE_PRECISION (GET_MODE (SUBREG_REG (op)))
+         && GET_MODE_PRECISION (GET_MODE (SUBREG_REG (op)))
+            <= HOST_BITS_PER_WIDE_INT
+         && GET_MODE_PRECISION (mode)
+            >= GET_MODE_PRECISION (GET_MODE (SUBREG_REG (op)))
+         && subreg_lowpart_p (op)
+         && (nonzero_bits (SUBREG_REG (op), GET_MODE (SUBREG_REG (op)))
+             & ~GET_MODE_MASK (GET_MODE (op))) == 0)
+       {
+         if (GET_MODE_PRECISION (mode)
+             == GET_MODE_PRECISION (GET_MODE (SUBREG_REG (op))))
+           return SUBREG_REG (op);
+         return simplify_gen_unary (ZERO_EXTEND, mode, SUBREG_REG (op),
+                                    GET_MODE (SUBREG_REG (op)));
+       }
+
 #if defined(POINTERS_EXTEND_UNSIGNED) && !defined(HAVE_ptr_extend)
       /* As we do not know which address space the pointer is referring to,
         we can do this only if the target does not support different pointer
@@ -1611,7 +1647,7 @@ simplify_const_unary_operation (enum rtx_code code, enum machine_mode mode,
          break;
 
        case NEG:
-         val = - arg0;
+         val = - (unsigned HOST_WIDE_INT) arg0;
          break;
 
        case ABS:
@@ -1900,17 +1936,13 @@ simplify_const_unary_operation (enum rtx_code code, enum machine_mode mode,
           && SCALAR_FLOAT_MODE_P (mode)
           && SCALAR_FLOAT_MODE_P (GET_MODE (op)))
     {
-      REAL_VALUE_TYPE d, t;
+      REAL_VALUE_TYPE d;
       REAL_VALUE_FROM_CONST_DOUBLE (d, op);
 
       switch (code)
        {
        case SQRT:
-         if (HONOR_SNANS (mode) && real_isnan (&d))
-           return 0;
-         real_sqrt (&t, mode, &d);
-         d = t;
-         break;
+         return 0;
        case ABS:
          d = real_value_abs (&d);
          break;
@@ -1990,14 +2022,13 @@ simplify_const_unary_operation (enum rtx_code code, enum machine_mode mode,
          /* Test against the signed lower bound.  */
          if (width > HOST_BITS_PER_WIDE_INT)
            {
-             th = (unsigned HOST_WIDE_INT) (-1)
-                  << (width - HOST_BITS_PER_WIDE_INT - 1);
+             th = HOST_WIDE_INT_M1U << (width - HOST_BITS_PER_WIDE_INT - 1);
              tl = 0;
            }
          else
            {
              th = -1;
-             tl = (unsigned HOST_WIDE_INT) (-1) << (width - 1);
+             tl = HOST_WIDE_INT_M1U << (width - 1);
            }
          real_from_integer (&t, VOIDmode, tl, th, 0);
          if (REAL_VALUES_LESS (x, t))
@@ -2050,6 +2081,35 @@ simplify_const_unary_operation (enum rtx_code code, enum machine_mode mode,
   return NULL_RTX;
 }
 \f
+/* Subroutine of simplify_binary_operation to simplify a binary operation
+   CODE that can commute with byte swapping, with result mode MODE and
+   operating on OP0 and OP1.  CODE is currently one of AND, IOR or XOR.
+   Return zero if no simplification or canonicalization is possible.  */
+
+static rtx
+simplify_byte_swapping_operation (enum rtx_code code, enum machine_mode mode,
+                                 rtx op0, rtx op1)
+{
+  rtx tem;
+
+  /* (op (bswap x) C1)) -> (bswap (op x C2)) with C2 swapped.  */
+  if (GET_CODE (op0) == BSWAP && CONST_SCALAR_INT_P (op1))
+    {
+      tem = simplify_gen_binary (code, mode, XEXP (op0, 0),
+                                simplify_gen_unary (BSWAP, mode, op1, mode));
+      return simplify_gen_unary (BSWAP, mode, tem, mode);
+    }
+
+  /* (op (bswap x) (bswap y)) -> (bswap (op x y)).  */
+  if (GET_CODE (op0) == BSWAP && GET_CODE (op1) == BSWAP)
+    {
+      tem = simplify_gen_binary (code, mode, XEXP (op0, 0), XEXP (op1, 0));
+      return simplify_gen_unary (BSWAP, mode, tem, mode);
+    }
+
+  return NULL_RTX;
+}
+
 /* Subroutine of simplify_binary_operation to simplify a commutative,
    associative binary operation CODE with result mode MODE, operating
    on OP0 and OP1.  CODE is currently one of PLUS, MULT, AND, IOR, XOR,
@@ -2762,12 +2822,13 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
          && CONST_INT_P (XEXP (op0, 1))
          && CONST_INT_P (op1)
          && (UINTVAL (XEXP (op0, 1)) & UINTVAL (op1)) != 0)
-       return simplify_gen_binary (IOR, mode,
-                                   simplify_gen_binary
-                                         (AND, mode, XEXP (op0, 0),
-                                          GEN_INT (UINTVAL (XEXP (op0, 1))
-                                                   & ~UINTVAL (op1))),
-                                   op1);
+       {
+         rtx tmp = simplify_gen_binary (AND, mode, XEXP (op0, 0),
+                                        gen_int_mode (UINTVAL (XEXP (op0, 1))
+                                                      & ~UINTVAL (op1),
+                                                      mode));
+         return simplify_gen_binary (IOR, mode, tmp, op1);
+       }
 
       /* If OP0 is (ashiftrt (plus ...) C), it might actually be
          a (sign_extend (plus ...)).  Then check if OP1 is a CONST_INT and
@@ -2784,6 +2845,7 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
           HOST_WIDE_INT mask = INTVAL (trueop1) << count;
 
           if (mask >> count == INTVAL (trueop1)
+             && trunc_int_for_mode (mask, mode) == mask
               && (mask & nonzero_bits (XEXP (op0, 0), mode)) == 0)
            return simplify_gen_binary (ASHIFTRT, mode,
                                        plus_constant (mode, XEXP (op0, 0),
@@ -2791,6 +2853,10 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
                                        XEXP (op0, 1));
         }
 
+      tem = simplify_byte_swapping_operation (code, mode, op0, op1);
+      if (tem)
+       return tem;
+
       tem = simplify_associative_operation (code, mode, op0, op1);
       if (tem)
        return tem;
@@ -2892,7 +2958,7 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
              /* Try to simplify ~A&C | ~B&C.  */
              if (na_c != NULL_RTX)
                return simplify_gen_binary (IOR, mode, na_c,
-                                           GEN_INT (~bval & cval));
+                                           gen_int_mode (~bval & cval, mode));
            }
          else
            {
@@ -2900,9 +2966,11 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
              if (na_c == const0_rtx)
                {
                  rtx a_nc_b = simplify_gen_binary (AND, mode, a,
-                                                   GEN_INT (~cval & bval));
+                                                   gen_int_mode (~cval & bval,
+                                                                 mode));
                  return simplify_gen_binary (IOR, mode, a_nc_b,
-                                             GEN_INT (~bval & cval));
+                                             gen_int_mode (~bval & cval,
+                                                           mode));
                }
            }
        }
@@ -2934,6 +3002,10 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
          && (reversed = reversed_comparison (op0, mode)))
        return reversed;
 
+      tem = simplify_byte_swapping_operation (code, mode, op0, op1);
+      if (tem)
+       return tem;
+
       tem = simplify_associative_operation (code, mode, op0, op1);
       if (tem)
        return tem;
@@ -3116,6 +3188,10 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
          && op1 == XEXP (XEXP (op0, 0), 0))
        return simplify_gen_binary (AND, mode, op1, XEXP (op0, 1));
 
+      tem = simplify_byte_swapping_operation (code, mode, op0, op1);
+      if (tem)
+       return tem;
+
       tem = simplify_associative_operation (code, mode, op0, op1);
       if (tem)
        return tem;
@@ -3228,7 +3304,7 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
       if (CONST_INT_P (trueop1)
          && exact_log2 (UINTVAL (trueop1)) > 0)
        return simplify_gen_binary (AND, mode, op0,
-                                   GEN_INT (INTVAL (op1) - 1));
+                                   gen_int_mode (INTVAL (op1) - 1, mode));
       break;
 
     case MOD:
@@ -3250,6 +3326,18 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
 
     case ROTATERT:
     case ROTATE:
+      /* Canonicalize rotates by constant amount.  If op1 is bitsize / 2,
+        prefer left rotation, if op1 is from bitsize / 2 + 1 to
+        bitsize - 1, use other direction of rotate with 1 .. bitsize / 2 - 1
+        amount instead.  */
+      if (CONST_INT_P (trueop1)
+         && IN_RANGE (INTVAL (trueop1),
+                      GET_MODE_BITSIZE (mode) / 2 + (code == ROTATE),
+                      GET_MODE_BITSIZE (mode) - 1))
+       return simplify_gen_binary (code == ROTATE ? ROTATERT : ROTATE,
+                                   mode, op0, GEN_INT (GET_MODE_BITSIZE (mode)
+                                                       - INTVAL (trueop1)));
+      /* FALLTHRU */
     case ASHIFTRT:
       if (trueop1 == CONST0_RTX (mode))
        return op0;
@@ -4029,15 +4117,15 @@ simplify_const_binary_operation (enum rtx_code code, enum machine_mode mode,
       switch (code)
        {
        case PLUS:
-         val = arg0s + arg1s;
+         val = (unsigned HOST_WIDE_INT) arg0s + arg1s;
          break;
 
        case MINUS:
-         val = arg0s - arg1s;
+         val = (unsigned HOST_WIDE_INT) arg0s - arg1s;
          break;
 
        case MULT:
-         val = arg0s * arg1s;
+         val = (unsigned HOST_WIDE_INT) arg0s * arg1s;
          break;
 
        case DIV:
@@ -4109,7 +4197,7 @@ simplify_const_binary_operation (enum rtx_code code, enum machine_mode mode,
 
          /* Sign-extend the result for arithmetic right shifts.  */
          if (code == ASHIFTRT && arg0s < 0 && arg1 > 0)
-           val |= ((unsigned HOST_WIDE_INT) (-1)) << (width - arg1);
+           val |= HOST_WIDE_INT_M1U << (width - arg1);
          break;
 
        case ROTATERT:
@@ -4752,6 +4840,21 @@ simplify_relational_operation_1 (enum rtx_code code, enum machine_mode mode,
                                    simplify_gen_binary (XOR, cmp_mode,
                                                         XEXP (op0, 1), op1));
 
+  /* (eq/ne (bswap x) C1) simplifies to (eq/ne x C2) with C2 swapped.  */
+  if ((code == EQ || code == NE)
+      && GET_CODE (op0) == BSWAP
+      && CONST_SCALAR_INT_P (op1))
+    return simplify_gen_relational (code, mode, cmp_mode, XEXP (op0, 0),
+                                   simplify_gen_unary (BSWAP, cmp_mode,
+                                                       op1, cmp_mode));
+
+  /* (eq/ne (bswap x) (bswap y)) simplifies to (eq/ne x y).  */
+  if ((code == EQ || code == NE)
+      && GET_CODE (op0) == BSWAP
+      && GET_CODE (op1) == BSWAP)
+    return simplify_gen_relational (code, mode, cmp_mode,
+                                   XEXP (op0, 0), XEXP (op1, 0));
+
   if (op0code == POPCOUNT && op1 == const0_rtx)
     switch (code)
       {