Makefile.in (targ): Fix target name check.
[gcc.git] / gcc / simplify-rtx.c
index f26f0083cf6db2d9dd974f35da7e7e68c204839e..791f91a34a87b5a0ed1a96e8ce421fe23dcf38aa 100644 (file)
@@ -1,7 +1,5 @@
 /* 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, 2006, 2007, 2008, 2009, 2010,
-   2011, 2012  Free Software Foundation, Inc.
+   Copyright (C) 1987-2013 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -244,7 +242,8 @@ avoid_constant_pool_reference (rtx x)
       /* If we're accessing the constant in a different mode than it was
          originally stored, attempt to fix that up via subreg simplifications.
          If that fails we have no choice but to return the original memory.  */
-      if (offset != 0 || cmode != GET_MODE (x))
+      if ((offset != 0 || cmode != GET_MODE (x))
+         && offset >= 0 && offset < GET_MODE_SIZE (cmode))
         {
           rtx tem = simplify_subreg (GET_MODE (x), c, cmode, offset);
           if (tem && CONSTANT_P (tem))
@@ -758,8 +757,17 @@ simplify_truncation (enum machine_mode mode, rtx op,
       && SCALAR_INT_MODE_P (GET_MODE (SUBREG_REG (op)))
       && GET_CODE (SUBREG_REG (op)) == TRUNCATE
       && subreg_lowpart_p (op))
-    return simplify_gen_unary (TRUNCATE, mode, XEXP (SUBREG_REG (op), 0),
-                              GET_MODE (XEXP (SUBREG_REG (op), 0)));
+    {
+      rtx inner = XEXP (SUBREG_REG (op), 0);
+      if (GET_MODE_PRECISION (mode)
+         <= GET_MODE_PRECISION (GET_MODE (SUBREG_REG (op))))
+       return simplify_gen_unary (TRUNCATE, mode, inner, GET_MODE (inner));
+      else
+       /* If subreg above is paradoxical and C is narrower
+          than A, return (subreg:A (truncate:C X) 0).  */
+       return simplify_gen_subreg (mode, SUBREG_REG (op),
+                                   GET_MODE (SUBREG_REG (op)), 0);
+    }
 
   /* (truncate:A (truncate:B X)) is (truncate:A X).  */
   if (GET_CODE (op) == TRUNCATE)
@@ -873,7 +881,9 @@ simplify_unary_operation_1 (enum rtx_code code, enum machine_mode mode, rtx op)
                              simplify_gen_unary (NOT, inner_mode, const1_rtx,
                                                  inner_mode),
                              XEXP (SUBREG_REG (op), 1));
-         return rtl_hooks.gen_lowpart_no_emit (mode, x);
+         temp = rtl_hooks.gen_lowpart_no_emit (mode, x);
+         if (temp)
+           return temp;
        }
 
       /* Apply De Morgan's laws to reduce number of patterns for machines
@@ -1029,7 +1039,11 @@ simplify_unary_operation_1 (enum rtx_code code, enum machine_mode mode, rtx op)
       if (GET_MODE_CLASS (mode) == MODE_PARTIAL_INT)
        {
          if (TRULY_NOOP_TRUNCATION_MODES_P (mode, GET_MODE (op)))
-           return rtl_hooks.gen_lowpart_no_emit (mode, op);
+           {
+             temp = rtl_hooks.gen_lowpart_no_emit (mode, op);
+             if (temp)
+               return temp;
+           }
          /* We can't handle truncation to a partial integer mode here
             because we don't know the real bitsize of the partial
             integer mode.  */
@@ -1048,7 +1062,11 @@ simplify_unary_operation_1 (enum rtx_code code, enum machine_mode mode, rtx op)
       if (GET_MODE_NUNITS (mode) == 1
          && (TRULY_NOOP_TRUNCATION_MODES_P (mode, GET_MODE (op))
              || truncated_to_mode (mode, op)))
