re PR debug/66691 (ICE on valid code at -O3 with -g enabled in simplify_subreg, at...
[gcc.git] / gcc / simplify-rtx.c
index 56de54d9bcb8da7ac1e3d2df36d43291f5a7d5b9..ca8310d15563a05be41957df933e302928ba29e6 100644 (file)
@@ -23,7 +23,10 @@ along with GCC; see the file COPYING3.  If not see
 #include "coretypes.h"
 #include "tm.h"
 #include "rtl.h"
+#include "alias.h"
+#include "symtab.h"
 #include "tree.h"
+#include "fold-const.h"
 #include "varasm.h"
 #include "tm_p.h"
 #include "regs.h"
@@ -31,17 +34,17 @@ along with GCC; see the file COPYING3.  If not see
 #include "flags.h"
 #include "insn-config.h"
 #include "recog.h"
-#include "hashtab.h"
-#include "hash-set.h"
-#include "vec.h"
-#include "machmode.h"
-#include "input.h"
 #include "function.h"
 #include "insn-codes.h"
 #include "optabs.h"
+#include "expmed.h"
+#include "dojump.h"
+#include "explow.h"
+#include "calls.h"
+#include "emit-rtl.h"
+#include "stmt.h"
 #include "expr.h"
 #include "diagnostic-core.h"
-#include "ggc.h"
 #include "target.h"
 #include "predict.h"
 
@@ -56,7 +59,6 @@ along with GCC; see the file COPYING3.  If not see
 
 static rtx neg_const_int (machine_mode, const_rtx);
 static bool plus_minus_operand_p (const_rtx);
-static bool simplify_plus_minus_op_data_cmp (rtx, rtx);
 static rtx simplify_plus_minus (enum rtx_code, machine_mode, rtx, rtx);
 static rtx simplify_immed_subreg (machine_mode, rtx, machine_mode,
                                  unsigned int);
@@ -201,7 +203,7 @@ simplify_gen_binary (enum rtx_code code, machine_mode mode, rtx op0,
   /* Put complex operands first and constants second if commutative.  */
   if (GET_RTX_CLASS (code) == RTX_COMM_ARITH
       && swap_commutative_operands_p (op0, op1))
-    tem = op0, op0 = op1, op1 = tem;
+    std::swap (op0, op1);
 
   return gen_rtx_fmt_ee (code, mode, op0, op1);
 }
@@ -524,9 +526,15 @@ simplify_replace_fn_rtx (rtx x, const_rtx old_rtx,
          op0 = simplify_replace_fn_rtx (XEXP (x, 0), old_rtx, fn, data);
          op1 = simplify_replace_fn_rtx (XEXP (x, 1), old_rtx, fn, data);
 
-         /* (lo_sum (high x) x) -> x  */
-         if (GET_CODE (op0) == HIGH && rtx_equal_p (XEXP (op0, 0), op1))
-           return op1;
+         /* (lo_sum (high x) y) -> y where x and y have the same base.  */
+         if (GET_CODE (op0) == HIGH)
+           {
+             rtx base0, base1, offset0, offset1;
+             split_const (XEXP (op0, 0), &base0, &offset0);
+             split_const (op1, &base1, &offset1);
+             if (rtx_equal_p (base0, base1))
+               return op1;
+           }
 
          if (op0 == XEXP (x, 0) && op1 == XEXP (x, 1))
            return x;
@@ -935,10 +943,7 @@ simplify_unary_operation_1 (enum rtx_code code, machine_mode mode, rtx op)
          in2 = simplify_gen_unary (NOT, op_mode, in2, op_mode);
 
          if (GET_CODE (in2) == NOT && GET_CODE (in1) != NOT)
-           {
-             rtx tem = in2;
-             in2 = in1; in1 = tem;
-           }
+           std::swap (in1, in2);
 
          return gen_rtx_fmt_ee (GET_CODE (op) == IOR ? AND : IOR,
                                 mode, in1, in2);
@@ -1150,7 +1155,7 @@ simplify_unary_operation_1 (enum rtx_code code, machine_mode mode, rtx op)
          = (float_truncate:SF foo:DF).
 
          (float_truncate:DF (float_extend:XF foo:SF))
-         = (float_extend:SF foo:DF).  */
+         = (float_extend:DF foo:SF).  */
       if ((GET_CODE (op) == FLOAT_TRUNCATE
           && flag_unsafe_math_optimizations)
          || GET_CODE (op) == FLOAT_EXTEND)
@@ -1162,14 +1167,14 @@ simplify_unary_operation_1 (enum rtx_code code, machine_mode mode, rtx op)
                                   XEXP (op, 0), mode);
 
       /*  (float_truncate (float x)) is (float x)  */
-      if (GET_CODE (op) == FLOAT
+      if ((GET_CODE (op) == FLOAT || GET_CODE (op) == UNSIGNED_FLOAT)
          && (flag_unsafe_math_optimizations
              || (SCALAR_FLOAT_MODE_P (GET_MODE (op))
                  && ((unsigned)significand_size (GET_MODE (op))
                      >= (GET_MODE_PRECISION (GET_MODE (XEXP (op, 0)))
                          - num_sign_bit_copies (XEXP (op, 0),
                                                 GET_MODE (XEXP (op, 0))))))))
-       return simplify_gen_unary (FLOAT, mode,
+       return simplify_gen_unary (GET_CODE (op), mode,
                                   XEXP (op, 0),
                                   GET_MODE (XEXP (op, 0)));
 
@@ -1200,7 +1205,7 @@ simplify_unary_operation_1 (enum rtx_code code, machine_mode mode, rtx op)
          rounding can't happen.
           */
       if (GET_CODE (op) == FLOAT_EXTEND
-         || (GET_CODE (op) == FLOAT
+         || ((GET_CODE (op) == FLOAT || GET_CODE (op) == UNSIGNED_FLOAT)
              && SCALAR_FLOAT_MODE_P (GET_MODE (op))
              && ((unsigned)significand_size (GET_MODE (op))
                  >= (GET_MODE_PRECISION (GET_MODE (XEXP (op, 0)))
@@ -1905,9 +1910,7 @@ simplify_associative_operation (enum rtx_code code, machine_mode mode,
       if (! swap_commutative_operands_p (op1, op0))
        return simplify_gen_binary (code, mode, op1, op0);
 
-      tem = op0;
-      op0 = op1;
-      op1 = tem;
+      std::swap (op0, op1);
     }
 
   if (GET_CODE (op0) == code)
@@ -1956,9 +1959,7 @@ simplify_binary_operation (enum rtx_code code, machine_mode mode,
   /* Make sure the constant is second.  */
   if (GET_RTX_CLASS (code) == RTX_COMM_ARITH
       && swap_commutative_operands_p (op0, op1))
-    {
-      tem = op0, op0 = op1, op1 = tem;
-    }
+    std::swap (op0, op1);
 
   trueop0 = avoid_constant_pool_reference (op0);
   trueop1 = avoid_constant_pool_reference (op1);
@@ -2159,15 +2160,14 @@ simplify_binary_operation_1 (enum rtx_code code, machine_mode mode,
          rtx xop00 = XEXP (op0, 0);
          rtx xop10 = XEXP (op1, 0);
 
-#ifdef HAVE_cc0
          if (GET_CODE (xop00) == CC0 && GET_CODE (xop10) == CC0)
-#else
+             return xop00;
+
            if (REG_P (xop00) && REG_P (xop10)
                && GET_MODE (xop00) == GET_MODE (xop10)
                && REGNO (xop00) == REGNO (xop10)
                && GET_MODE_CLASS (GET_MODE (xop00)) == MODE_CC
                && GET_MODE_CLASS (GET_MODE (xop10)) == MODE_CC)
-#endif
              return xop00;
        }
       break;
@@ -2687,6 +2687,39 @@ simplify_binary_operation_1 (enum rtx_code code, machine_mode mode,
                                                        XEXP (op0, 1), mode),
                                    op1);
 
+      /* Given (xor (ior (xor A B) C) D), where B, C and D are
+        constants, simplify to (xor (ior A C) (B&~C)^D), canceling
+        out bits inverted twice and not set by C.  Similarly, given
+        (xor (and (xor A B) C) D), simplify without inverting C in
+        the xor operand: (xor (and A C) (B&C)^D).
+      */
+      else if ((GET_CODE (op0) == IOR || GET_CODE (op0) == AND)
+              && GET_CODE (XEXP (op0, 0)) == XOR
+              && CONST_INT_P (op1)
+              && CONST_INT_P (XEXP (op0, 1))
+              && CONST_INT_P (XEXP (XEXP (op0, 0), 1)))
+       {
+         enum rtx_code op = GET_CODE (op0);
+         rtx a = XEXP (XEXP (op0, 0), 0);
+         rtx b = XEXP (XEXP (op0, 0), 1);
+         rtx c = XEXP (op0, 1);
+         rtx d = op1;
+         HOST_WIDE_INT bval = INTVAL (b);
+         HOST_WIDE_INT cval = INTVAL (c);
+         HOST_WIDE_INT dval = INTVAL (d);
+         HOST_WIDE_INT xcval;
+
+         if (op == IOR)
+           xcval = ~cval;
+         else
+           xcval = cval;
+
+         return simplify_gen_binary (XOR, mode,
+                                     simplify_gen_binary (op, mode, a, c),
+                                     gen_int_mode ((bval & xcval) ^ dval,
+                                                   mode));
+       }
+
       /* Given (xor (and A B) C), using P^Q == (~P&Q) | (~Q&P),
         we can transform like this:
             (A&B)^C == ~(A&B)&C | ~C&(A&B)
@@ -2703,12 +2736,31 @@ simplify_binary_operation_1 (enum rtx_code code, machine_mode mode,
          HOST_WIDE_INT bval = INTVAL (b);
          HOST_WIDE_INT cval = INTVAL (c);
 
-         rtx na_c
-           = simplify_binary_operation (AND, mode,
-                                        simplify_gen_unary (NOT, mode, a, mode),
-                                        c);
+         /* Instead of computing ~A&C, we compute its negated value,
+            ~(A|~C).  If it yields -1, ~A&C is zero, so we can
+            optimize for sure.  If it does not simplify, we still try
+            to compute ~A&C below, but since that always allocates
+            RTL, we don't try that before committing to returning a
+            simplified expression.  */
+         rtx n_na_c = simplify_binary_operation (IOR, mode, a,
+                                                 GEN_INT (~cval));
+
          if ((~cval & bval) == 0)
            {
+             rtx na_c = NULL_RTX;
+             if (n_na_c)
+               na_c = simplify_gen_unary (NOT, mode, n_na_c, mode);
+             else
+               {
+                 /* If ~A does not simplify, don't bother: we don't
+                    want to simplify 2 operations into 3, and if na_c
+                    were to simplify with na, n_na_c would have
+                    simplified as well.  */
+                 rtx na = simplify_unary_operation (NOT, mode, a, mode);
+                 if (na)
+                   na_c = simplify_gen_binary (AND, mode, na, c);
+               }
+
              /* Try to simplify ~A&C | ~B&C.  */
              if (na_c != NULL_RTX)
                return simplify_gen_binary (IOR, mode, na_c,
@@ -2717,7 +2769,7 @@ simplify_binary_operation_1 (enum rtx_code code, machine_mode mode,
          else
            {
              /* If ~A&C is zero, simplify A&(~C&B) | ~B&C.  */
-             if (na_c == const0_rtx)
+             if (n_na_c == CONSTM1_RTX (mode))
                {
                  rtx a_nc_b = simplify_gen_binary (AND, mode, a,
                                                    gen_int_mode (~cval & bval,
@@ -3482,7 +3534,21 @@ simplify_binary_operation_1 (enum rtx_code code, machine_mode mode,
          while (GET_MODE (vec) != mode
                 && GET_CODE (vec) == VEC_CONCAT)
            {
-             HOST_WIDE_INT vec_size = GET_MODE_SIZE (GET_MODE (XEXP (vec, 0)));
+             HOST_WIDE_INT vec_size;
+
+             if (CONST_INT_P (XEXP (vec, 0)))
+               {
+                 /* vec_concat of two const_ints doesn't make sense with
+                    respect to modes.  */
+                 if (CONST_INT_P (XEXP (vec, 1)))
+                   return 0;
+
+                 vec_size = GET_MODE_SIZE (GET_MODE (trueop0))
+                            - GET_MODE_SIZE (GET_MODE (XEXP (vec, 1)));
+               }
+             else
+               vec_size = GET_MODE_SIZE (GET_MODE (XEXP (vec, 0)));
+
              if (offset < vec_size)
                vec = XEXP (vec, 0);
              else
@@ -3982,20 +4048,10 @@ simplify_const_binary_operation (enum rtx_code code, machine_mode mode,
 
 
 \f
-/* Simplify a PLUS or MINUS, at least one of whose operands may be another
-   PLUS or MINUS.
-
-   Rather than test for specific case, we do this by a brute-force method
-   and do all possible simplifications until no more changes occur.  Then
-   we rebuild the operation.  */
+/* Return a positive integer if X should sort after Y.  The value
+   returned is 1 if and only if X and Y are both regs.  */
 
-struct simplify_plus_minus_op_data
-{
-  rtx op;
-  short neg;
-};
-
-static bool
+static int
 simplify_plus_minus_op_data_cmp (rtx x, rtx y)
 {
   int result;
@@ -4003,20 +4059,33 @@ simplify_plus_minus_op_data_cmp (rtx x, rtx y)
   result = (commutative_operand_precedence (y)
            - commutative_operand_precedence (x));
   if (result)
-    return result > 0;
+    return result + result;
 
   /* Group together equal REGs to do more simplification.  */
   if (REG_P (x) && REG_P (y))
     return REGNO (x) > REGNO (y);
-  else
-    return false;
+
+  return 0;
 }
 
+/* Simplify and canonicalize a PLUS or MINUS, at least one of whose
+   operands may be another PLUS or MINUS.
+
+   Rather than test for specific case, we do this by a brute-force method
+   and do all possible simplifications until no more changes occur.  Then
+   we rebuild the operation.
+
+   May return NULL_RTX when no changes were made.  */
+
 static rtx
 simplify_plus_minus (enum rtx_code code, machine_mode mode, rtx op0,
                     rtx op1)
 {
-  struct simplify_plus_minus_op_data ops[16];
+  struct simplify_plus_minus_op_data
+  {
+    rtx op;
+    short neg;
+  } ops[16];
   rtx result, tem;
   int n_ops = 2;
   int changed, n_constants, canonicalized = 0;
@@ -4057,7 +4126,18 @@ simplify_plus_minus (enum rtx_code code, machine_mode mode, rtx op0,
 
              ops[i].op = XEXP (this_op, 0);
              changed = 1;
-             canonicalized |= this_neg || i != n_ops - 2;
+             /* If this operand was negated then we will potentially
+                canonicalize the expression.  Similarly if we don't
+                place the operands adjacent we're re-ordering the
+                expression and thus might be performing a
+                canonicalization.  Ignore register re-ordering.
+                ??? It might be better to shuffle the ops array here,
+                but then (plus (plus (A, B), plus (C, D))) wouldn't
+                be seen as non-canonical.  */
+             if (this_neg
+                 || (i != n_ops - 2
+                     && !(REG_P (ops[i].op) && REG_P (ops[n_ops - 1].op))))
+               canonicalized = 1;
              break;
 
            case NEG:
@@ -4078,7 +4158,7 @@ simplify_plus_minus (enum rtx_code code, machine_mode mode, rtx op0,
                  ops[n_ops].neg = this_neg;
                  n_ops++;
                  changed = 1;
-                 canonicalized = 1;
+                 canonicalized = 1;
                }
              break;
 
@@ -4091,7 +4171,7 @@ simplify_plus_minus (enum rtx_code code, machine_mode mode, rtx op0,
                  ops[i].op = XEXP (this_op, 0);
                  ops[i].neg = !this_neg;
                  changed = 1;
-                 canonicalized = 1;
+                 canonicalized = 1;
                }
              break;
 
@@ -4102,7 +4182,7 @@ simplify_plus_minus (enum rtx_code code, machine_mode mode, rtx op0,
                  ops[i].op = neg_const_int (mode, this_op);
                  ops[i].neg = 0;
                  changed = 1;
-                 canonicalized = 1;
+                 canonicalized = 1;
                }
              break;
 
@@ -4146,23 +4226,29 @@ simplify_plus_minus (enum rtx_code code, machine_mode mode, rtx op0,
     }
 
   /* Now simplify each pair of operands until nothing changes.  */
-  do
+  while (1)
     {
       /* Insertion sort is good enough for a small array.  */
       for (i = 1; i < n_ops; i++)
-        {
-          struct simplify_plus_minus_op_data save;
-          j = i - 1;
-          if (!simplify_plus_minus_op_data_cmp (ops[j].op, ops[i].op))
+       {
+         struct simplify_plus_minus_op_data save;
+         int cmp;
+
+         j = i - 1;
+         cmp = simplify_plus_minus_op_data_cmp (ops[j].op, ops[i].op);
+         if (cmp <= 0)
            continue;
+         /* Just swapping registers doesn't count as canonicalization.  */
+         if (cmp != 1)
+           canonicalized = 1;
 
-          canonicalized = 1;
-          save = ops[i];
-          do
+         save = ops[i];
+         do
            ops[j + 1] = ops[j];
-          while (j-- && simplify_plus_minus_op_data_cmp (ops[j].op, save.op));
-          ops[j + 1] = save;
-        }
+         while (j--
+                && simplify_plus_minus_op_data_cmp (ops[j].op, save.op) > 0);
+         ops[j + 1] = save;
+       }
 
       changed = 0;
       for (i = n_ops - 1; i > 0; i--)
@@ -4179,10 +4265,10 @@ simplify_plus_minus (enum rtx_code code, machine_mode mode, rtx op0,
                  {
                    ncode = MINUS;
                    if (lneg)
-                     tem = lhs, lhs = rhs, rhs = tem;
+                     std::swap (lhs, rhs);
                  }
                else if (swap_commutative_operands_p (lhs, rhs))
-                 tem = lhs, lhs = rhs, rhs = tem;
+                 std::swap (lhs, rhs);
 
                if ((GET_CODE (lhs) == CONST || CONST_INT_P (lhs))
                    && (GET_CODE (rhs) == CONST || CONST_INT_P (rhs)))
@@ -4191,7 +4277,8 @@ simplify_plus_minus (enum rtx_code code, machine_mode mode, rtx op0,
 
                    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);
+                   tem = simplify_binary_operation (ncode, mode, tem_lhs,
+                                                    tem_rhs);
 
                    if (tem && !CONSTANT_P (tem))
                      tem = gen_rtx_CONST (GET_MODE (tem), tem);
@@ -4229,20 +4316,22 @@ simplify_plus_minus (enum rtx_code code, machine_mode mode, rtx op0,
              }
          }
 
-      /* If nothing changed, fail.  */
-      if (!canonicalized)
-        return NULL_RTX;
+      if (!changed)
+       break;
 
       /* Pack all the operands to the lower-numbered entries.  */
       for (i = 0, j = 0; j < n_ops; j++)
-        if (ops[j].op)
-          {
+       if (ops[j].op)
+         {
            ops[i] = ops[j];
            i++;
-          }
+         }
       n_ops = i;
     }
-  while (changed);
+
+  /* If nothing changed, fail.  */
+  if (!canonicalized)
+    return NULL_RTX;
 
   /* Create (minus -C X) instead of (neg (const (plus X C))).  */
   if (n_ops == 2
@@ -4372,7 +4461,7 @@ simplify_relational_operation (enum rtx_code code, machine_mode mode,
   /* For the following tests, ensure const0_rtx is op1.  */
   if (swap_commutative_operands_p (op0, op1)
       || (op0 == const0_rtx && op1 != const0_rtx))
-    tem = op0, op0 = op1, op1 = tem, code = swap_condition (code);
+    std::swap (op0, op1), code = swap_condition (code);
 
   /* If op0 is a compare, extract the comparison arguments from it.  */
   if (GET_CODE (op0) == COMPARE && op1 == const0_rtx)
@@ -4568,7 +4657,8 @@ simplify_relational_operation_1 (enum rtx_code code, machine_mode mode,
   if ((code == EQ || code == NE)
       && op0code == AND
       && rtx_equal_p (XEXP (op0, 0), op1)
-      && !side_effects_p (op1))
+      && !side_effects_p (op1)
+      && op1 != CONST0_RTX (cmp_mode))
     {
       rtx not_y = simplify_gen_unary (NOT, cmp_mode, XEXP (op0, 1), cmp_mode);
       rtx lhs = simplify_gen_binary (AND, cmp_mode, not_y, XEXP (op0, 0));
@@ -4581,7 +4671,8 @@ simplify_relational_operation_1 (enum rtx_code code, machine_mode mode,
   if ((code == EQ || code == NE)
       && op0code == AND
       && rtx_equal_p (XEXP (op0, 1), op1)
-      && !side_effects_p (op1))
+      && !side_effects_p (op1)
+      && op1 != CONST0_RTX (cmp_mode))
     {
       rtx not_x = simplify_gen_unary (NOT, cmp_mode, XEXP (op0, 0), cmp_mode);
       rtx lhs = simplify_gen_binary (AND, cmp_mode, not_x, XEXP (op0, 1));
@@ -4731,7 +4822,7 @@ simplify_const_relational_operation (enum rtx_code code,
   /* Make sure the constant is second.  */
   if (swap_commutative_operands_p (op0, op1))
     {
-      tem = op0, op0 = op1, op1 = tem;
+      std::swap (op0, op1);
       code = swap_condition (code);
     }
 
@@ -5092,7 +5183,7 @@ simplify_ternary_operation (enum rtx_code code, machine_mode mode,
       /* Canonicalize the two multiplication operands.  */
       /* a * -b + c  =>  -b * a + c.  */
       if (swap_commutative_operands_p (op0, op1))
-       tem = op0, op0 = op1, op1 = tem, any_change = true;
+       std::swap (op0, op1), any_change = true;
 
       if (any_change)
        return gen_rtx_FMA (mode, op0, op1, op2);