-       return rtl_hooks.gen_lowpart_no_emit (mode, op);
+       {
+         temp = rtl_hooks.gen_lowpart_no_emit (mode, op);
+         if (temp)
+           return temp;
+       }
 
       /* A truncate of a comparison can be replaced with a subreg if
          STORE_FLAG_VALUE permits.  This is like the previous test,
@@ -1057,7 +1075,11 @@ simplify_unary_operation_1 (enum rtx_code code, enum machine_mode mode, rtx op)
       if (HWI_COMPUTABLE_MODE_P (mode)
          && COMPARISON_P (op)
          && (STORE_FLAG_VALUE & ~GET_MODE_MASK (mode)) == 0)
-       return rtl_hooks.gen_lowpart_no_emit (mode, op);
+       {
+         temp = rtl_hooks.gen_lowpart_no_emit (mode, op);
+         if (temp)
+           return temp;
+       }
 
       /* A truncate of a memory is just loading the low part of the memory
         if we are not changing the meaning of the address. */
@@ -1065,7 +1087,11 @@ simplify_unary_operation_1 (enum rtx_code code, enum machine_mode mode, rtx op)
          && !VECTOR_MODE_P (mode)
          && !MEM_VOLATILE_P (op)
          && !mode_dependent_address_p (XEXP (op, 0), MEM_ADDR_SPACE (op)))
-       return rtl_hooks.gen_lowpart_no_emit (mode, op);
+       {
+         temp = rtl_hooks.gen_lowpart_no_emit (mode, op);
+         if (temp)
+           return temp;
+       }
 
       break;
 
@@ -1298,7 +1324,11 @@ simplify_unary_operation_1 (enum rtx_code code, enum machine_mode mode, rtx op)
          && SUBREG_PROMOTED_VAR_P (op)
          && ! SUBREG_PROMOTED_UNSIGNED_P (op)
          && GET_MODE_SIZE (mode) <= GET_MODE_SIZE (GET_MODE (XEXP (op, 0))))
-       return rtl_hooks.gen_lowpart_no_emit (mode, op);
+       {
+         temp = rtl_hooks.gen_lowpart_no_emit (mode, op);
+         if (temp)
+           return temp;
+       }
 
       /* (sign_extend:M (sign_extend:N <X>)) is (sign_extend:M <X>).
         (sign_extend:M (zero_extend:N <X>)) is (zero_extend:M <X>).  */
@@ -1330,9 +1360,10 @@ simplify_unary_operation_1 (enum rtx_code code, enum machine_mode mode, rtx op)
            {
              rtx inner =
                rtl_hooks.gen_lowpart_no_emit (tmode, XEXP (XEXP (op, 0), 0));
-             return simplify_gen_unary (GET_CODE (op) == ASHIFTRT
-                                        ? SIGN_EXTEND : ZERO_EXTEND,
-                                        mode, inner, tmode);
+             if (inner)
+               return simplify_gen_unary (GET_CODE (op) == ASHIFTRT
+                                          ? SIGN_EXTEND : ZERO_EXTEND,
+                                          mode, inner, tmode);
            }
        }
 
@@ -1360,7 +1391,11 @@ simplify_unary_operation_1 (enum rtx_code code, enum machine_mode mode, rtx op)
          && SUBREG_PROMOTED_VAR_P (op)
          && SUBREG_PROMOTED_UNSIGNED_P (op) > 0
          && GET_MODE_SIZE (mode) <= GET_MODE_SIZE (GET_MODE (XEXP (op, 0))))
-       return rtl_hooks.gen_lowpart_no_emit (mode, op);
+       {
+         temp = rtl_hooks.gen_lowpart_no_emit (mode, op);
+         if (temp)
+           return temp;
+       }
 
       /* Extending a widening multiplication should be canonicalized to
         a wider widening multiplication.  */
@@ -1425,7 +1460,8 @@ simplify_unary_operation_1 (enum rtx_code code, enum machine_mode mode, rtx op)
            {
              rtx inner =
                rtl_hooks.gen_lowpart_no_emit (tmode, XEXP (XEXP (op, 0), 0));
-             return simplify_gen_unary (ZERO_EXTEND, mode, inner, tmode);
+             if (inner)
+               return simplify_gen_unary (ZERO_EXTEND, mode, inner, tmode);
            }
        }
 
@@ -3095,7 +3131,11 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
        }
       /* x/1 is x.  */
       if (trueop1 == CONST1_RTX (mode))
-       return rtl_hooks.gen_lowpart_no_emit (mode, op0);
+       {
+         tem = rtl_hooks.gen_lowpart_no_emit (mode, op0);
+         if (tem)
+           return tem;
+       }
       /* Convert divide by power of two into shift.  */
       if (CONST_INT_P (trueop1)
          && (val = exact_log2 (UINTVAL (trueop1))) > 0)
@@ -3154,12 +3194,17 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
            }
          /* x/1 is x.  */
          if (trueop1 == CONST1_RTX (mode))
-           return rtl_hooks.gen_lowpart_no_emit (mode, op0);
+           {
+             tem = rtl_hooks.gen_lowpart_no_emit (mode, op0);
+             if (tem)
+               return tem;
+           }
          /* x/-1 is -x.  */
          if (trueop1 == constm1_rtx)
            {
              rtx x = rtl_hooks.gen_lowpart_no_emit (mode, op0);
-             return simplify_gen_unary (NEG, mode, x, mode);
+             if (x)
+               return simplify_gen_unary (NEG, mode, x, mode);
            }
        }
       break;
@@ -3515,6 +3560,31 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
            return vec;
        }
 
+      /* If we select elements in a vec_merge that all come from the same
+        operand, select from that operand directly.  */
+      if (GET_CODE (op0) == VEC_MERGE)
+       {
+         rtx trueop02 = avoid_constant_pool_reference (XEXP (op0, 2));
+         if (CONST_INT_P (trueop02))
+           {
+             unsigned HOST_WIDE_INT sel = UINTVAL (trueop02);
+             bool all_operand0 = true;
+             bool all_operand1 = true;
+             for (int i = 0; i < XVECLEN (trueop1, 0); i++)
+               {
+                 rtx j = XVECEXP (trueop1, 0, i);
+                 if (sel & (1 << UINTVAL (j)))
+                   all_operand1 = false;
+                 else
+                   all_operand0 = false;
+               }
+             if (all_operand0 && !side_effects_p (XEXP (op0, 1)))
+               return simplify_gen_binary (VEC_SELECT, mode, XEXP (op0, 0), op1);
+             if (all_operand1 && !side_effects_p (XEXP (op0, 0)))
+               return simplify_gen_binary (VEC_SELECT, mode, XEXP (op0, 1), op1);
+           }
+       }
+
       return 0;
     case VEC_CONCAT:
       {
@@ -3578,10 +3648,13 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
            return gen_rtx_CONST_VECTOR (mode, v);
          }
 
-       /* Try to merge VEC_SELECTs from the same vector into a single one.  */
+       /* Try to merge two VEC_SELECTs from the same vector into a single one.
+          Restrict the transformation to avoid generating a VEC_SELECT with a
+          mode unrelated to its operand.  */
        if (GET_CODE (trueop0) == VEC_SELECT
            && GET_CODE (trueop1) == VEC_SELECT
-           && rtx_equal_p (XEXP (trueop0, 0), XEXP (trueop1, 0)))
+           && rtx_equal_p (XEXP (trueop0, 0), XEXP (trueop1, 0))
+           && GET_MODE (XEXP (trueop0, 0)) == mode)
          {
            rtx par0 = XEXP (trueop0, 1);
            rtx par1 = XEXP (trueop1, 1);
@@ -5176,7 +5249,7 @@ simplify_ternary_operation (enum rtx_code code, enum machine_mode mode,
 {
   unsigned int width = GET_MODE_PRECISION (mode);
   bool any_change = false;
-  rtx tem;
+  rtx tem, trueop2;
 
   /* VOIDmode means "infinite" precision.  */
   if (width == 0)
@@ -5322,33 +5395,74 @@ simplify_ternary_operation (enum rtx_code code, enum machine_mode mode,
       gcc_assert (GET_MODE (op0) == mode);
       gcc_assert (GET_MODE (op1) == mode);
       gcc_assert (VECTOR_MODE_P (mode));
-      op2 = avoid_constant_pool_reference (op2);
-      if (CONST_INT_P (op2))
+      trueop2 = avoid_constant_pool_reference (op2);
+      if (CONST_INT_P (trueop2))
        {
-          int elt_size = GET_MODE_SIZE (GET_MODE_INNER (mode));
+         int elt_size = GET_MODE_SIZE (GET_MODE_INNER (mode));
          unsigned n_elts = (GET_MODE_SIZE (mode) / elt_size);
-         int mask = (1 << n_elts) - 1;
+         unsigned HOST_WIDE_INT sel = UINTVAL (trueop2);
+         unsigned HOST_WIDE_INT mask;
+         if (n_elts == HOST_BITS_PER_WIDE_INT)
+           mask = -1;
+         else
+           mask = ((unsigned HOST_WIDE_INT) 1 << n_elts) - 1;
 
-         if (!(INTVAL (op2) & mask))
+         if (!(sel & mask) && !side_effects_p (op0))
            return op1;
-         if ((INTVAL (op2) & mask) == mask)
+         if ((sel & mask) == mask && !side_effects_p (op1))
            return op0;
 
-         op0 = avoid_constant_pool_reference (op0);
-         op1 = avoid_constant_pool_reference (op1);
-         if (GET_CODE (op0) == CONST_VECTOR
-             && GET_CODE (op1) == CONST_VECTOR)
+         rtx trueop0 = avoid_constant_pool_reference (op0);
+         rtx trueop1 = avoid_constant_pool_reference (op1);
+         if (GET_CODE (trueop0) == CONST_VECTOR
+             && GET_CODE (trueop1) == CONST_VECTOR)
            {
              rtvec v = rtvec_alloc (n_elts);
              unsigned int i;
 
              for (i = 0; i < n_elts; i++)
-               RTVEC_ELT (v, i) = (INTVAL (op2) & (1 << i)
-                                   ? CONST_VECTOR_ELT (op0, i)
-                                   : CONST_VECTOR_ELT (op1, i));
+               RTVEC_ELT (v, i) = ((sel & ((unsigned HOST_WIDE_INT) 1 << i))
+                                   ? CONST_VECTOR_ELT (trueop0, i)
+                                   : CONST_VECTOR_ELT (trueop1, i));
              return gen_rtx_CONST_VECTOR (mode, v);
            }
+
+         /* Replace (vec_merge (vec_merge a b m) c n) with (vec_merge b c n)
+            if no element from a appears in the result.  */
+         if (GET_CODE (op0) == VEC_MERGE)
+           {
+             tem = avoid_constant_pool_reference (XEXP (op0, 2));
+             if (CONST_INT_P (tem))
+               {
+                 unsigned HOST_WIDE_INT sel0 = UINTVAL (tem);
+                 if (!(sel & sel0 & mask) && !side_effects_p (XEXP (op0, 0)))
+                   return simplify_gen_ternary (code, mode, mode,
+                                                XEXP (op0, 1), op1, op2);
+                 if (!(sel & ~sel0 & mask) && !side_effects_p (XEXP (op0, 1)))
+                   return simplify_gen_ternary (code, mode, mode,
+                                                XEXP (op0, 0), op1, op2);
+               }
+           }
+         if (GET_CODE (op1) == VEC_MERGE)
+           {
+             tem = avoid_constant_pool_reference (XEXP (op1, 2));
+             if (CONST_INT_P (tem))
+               {
+                 unsigned HOST_WIDE_INT sel1 = UINTVAL (tem);
+                 if (!(~sel & sel1 & mask) && !side_effects_p (XEXP (op1, 0)))
+                   return simplify_gen_ternary (code, mode, mode,
+                                                op0, XEXP (op1, 1), op2);
+                 if (!(~sel & ~sel1 & mask) && !side_effects_p (XEXP (op1, 1)))
+                   return simplify_gen_ternary (code, mode, mode,
+                                                op0, XEXP (op1, 0), op2);
+               }
+           }
        }
+
+      if (rtx_equal_p (op0, op1)
+         && !side_effects_p (op2) && !side_effects_p (op1))
+       return op0;
+
       break;
 
     default: