re PR debug/66691 (ICE on valid code at -O3 with -g enabled in simplify_subreg, at...
[gcc.git] / gcc / simplify-rtx.c
index 7fb1c6db63d270b767e59bd2002492b58e9e8e6d..ca8310d15563a05be41957df933e302928ba29e6 100644 (file)
@@ -1,5 +1,5 @@
 /* RTL simplification functions for GNU compiler.
-   Copyright (C) 1987-2014 Free Software Foundation, Inc.
+   Copyright (C) 1987-2015 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -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"
@@ -32,10 +35,18 @@ along with GCC; see the file COPYING3.  If not see
 #include "insn-config.h"
 #include "recog.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"
 
 /* Simplification and canonicalization of RTL.  */
 
@@ -46,24 +57,23 @@ along with GCC; see the file COPYING3.  If not see
 #define HWI_SIGN_EXTEND(low) \
  ((((HOST_WIDE_INT) low) < 0) ? ((HOST_WIDE_INT) -1) : ((HOST_WIDE_INT) 0))
 
-static rtx neg_const_int (enum machine_mode, const_rtx);
+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, enum machine_mode, rtx, rtx);
-static rtx simplify_immed_subreg (enum machine_mode, rtx, enum machine_mode,
+static rtx simplify_plus_minus (enum rtx_code, machine_mode, rtx, rtx);
+static rtx simplify_immed_subreg (machine_mode, rtx, machine_mode,
                                  unsigned int);
-static rtx simplify_associative_operation (enum rtx_code, enum machine_mode,
+static rtx simplify_associative_operation (enum rtx_code, machine_mode,
                                           rtx, rtx);
-static rtx simplify_relational_operation_1 (enum rtx_code, enum machine_mode,
-                                           enum machine_mode, rtx, rtx);
-static rtx simplify_unary_operation_1 (enum rtx_code, enum machine_mode, rtx);
-static rtx simplify_binary_operation_1 (enum rtx_code, enum machine_mode,
+static rtx simplify_relational_operation_1 (enum rtx_code, machine_mode,
+                                           machine_mode, rtx, rtx);
+static rtx simplify_unary_operation_1 (enum rtx_code, machine_mode, rtx);
+static rtx simplify_binary_operation_1 (enum rtx_code, machine_mode,
                                        rtx, rtx, rtx, rtx);
 \f
 /* Negate a CONST_INT rtx, truncating (because a conversion from a
    maximally negative number can overflow).  */
 static rtx
-neg_const_int (enum machine_mode mode, const_rtx i)
+neg_const_int (machine_mode mode, const_rtx i)
 {
   return gen_int_mode (-(unsigned HOST_WIDE_INT) INTVAL (i), mode);
 }
@@ -72,7 +82,7 @@ neg_const_int (enum machine_mode mode, const_rtx i)
    the most significant bit of machine mode MODE.  */
 
 bool
-mode_signbit_p (enum machine_mode mode, const_rtx x)
+mode_signbit_p (machine_mode mode, const_rtx x)
 {
   unsigned HOST_WIDE_INT val;
   unsigned int width;
@@ -125,7 +135,7 @@ mode_signbit_p (enum machine_mode mode, const_rtx x)
    precision of MODE is too large to handle.  */
 
 bool
-val_signbit_p (enum machine_mode mode, unsigned HOST_WIDE_INT val)
+val_signbit_p (machine_mode mode, unsigned HOST_WIDE_INT val)
 {
   unsigned int width;
 
@@ -143,7 +153,7 @@ val_signbit_p (enum machine_mode mode, unsigned HOST_WIDE_INT val)
 /* Test whether the most significant bit of mode MODE is set in VAL.
    Returns false if the precision of MODE is too large to handle.  */
 bool
-val_signbit_known_set_p (enum machine_mode mode, unsigned HOST_WIDE_INT val)
+val_signbit_known_set_p (machine_mode mode, unsigned HOST_WIDE_INT val)
 {
   unsigned int width;
 
@@ -161,7 +171,7 @@ val_signbit_known_set_p (enum machine_mode mode, unsigned HOST_WIDE_INT val)
 /* Test whether the most significant bit of mode MODE is clear in VAL.
    Returns false if the precision of MODE is too large to handle.  */
 bool
-val_signbit_known_clear_p (enum machine_mode mode, unsigned HOST_WIDE_INT val)
+val_signbit_known_clear_p (machine_mode mode, unsigned HOST_WIDE_INT val)
 {
   unsigned int width;
 
@@ -180,7 +190,7 @@ val_signbit_known_clear_p (enum machine_mode mode, unsigned HOST_WIDE_INT val)
    seeing if the expression folds.  */
 
 rtx
-simplify_gen_binary (enum rtx_code code, enum machine_mode mode, rtx op0,
+simplify_gen_binary (enum rtx_code code, machine_mode mode, rtx op0,
                     rtx op1)
 {
   rtx tem;
@@ -193,7 +203,7 @@ simplify_gen_binary (enum rtx_code code, enum 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);
 }
@@ -204,7 +214,7 @@ rtx
 avoid_constant_pool_reference (rtx x)
 {
   rtx c, tmp, addr;
-  enum machine_mode cmode;
+  machine_mode cmode;
   HOST_WIDE_INT offset = 0;
 
   switch (GET_CODE (x))
@@ -288,7 +298,7 @@ delegitimize_mem_from_attrs (rtx x)
       && MEM_OFFSET_KNOWN_P (x))
     {
       tree decl = MEM_EXPR (x);
-      enum machine_mode mode = GET_MODE (x);
+      machine_mode mode = GET_MODE (x);
       HOST_WIDE_INT offset = 0;
 
       switch (TREE_CODE (decl))
@@ -378,8 +388,8 @@ delegitimize_mem_from_attrs (rtx x)
    the specified operation.  */
 
 rtx
-simplify_gen_unary (enum rtx_code code, enum machine_mode mode, rtx op,
-                   enum machine_mode op_mode)
+simplify_gen_unary (enum rtx_code code, machine_mode mode, rtx op,
+                   machine_mode op_mode)
 {
   rtx tem;
 
@@ -393,8 +403,8 @@ simplify_gen_unary (enum rtx_code code, enum machine_mode mode, rtx op,
 /* Likewise for ternary operations.  */
 
 rtx
-simplify_gen_ternary (enum rtx_code code, enum machine_mode mode,
-                     enum machine_mode op0_mode, rtx op0, rtx op1, rtx op2)
+simplify_gen_ternary (enum rtx_code code, machine_mode mode,
+                     machine_mode op0_mode, rtx op0, rtx op1, rtx op2)
 {
   rtx tem;
 
@@ -410,8 +420,8 @@ simplify_gen_ternary (enum rtx_code code, enum machine_mode mode,
    CMP_MODE specifies mode comparison is done in.  */
 
 rtx
-simplify_gen_relational (enum rtx_code code, enum machine_mode mode,
-                        enum machine_mode cmp_mode, rtx op0, rtx op1)
+simplify_gen_relational (enum rtx_code code, machine_mode mode,
+                        machine_mode cmp_mode, rtx op0, rtx op1)
 {
   rtx tem;
 
@@ -432,8 +442,8 @@ simplify_replace_fn_rtx (rtx x, const_rtx old_rtx,
                         rtx (*fn) (rtx, const_rtx, void *), void *data)
 {
   enum rtx_code code = GET_CODE (x);
-  enum machine_mode mode = GET_MODE (x);
-  enum machine_mode op_mode;
+  machine_mode mode = GET_MODE (x);
+  machine_mode op_mode;
   const char *fmt;
   rtx op0, op1, op2, newx, op;
   rtvec vec, newvec;
@@ -516,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;
@@ -629,8 +645,8 @@ simplify_replace_rtx (rtx x, const_rtx old_rtx, rtx new_rtx)
    assume that truncating it too is a no-op.  */
 
 static rtx
-simplify_truncation (enum machine_mode mode, rtx op,
-                    enum machine_mode op_mode)
+simplify_truncation (machine_mode mode, rtx op,
+                    machine_mode op_mode)
 {
   unsigned int precision = GET_MODE_UNIT_PRECISION (mode);
   unsigned int op_precision = GET_MODE_UNIT_PRECISION (op_mode);
@@ -646,7 +662,7 @@ simplify_truncation (enum machine_mode mode, rtx op,
         truncation without the extension.  Finally, if the outermode
         is larger than the origmode, we can just extend to the appropriate
         mode.  */
-      enum machine_mode origmode = GET_MODE (XEXP (op, 0));
+      machine_mode origmode = GET_MODE (XEXP (op, 0));
       if (mode == origmode)
        return XEXP (op, 0);
       else if (precision <= GET_MODE_UNIT_PRECISION (origmode))
@@ -804,8 +820,8 @@ simplify_truncation (enum machine_mode mode, rtx op,
    MODE with input operand OP whose mode was originally OP_MODE.
    Return zero if no simplification can be made.  */
 rtx
-simplify_unary_operation (enum rtx_code code, enum machine_mode mode,
-                         rtx op, enum machine_mode op_mode)
+simplify_unary_operation (enum rtx_code code, machine_mode mode,
+                         rtx op, machine_mode op_mode)
 {
   rtx trueop, tem;
 
@@ -821,7 +837,7 @@ simplify_unary_operation (enum rtx_code code, enum machine_mode mode,
 /* Perform some simplifications we can do even if the operands
    aren't constant.  */
 static rtx
-simplify_unary_operation_1 (enum rtx_code code, enum machine_mode mode, rtx op)
+simplify_unary_operation_1 (enum rtx_code code, machine_mode mode, rtx op)
 {
   enum rtx_code reversed;
   rtx temp;
@@ -884,7 +900,7 @@ simplify_unary_operation_1 (enum rtx_code code, enum machine_mode mode, rtx op)
         so we can perform the above simplification.  */
       if (STORE_FLAG_VALUE == -1
          && GET_CODE (op) == ASHIFTRT
-         && GET_CODE (XEXP (op, 1))
+         && CONST_INT_P (XEXP (op, 1))
          && INTVAL (XEXP (op, 1)) == GET_MODE_PRECISION (mode) - 1)
        return simplify_gen_relational (GE, mode, VOIDmode,
                                        XEXP (op, 0), const0_rtx);
@@ -897,7 +913,7 @@ simplify_unary_operation_1 (enum rtx_code code, enum machine_mode mode, rtx op)
          && GET_CODE (SUBREG_REG (op)) == ASHIFT
          && XEXP (SUBREG_REG (op), 0) == const1_rtx)
        {
-         enum machine_mode inner_mode = GET_MODE (SUBREG_REG (op));
+         machine_mode inner_mode = GET_MODE (SUBREG_REG (op));
          rtx x;
 
          x = gen_rtx_ROTATE (inner_mode,
@@ -916,7 +932,7 @@ simplify_unary_operation_1 (enum rtx_code code, enum machine_mode mode, rtx op)
       if (GET_CODE (op) == IOR || GET_CODE (op) == AND)
        {
          rtx in1 = XEXP (op, 0), in2 = XEXP (op, 1);
-         enum machine_mode op_mode;
+         machine_mode op_mode;
 
          op_mode = GET_MODE (in1);
          in1 = simplify_gen_unary (NOT, op_mode, in1, op_mode);
@@ -927,10 +943,7 @@ simplify_unary_operation_1 (enum rtx_code code, enum 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);
@@ -1034,7 +1047,7 @@ simplify_unary_operation_1 (enum rtx_code code, enum machine_mode mode, rtx op)
          && XEXP (op, 1) == const0_rtx
          && SCALAR_INT_MODE_P (GET_MODE (XEXP (op, 0))))
        {
-         enum machine_mode inner = GET_MODE (XEXP (op, 0));
+         machine_mode inner = GET_MODE (XEXP (op, 0));
          int isize = GET_MODE_PRECISION (inner);
          if (STORE_FLAG_VALUE == 1)
            {
@@ -1142,7 +1155,7 @@ simplify_unary_operation_1 (enum rtx_code code, enum 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)
@@ -1154,14 +1167,14 @@ simplify_unary_operation_1 (enum rtx_code code, enum 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)));
 
@@ -1192,7 +1205,7 @@ simplify_unary_operation_1 (enum rtx_code code, enum 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)))
@@ -1321,8 +1334,8 @@ simplify_unary_operation_1 (enum rtx_code code, enum machine_mode mode, rtx op)
              && (rcode == SIGN_EXTEND
                  || (rcode == ASHIFTRT && CONST_INT_P (XEXP (rhs, 1)))))
            {
-             enum machine_mode lmode = GET_MODE (lhs);
-             enum machine_mode rmode = GET_MODE (rhs);
+             machine_mode lmode = GET_MODE (lhs);
+             machine_mode rmode = GET_MODE (rhs);
              int bits;
 
              if (lcode == ASHIFTRT)
@@ -1352,7 +1365,7 @@ simplify_unary_operation_1 (enum rtx_code code, enum machine_mode mode, rtx op)
         target mode is the same as the variable's promotion.  */
       if (GET_CODE (op) == SUBREG
          && SUBREG_PROMOTED_VAR_P (op)
-         && ! SUBREG_PROMOTED_UNSIGNED_P (op)
+         && SUBREG_PROMOTED_SIGNED_P (op)
          && GET_MODE_SIZE (mode) <= GET_MODE_SIZE (GET_MODE (XEXP (op, 0))))
        {
          temp = rtl_hooks.gen_lowpart_no_emit (mode, op);
@@ -1364,8 +1377,8 @@ simplify_unary_operation_1 (enum rtx_code code, enum machine_mode mode, rtx op)
         (sign_extend:M (zero_extend:N <X>)) is (zero_extend:M <X>).  */
       if (GET_CODE (op) == SIGN_EXTEND || GET_CODE (op) == ZERO_EXTEND)
        {
-         gcc_assert (GET_MODE_BITSIZE (mode)
-                     > GET_MODE_BITSIZE (GET_MODE (op)));
+         gcc_assert (GET_MODE_PRECISION (mode)
+                     > GET_MODE_PRECISION (GET_MODE (op)));
          return simplify_gen_unary (GET_CODE (op), mode, XEXP (op, 0),
                                     GET_MODE (XEXP (op, 0)));
        }
@@ -1381,7 +1394,7 @@ simplify_unary_operation_1 (enum rtx_code code, enum machine_mode mode, rtx op)
          && XEXP (XEXP (op, 0), 1) == XEXP (op, 1)
          && GET_MODE_BITSIZE (GET_MODE (op)) > INTVAL (XEXP (op, 1)))
        {
-         enum machine_mode tmode
+         machine_mode tmode
            = mode_for_size (GET_MODE_BITSIZE (GET_MODE (op))
                             - INTVAL (XEXP (op, 1)), MODE_INT, 1);
          gcc_assert (GET_MODE_BITSIZE (mode)
@@ -1419,7 +1432,7 @@ simplify_unary_operation_1 (enum rtx_code code, enum machine_mode mode, rtx op)
         target mode is the same as the variable's promotion.  */
       if (GET_CODE (op) == SUBREG
          && SUBREG_PROMOTED_VAR_P (op)
-         && SUBREG_PROMOTED_UNSIGNED_P (op) > 0
+         && SUBREG_PROMOTED_UNSIGNED_P (op)
          && GET_MODE_SIZE (mode) <= GET_MODE_SIZE (GET_MODE (XEXP (op, 0))))
        {
          temp = rtl_hooks.gen_lowpart_no_emit (mode, op);
@@ -1443,8 +1456,8 @@ simplify_unary_operation_1 (enum rtx_code code, enum machine_mode mode, rtx op)
              && (rcode == ZERO_EXTEND
                  || (rcode == LSHIFTRT && CONST_INT_P (XEXP (rhs, 1)))))
            {
-             enum machine_mode lmode = GET_MODE (lhs);
-             enum machine_mode rmode = GET_MODE (rhs);
+             machine_mode lmode = GET_MODE (lhs);
+             machine_mode rmode = GET_MODE (rhs);
              int bits;
 
              if (lcode == LSHIFTRT)
@@ -1476,15 +1489,15 @@ simplify_unary_operation_1 (enum rtx_code code, enum machine_mode mode, rtx op)
 
       /* (zero_extend:M (lshiftrt:N (ashift <X> (const_int I)) (const_int I)))
         is (zero_extend:M (subreg:O <X>)) if there is mode with
-        GET_MODE_BITSIZE (N) - I bits.  */
+        GET_MODE_PRECISION (N) - I bits.  */
       if (GET_CODE (op) == LSHIFTRT
          && GET_CODE (XEXP (op, 0)) == ASHIFT
          && CONST_INT_P (XEXP (op, 1))
          && XEXP (XEXP (op, 0), 1) == XEXP (op, 1)
-         && GET_MODE_BITSIZE (GET_MODE (op)) > INTVAL (XEXP (op, 1)))
+         && GET_MODE_PRECISION (GET_MODE (op)) > INTVAL (XEXP (op, 1)))
        {
-         enum machine_mode tmode
-           = mode_for_size (GET_MODE_BITSIZE (GET_MODE (op))
+         machine_mode tmode
+           = mode_for_size (GET_MODE_PRECISION (GET_MODE (op))
                             - INTVAL (XEXP (op, 1)), MODE_INT, 1);
          if (tmode != BLKmode)
            {
@@ -1545,8 +1558,8 @@ simplify_unary_operation_1 (enum rtx_code code, enum machine_mode mode, rtx op)
    be MODE with input operand OP whose mode was originally OP_MODE.
    Return zero if the value cannot be computed.  */
 rtx
-simplify_const_unary_operation (enum rtx_code code, enum machine_mode mode,
-                               rtx op, enum machine_mode op_mode)
+simplify_const_unary_operation (enum rtx_code code, machine_mode mode,
+                               rtx op, machine_mode op_mode)
 {
   unsigned int width = GET_MODE_PRECISION (mode);
 
@@ -1574,7 +1587,7 @@ simplify_const_unary_operation (enum rtx_code code, enum machine_mode mode,
              RTVEC_ELT (v, i) = op;
          else
            {
-             enum machine_mode inmode = GET_MODE (op);
+             machine_mode inmode = GET_MODE (op);
               int in_elt_size = GET_MODE_SIZE (GET_MODE_INNER (inmode));
               unsigned in_n_elts = (GET_MODE_SIZE (inmode) / in_elt_size);
 
@@ -1591,7 +1604,7 @@ simplify_const_unary_operation (enum rtx_code code, enum machine_mode mode,
     {
       int elt_size = GET_MODE_SIZE (GET_MODE_INNER (mode));
       unsigned n_elts = (GET_MODE_SIZE (mode) / elt_size);
-      enum machine_mode opmode = GET_MODE (op);
+      machine_mode opmode = GET_MODE (op);
       int op_elt_size = GET_MODE_SIZE (GET_MODE_INNER (opmode));
       unsigned op_n_elts = (GET_MODE_SIZE (opmode) / op_elt_size);
       rtvec v = rtvec_alloc (n_elts);
@@ -1654,7 +1667,7 @@ simplify_const_unary_operation (enum rtx_code code, enum machine_mode mode,
   if (CONST_SCALAR_INT_P (op) && width > 0)
     {
       wide_int result;
-      enum machine_mode imode = op_mode == VOIDmode ? mode : op_mode;
+      machine_mode imode = op_mode == VOIDmode ? mode : op_mode;
       rtx_mode_t op0 = std::make_pair (op, imode);
       int int_value;
 
@@ -1848,7 +1861,7 @@ simplify_const_unary_operation (enum rtx_code code, enum machine_mode mode,
    Return zero if no simplification or canonicalization is possible.  */
 
 static rtx
-simplify_byte_swapping_operation (enum rtx_code code, enum machine_mode mode,
+simplify_byte_swapping_operation (enum rtx_code code, machine_mode mode,
                                  rtx op0, rtx op1)
 {
   rtx tem;
@@ -1878,7 +1891,7 @@ simplify_byte_swapping_operation (enum rtx_code code, enum machine_mode mode,
    canonicalization is possible.  */
 
 static rtx
-simplify_associative_operation (enum rtx_code code, enum machine_mode mode,
+simplify_associative_operation (enum rtx_code code, machine_mode mode,
                                rtx op0, rtx op1)
 {
   rtx tem;
@@ -1897,9 +1910,7 @@ simplify_associative_operation (enum rtx_code code, enum 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)
@@ -1932,7 +1943,7 @@ simplify_associative_operation (enum rtx_code code, enum machine_mode mode,
    Don't use this for relational operations such as EQ or LT.
    Use simplify_relational_operation instead.  */
 rtx
-simplify_binary_operation (enum rtx_code code, enum machine_mode mode,
+simplify_binary_operation (enum rtx_code code, machine_mode mode,
                           rtx op0, rtx op1)
 {
   rtx trueop0, trueop1;
@@ -1948,9 +1959,7 @@ simplify_binary_operation (enum rtx_code code, enum 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);
@@ -1967,7 +1976,7 @@ simplify_binary_operation (enum rtx_code code, enum machine_mode mode,
    actual constants.  */
 
 static rtx
-simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
+simplify_binary_operation_1 (enum rtx_code code, machine_mode mode,
                             rtx op0, rtx op1, rtx trueop0, rtx trueop1)
 {
   rtx tem, reversed, opleft, opright;
@@ -2151,15 +2160,14 @@ simplify_binary_operation_1 (enum rtx_code code, enum 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;
@@ -2679,6 +2687,39 @@ simplify_binary_operation_1 (enum rtx_code code, enum 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)
@@ -2695,12 +2736,31 @@ simplify_binary_operation_1 (enum rtx_code code, enum 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,
@@ -2709,7 +2769,7 @@ simplify_binary_operation_1 (enum rtx_code code, enum 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,
@@ -2799,7 +2859,7 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
          && (~GET_MODE_MASK (GET_MODE (XEXP (op0, 0)))
              & UINTVAL (trueop1)) == 0)
        {
-         enum machine_mode imode = GET_MODE (XEXP (op0, 0));
+         machine_mode imode = GET_MODE (XEXP (op0, 0));
          tem = simplify_gen_binary (AND, imode, XEXP (op0, 0),
                                     gen_int_mode (INTVAL (trueop1),
                                                   imode));
@@ -2812,7 +2872,7 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
       if (GET_CODE (op0) == TRUNCATE && CONST_INT_P (trueop1))
        {
          rtx x = XEXP (op0, 0);
-         enum machine_mode xmode = GET_MODE (x);
+         machine_mode xmode = GET_MODE (x);
          tem = simplify_gen_binary (AND, xmode, x,
                                     gen_int_mode (INTVAL (trueop1), xmode));
          return simplify_gen_unary (TRUNCATE, mode, tem, xmode);
@@ -2925,15 +2985,27 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
       /* (and X (ior (not X) Y) -> (and X Y) */
       if (GET_CODE (op1) == IOR
          && GET_CODE (XEXP (op1, 0)) == NOT
-         && op0 == XEXP (XEXP (op1, 0), 0))
+         && rtx_equal_p (op0, XEXP (XEXP (op1, 0), 0)))
        return simplify_gen_binary (AND, mode, op0, XEXP (op1, 1));
 
       /* (and (ior (not X) Y) X) -> (and X Y) */
       if (GET_CODE (op0) == IOR
          && GET_CODE (XEXP (op0, 0)) == NOT
-         && op1 == XEXP (XEXP (op0, 0), 0))
+         && rtx_equal_p (op1, XEXP (XEXP (op0, 0), 0)))
        return simplify_gen_binary (AND, mode, op1, XEXP (op0, 1));
 
+      /* (and X (ior Y (not X)) -> (and X Y) */
+      if (GET_CODE (op1) == IOR
+         && GET_CODE (XEXP (op1, 1)) == NOT
+         && rtx_equal_p (op0, XEXP (XEXP (op1, 1), 0)))
+       return simplify_gen_binary (AND, mode, op0, XEXP (op1, 0));
+
+      /* (and (ior Y (not X)) X) -> (and X Y) */
+      if (GET_CODE (op0) == IOR
+         && GET_CODE (XEXP (op0, 1)) == NOT
+         && rtx_equal_p (op1, XEXP (XEXP (op0, 1), 0)))
+       return simplify_gen_binary (AND, mode, op1, XEXP (op0, 0));
+
       tem = simplify_byte_swapping_operation (code, mode, op0, op1);
       if (tem)
        return tem;
@@ -3076,13 +3148,15 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
         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 defined(HAVE_rotate) && defined(HAVE_rotatert)
       if (CONST_INT_P (trueop1)
          && IN_RANGE (INTVAL (trueop1),
-                      GET_MODE_BITSIZE (mode) / 2 + (code == ROTATE),
-                      GET_MODE_BITSIZE (mode) - 1))
+                      GET_MODE_PRECISION (mode) / 2 + (code == ROTATE),
+                      GET_MODE_PRECISION (mode) - 1))
        return simplify_gen_binary (code == ROTATE ? ROTATERT : ROTATE,
-                                   mode, op0, GEN_INT (GET_MODE_BITSIZE (mode)
+                                   mode, op0, GEN_INT (GET_MODE_PRECISION (mode)
                                                        - INTVAL (trueop1)));
+#endif
       /* FALLTHRU */
     case ASHIFTRT:
       if (trueop1 == CONST0_RTX (mode))
@@ -3094,10 +3168,47 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
          && UINTVAL (trueop0) == GET_MODE_MASK (mode)
          && ! side_effects_p (op1))
        return op0;
+      /* Given:
+        scalar modes M1, M2
+        scalar constants c1, c2
+        size (M2) > size (M1)
+        c1 == size (M2) - size (M1)
+        optimize:
+        (ashiftrt:M1 (subreg:M1 (lshiftrt:M2 (reg:M2) (const_int <c1>))
+                                <low_part>)
+                     (const_int <c2>))
+        to:
+        (subreg:M1 (ashiftrt:M2 (reg:M2) (const_int <c1 + c2>))
+                   <low_part>).  */
+      if (code == ASHIFTRT
+         && !VECTOR_MODE_P (mode)
+         && SUBREG_P (op0)
+         && CONST_INT_P (op1)
+         && GET_CODE (SUBREG_REG (op0)) == LSHIFTRT
+         && !VECTOR_MODE_P (GET_MODE (SUBREG_REG (op0)))
+         && CONST_INT_P (XEXP (SUBREG_REG (op0), 1))
+         && (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (op0)))
+             > GET_MODE_BITSIZE (mode))
+         && (INTVAL (XEXP (SUBREG_REG (op0), 1))
+             == (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (op0)))
+                 - GET_MODE_BITSIZE (mode)))
+         && subreg_lowpart_p (op0))
+       {
+         rtx tmp = GEN_INT (INTVAL (XEXP (SUBREG_REG (op0), 1))
+                            + INTVAL (op1));
+         machine_mode inner_mode = GET_MODE (SUBREG_REG (op0));
+         tmp = simplify_gen_binary (ASHIFTRT,
+                                    GET_MODE (SUBREG_REG (op0)),
+                                    XEXP (SUBREG_REG (op0), 0),
+                                    tmp);
+         return simplify_gen_subreg (mode, tmp, inner_mode,
+                                     subreg_lowpart_offset (mode,
+                                                            inner_mode));
+       }
     canonicalize_shift:
       if (SHIFT_COUNT_TRUNCATED && CONST_INT_P (op1))
        {
-         val = INTVAL (op1) & (GET_MODE_BITSIZE (mode) - 1);
+         val = INTVAL (op1) & (GET_MODE_PRECISION (mode) - 1);
          if (val != INTVAL (op1))
            return simplify_gen_binary (code, mode, op0, GEN_INT (val));
        }
@@ -3123,7 +3234,7 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
          && STORE_FLAG_VALUE == 1
          && INTVAL (trueop1) < (HOST_WIDE_INT)width)
        {
-         enum machine_mode imode = GET_MODE (XEXP (op0, 0));
+         machine_mode imode = GET_MODE (XEXP (op0, 0));
          unsigned HOST_WIDE_INT zero_val = 0;
 
          if (CLZ_DEFINED_VALUE_AT_ZERO (imode, zero_val)
@@ -3214,7 +3325,7 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
              rtx op0 = XEXP (trueop0, 0);
              rtx op1 = XEXP (trueop0, 1);
 
-             enum machine_mode opmode = GET_MODE (op0);
+             machine_mode opmode = GET_MODE (op0);
              int elt_size = GET_MODE_SIZE (GET_MODE_INNER (opmode));
              int n_elts = GET_MODE_SIZE (opmode) / elt_size;
 
@@ -3236,7 +3347,7 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
                  rtx op00 = XEXP (op0, 0);
                  rtx op01 = XEXP (op0, 1);
 
-                 enum machine_mode mode00, mode01;
+                 machine_mode mode00, mode01;
                  int n_elts00, n_elts01;
 
                  mode00 = GET_MODE (op00);
@@ -3366,6 +3477,50 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
 
              return simplify_gen_binary (VEC_CONCAT, mode, subop0, subop1);
            }
+
+         /* If we select one half of a vec_concat, return that.  */
+         if (GET_CODE (trueop0) == VEC_CONCAT
+             && CONST_INT_P (XVECEXP (trueop1, 0, 0)))
+           {
+             rtx subop0 = XEXP (trueop0, 0);
+             rtx subop1 = XEXP (trueop0, 1);
+             machine_mode mode0 = GET_MODE (subop0);
+             machine_mode mode1 = GET_MODE (subop1);
+             int li = GET_MODE_SIZE (GET_MODE_INNER (mode0));
+             int l0 = GET_MODE_SIZE (mode0) / li;
+             int l1 = GET_MODE_SIZE (mode1) / li;
+             int i0 = INTVAL (XVECEXP (trueop1, 0, 0));
+             if (i0 == 0 && !side_effects_p (op1) && mode == mode0)
+               {
+                 bool success = true;
+                 for (int i = 1; i < l0; ++i)
+                   {
+                     rtx j = XVECEXP (trueop1, 0, i);
+                     if (!CONST_INT_P (j) || INTVAL (j) != i)
+                       {
+                         success = false;
+                         break;
+                       }
+                   }
+                 if (success)
+                   return subop0;
+               }
+             if (i0 == l0 && !side_effects_p (op0) && mode == mode1)
+               {
+                 bool success = true;
+                 for (int i = 1; i < l1; ++i)
+                   {
+                     rtx j = XVECEXP (trueop1, 0, i);
+                     if (!CONST_INT_P (j) || INTVAL (j) != i0 + i)
+                       {
+                         success = false;
+                         break;
+                       }
+                   }
+                 if (success)
+                   return subop1;
+               }
+           }
        }
 
       if (XVECLEN (trueop1, 0) == 1
@@ -3379,7 +3534,21 @@ simplify_binary_operation_1 (enum rtx_code code, enum 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
@@ -3419,13 +3588,38 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
            }
        }
 
+      /* If we have two nested selects that are inverses of each
+        other, replace them with the source operand.  */
+      if (GET_CODE (trueop0) == VEC_SELECT
+         && GET_MODE (XEXP (trueop0, 0)) == mode)
+       {
+         rtx op0_subop1 = XEXP (trueop0, 1);
+         gcc_assert (GET_CODE (op0_subop1) == PARALLEL);
+         gcc_assert (XVECLEN (trueop1, 0) == GET_MODE_NUNITS (mode));
+
+         /* Apply the outer ordering vector to the inner one.  (The inner
+            ordering vector is expressly permitted to be of a different
+            length than the outer one.)  If the result is { 0, 1, ..., n-1 }
+            then the two VEC_SELECTs cancel.  */
+         for (int i = 0; i < XVECLEN (trueop1, 0); ++i)
+           {
+             rtx x = XVECEXP (trueop1, 0, i);
+             if (!CONST_INT_P (x))
+               return 0;
+             rtx y = XVECEXP (op0_subop1, 0, INTVAL (x));
+             if (!CONST_INT_P (y) || i != INTVAL (y))
+               return 0;
+           }
+         return XEXP (trueop0, 0);
+       }
+
       return 0;
     case VEC_CONCAT:
       {
-       enum machine_mode op0_mode = (GET_MODE (trueop0) != VOIDmode
+       machine_mode op0_mode = (GET_MODE (trueop0) != VOIDmode
                                      ? GET_MODE (trueop0)
                                      : GET_MODE_INNER (mode));
-       enum machine_mode op1_mode = (GET_MODE (trueop1) != VOIDmode
+       machine_mode op1_mode = (GET_MODE (trueop1) != VOIDmode
                                      ? GET_MODE (trueop1)
                                      : GET_MODE_INNER (mode));
 
@@ -3513,7 +3707,7 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
 }
 
 rtx
-simplify_const_binary_operation (enum rtx_code code, enum machine_mode mode,
+simplify_const_binary_operation (enum rtx_code code, machine_mode mode,
                                 rtx op0, rtx op1)
 {
   unsigned int width = GET_MODE_PRECISION (mode);
@@ -3524,9 +3718,9 @@ simplify_const_binary_operation (enum rtx_code code, enum machine_mode mode,
       && GET_CODE (op1) == CONST_VECTOR)
     {
       unsigned n_elts = GET_MODE_NUNITS (mode);
-      enum machine_mode op0mode = GET_MODE (op0);
+      machine_mode op0mode = GET_MODE (op0);
       unsigned op0_n_elts = GET_MODE_NUNITS (op0mode);
-      enum machine_mode op1mode = GET_MODE (op1);
+      machine_mode op1mode = GET_MODE (op1);
       unsigned op1_n_elts = GET_MODE_NUNITS (op1mode);
       rtvec v = rtvec_alloc (n_elts);
       unsigned int i;
@@ -3708,7 +3902,8 @@ simplify_const_binary_operation (enum rtx_code code, enum machine_mode mode,
     }
 
   /* We can fold some multi-word operations.  */
-  if (GET_MODE_CLASS (mode) == MODE_INT
+  if ((GET_MODE_CLASS (mode) == MODE_INT
+       || GET_MODE_CLASS (mode) == MODE_PARTIAL_INT)
       && CONST_SCALAR_INT_P (op0)
       && CONST_SCALAR_INT_P (op1))
     {
@@ -3853,20 +4048,10 @@ simplify_const_binary_operation (enum rtx_code code, enum 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.  */
-
-struct simplify_plus_minus_op_data
-{
-  rtx op;
-  short neg;
-};
+/* 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.  */
 
-static bool
+static int
 simplify_plus_minus_op_data_cmp (rtx x, rtx y)
 {
   int result;
@@ -3874,23 +4059,36 @@ 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, enum machine_mode mode, rtx op0,
+simplify_plus_minus (enum rtx_code code, machine_mode mode, rtx op0,
                     rtx op1)
 {
-  struct simplify_plus_minus_op_data ops[8];
+  struct simplify_plus_minus_op_data
+  {
+    rtx op;
+    short neg;
+  } ops[16];
   rtx result, tem;
-  int n_ops = 2, input_ops = 2;
-  int changed, n_constants = 0, canonicalized = 0;
+  int n_ops = 2;
+  int changed, n_constants, canonicalized = 0;
   int i, j;
 
   memset (ops, 0, sizeof ops);
@@ -3907,6 +4105,7 @@ simplify_plus_minus (enum rtx_code code, enum machine_mode mode, rtx op0,
   do
     {
       changed = 0;
+      n_constants = 0;
 
       for (i = 0; i < n_ops; i++)
        {
@@ -3918,7 +4117,7 @@ simplify_plus_minus (enum rtx_code code, enum machine_mode mode, rtx op0,
            {
            case PLUS:
            case MINUS:
-             if (n_ops == 7)
+             if (n_ops == ARRAY_SIZE (ops))
                return NULL_RTX;
 
              ops[n_ops].op = XEXP (this_op, 1);
@@ -3926,9 +4125,19 @@ simplify_plus_minus (enum rtx_code code, enum machine_mode mode, rtx op0,
              n_ops++;
 
              ops[i].op = XEXP (this_op, 0);
-             input_ops++;
              changed = 1;
-             canonicalized |= this_neg;
+             /* 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:
@@ -3939,7 +4148,7 @@ simplify_plus_minus (enum rtx_code code, enum machine_mode mode, rtx op0,
              break;
 
            case CONST:
-             if (n_ops < 7
+             if (n_ops != ARRAY_SIZE (ops)
                  && GET_CODE (XEXP (this_op, 0)) == PLUS
                  && CONSTANT_P (XEXP (XEXP (this_op, 0), 0))
                  && CONSTANT_P (XEXP (XEXP (this_op, 0), 1)))
@@ -3949,20 +4158,20 @@ simplify_plus_minus (enum rtx_code code, enum machine_mode mode, rtx op0,
                  ops[n_ops].neg = this_neg;
                  n_ops++;
                  changed = 1;
-                 canonicalized = 1;
+                 canonicalized = 1;
                }
              break;
 
            case NOT:
              /* ~a -> (-a - 1) */
-             if (n_ops != 7)
+             if (n_ops != ARRAY_SIZE (ops))
                {
                  ops[n_ops].op = CONSTM1_RTX (mode);
                  ops[n_ops++].neg = this_neg;
                  ops[i].op = XEXP (this_op, 0);
                  ops[i].neg = !this_neg;
                  changed = 1;
-                 canonicalized = 1;
+                 canonicalized = 1;
                }
              break;
 
@@ -3973,7 +4182,7 @@ simplify_plus_minus (enum rtx_code code, enum 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;
 
@@ -4017,23 +4226,29 @@ simplify_plus_minus (enum rtx_code code, enum machine_mode mode, rtx op0,
     }
 
   /* Now simplify each pair of operands until nothing changes.  */
-  do
+  while (1)
     {
-      /* Insertion sort is good enough for an eight-element array.  */
+      /* 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--)
@@ -4050,10 +4265,10 @@ simplify_plus_minus (enum rtx_code code, enum 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)))
@@ -4062,7 +4277,8 @@ simplify_plus_minus (enum rtx_code code, enum 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);
@@ -4070,16 +4286,21 @@ simplify_plus_minus (enum rtx_code code, enum machine_mode mode, rtx op0,
                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
-                  when it calls us to simplify CONST operations.  */
-               if (tem
-                   && ! (GET_CODE (tem) == CONST
-                         && GET_CODE (XEXP (tem, 0)) == ncode
-                         && XEXP (XEXP (tem, 0), 0) == lhs
-                         && XEXP (XEXP (tem, 0), 1) == rhs))
+               if (tem)
                  {
+                   /* Reject "simplifications" that just wrap the two
+                      arguments in a CONST.  Failure to do so can result
+                      in infinite recursion with simplify_binary_operation
+                      when it calls us to simplify CONST operations.
+                      Also, if we find such a simplification, don't try
+                      any more combinations with this rhs:  We must have
+                      something like symbol+offset, ie. one of the
+                      trivial CONST expressions we handle later.  */
+                   if (GET_CODE (tem) == CONST
+                       && GET_CODE (XEXP (tem, 0)) == ncode
+                       && XEXP (XEXP (tem, 0), 0) == lhs
+                       && XEXP (XEXP (tem, 0), 1) == rhs)
+                     break;
                    lneg &= rneg;
                    if (GET_CODE (tem) == NEG)
                      tem = XEXP (tem, 0), lneg = !lneg;
@@ -4095,20 +4316,22 @@ simplify_plus_minus (enum rtx_code code, enum 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
@@ -4179,8 +4402,8 @@ plus_minus_operand_p (const_rtx x)
    the operands or, if both are VOIDmode, the operands are compared in
    "infinite precision".  */
 rtx
-simplify_relational_operation (enum rtx_code code, enum machine_mode mode,
-                              enum machine_mode cmp_mode, rtx op0, rtx op1)
+simplify_relational_operation (enum rtx_code code, machine_mode mode,
+                              machine_mode cmp_mode, rtx op0, rtx op1)
 {
   rtx tem, trueop0, trueop1;
 
@@ -4238,7 +4461,7 @@ simplify_relational_operation (enum rtx_code code, enum 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)
@@ -4262,8 +4485,8 @@ simplify_relational_operation (enum rtx_code code, enum machine_mode mode,
    mode the comparison is done in, so it is the mode of the operands.  */
 
 static rtx
-simplify_relational_operation_1 (enum rtx_code code, enum machine_mode mode,
-                                enum machine_mode cmp_mode, rtx op0, rtx op1)
+simplify_relational_operation_1 (enum rtx_code code, machine_mode mode,
+                                machine_mode cmp_mode, rtx op0, rtx op1)
 {
   enum rtx_code op0code = GET_CODE (op0);
 
@@ -4408,16 +4631,16 @@ simplify_relational_operation_1 (enum rtx_code code, enum machine_mode mode,
       && op0code == XOR
       && rtx_equal_p (XEXP (op0, 0), op1)
       && !side_effects_p (XEXP (op0, 0)))
-    return simplify_gen_relational (code, mode, cmp_mode,
-                                   XEXP (op0, 1), const0_rtx);
+    return simplify_gen_relational (code, mode, cmp_mode, XEXP (op0, 1),
+                                   CONST0_RTX (mode));
 
   /* 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, 1)))
-    return simplify_gen_relational (code, mode, cmp_mode,
-                                   XEXP (op0, 0), const0_rtx);
+    return simplify_gen_relational (code, mode, cmp_mode, XEXP (op0, 0),
+                                   CONST0_RTX (mode));
 
   /* (eq/ne (xor x C1) C2) simplifies to (eq/ne x (C1^C2)).  */
   if ((code == EQ || code == NE)
@@ -4428,6 +4651,36 @@ simplify_relational_operation_1 (enum rtx_code code, enum machine_mode mode,
                                    simplify_gen_binary (XOR, cmp_mode,
                                                         XEXP (op0, 1), op1));
 
+  /* (eq/ne (and x y) x) simplifies to (eq/ne (and (not y) x) 0), which
+     can be implemented with a BICS instruction on some targets, or
+     constant-folded if y is a constant.  */
+  if ((code == EQ || code == NE)
+      && op0code == AND
+      && rtx_equal_p (XEXP (op0, 0), 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));
+
+      return simplify_gen_relational (code, mode, cmp_mode, lhs,
+                                     CONST0_RTX (cmp_mode));
+    }
+
+  /* Likewise for (eq/ne (and x y) y).  */
+  if ((code == EQ || code == NE)
+      && op0code == AND
+      && rtx_equal_p (XEXP (op0, 1), 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));
+
+      return simplify_gen_relational (code, mode, cmp_mode, lhs,
+                                     CONST0_RTX (cmp_mode));
+    }
+
   /* (eq/ne (bswap x) C1) simplifies to (eq/ne x C2) with C2 swapped.  */
   if ((code == EQ || code == NE)
       && GET_CODE (op0) == BSWAP
@@ -4536,7 +4789,7 @@ comparison_result (enum rtx_code code, int known_results)
 
 rtx
 simplify_const_relational_operation (enum rtx_code code,
-                                    enum machine_mode mode,
+                                    machine_mode mode,
                                     rtx op0, rtx op1)
 {
   rtx tem;
@@ -4569,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);
     }
 
@@ -4606,10 +4859,10 @@ simplify_const_relational_operation (enum rtx_code code,
      result except if they have side-effects.  Even with NaNs we know
      the result of unordered comparisons and, if signaling NaNs are
      irrelevant, also the result of LT/GT/LTGT.  */
-  if ((! HONOR_NANS (GET_MODE (trueop0))
+  if ((! HONOR_NANS (trueop0)
        || code == UNEQ || code == UNLE || code == UNGE
        || ((code == LT || code == GT || code == LTGT)
-          && ! HONOR_SNANS (GET_MODE (trueop0))))
+          && ! HONOR_SNANS (trueop0)))
       && rtx_equal_p (trueop0, trueop1)
       && ! side_effects_p (trueop0))
     return comparison_result (code, CMP_EQ);
@@ -4661,7 +4914,7 @@ simplify_const_relational_operation (enum rtx_code code,
       /* It would be nice if we really had a mode here.  However, the
         largest int representable on the target is as good as
         infinite.  */
-      enum machine_mode cmode = (mode == VOIDmode) ? MAX_MODE_INT : mode;
+      machine_mode cmode = (mode == VOIDmode) ? MAX_MODE_INT : mode;
       rtx_mode_t ptrueop0 = std::make_pair (trueop0, cmode);
       rtx_mode_t ptrueop1 = std::make_pair (trueop1, cmode);
 
@@ -4897,8 +5150,8 @@ simplify_const_relational_operation (enum rtx_code code,
    a constant.  Return 0 if no simplifications is possible.  */
 
 rtx
-simplify_ternary_operation (enum rtx_code code, enum machine_mode mode,
-                           enum machine_mode op0_mode, rtx op0, rtx op1,
+simplify_ternary_operation (enum rtx_code code, machine_mode mode,
+                           machine_mode op0_mode, rtx op0, rtx op1,
                            rtx op2)
 {
   unsigned int width = GET_MODE_PRECISION (mode);
@@ -4930,7 +5183,7 @@ simplify_ternary_operation (enum rtx_code code, enum 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);
@@ -5000,7 +5253,7 @@ simplify_ternary_operation (enum rtx_code code, enum machine_mode mode,
 
       if (COMPARISON_P (op0) && ! side_effects_p (op0))
        {
-         enum machine_mode cmp_mode = (GET_MODE (XEXP (op0, 0)) == VOIDmode
+         machine_mode cmp_mode = (GET_MODE (XEXP (op0, 0)) == VOIDmode
                                        ? GET_MODE (XEXP (op0, 1))
                                        : GET_MODE (XEXP (op0, 0)));
          rtx temp;
@@ -5111,6 +5364,22 @@ simplify_ternary_operation (enum rtx_code code, enum machine_mode mode,
                                                 op0, XEXP (op1, 0), op2);
                }
            }
+
+         /* Replace (vec_merge (vec_duplicate (vec_select a parallel (i))) a 1 << i)
+            with a.  */
+         if (GET_CODE (op0) == VEC_DUPLICATE
+             && GET_CODE (XEXP (op0, 0)) == VEC_SELECT
+             && GET_CODE (XEXP (XEXP (op0, 0), 1)) == PARALLEL
+             && mode_nunits[GET_MODE (XEXP (op0, 0))] == 1)
+           {
+             tem = XVECEXP ((XEXP (XEXP (op0, 0), 1)), 0, 0);
+             if (CONST_INT_P (tem) && CONST_INT_P (op2))
+               {
+                 if (XEXP (XEXP (op0, 0), 0) == op1
+                     && UINTVAL (op2) == HOST_WIDE_INT_1U << UINTVAL (tem))
+                   return op1;
+               }
+           }
        }
 
       if (rtx_equal_p (op0, op1)
@@ -5135,8 +5404,8 @@ simplify_ternary_operation (enum rtx_code code, enum machine_mode mode,
    and then repacking them again for OUTERMODE.  */
 
 static rtx
-simplify_immed_subreg (enum machine_mode outermode, rtx op,
-                      enum machine_mode innermode, unsigned int byte)
+simplify_immed_subreg (machine_mode outermode, rtx op,
+                      machine_mode innermode, unsigned int byte)
 {
   enum {
     value_bit = 8,
@@ -5153,7 +5422,7 @@ simplify_immed_subreg (enum machine_mode outermode, rtx op,
   rtx result_s;
   rtvec result_v = NULL;
   enum mode_class outer_class;
-  enum machine_mode outer_submode;
+  machine_mode outer_submode;
   int max_bitsize;
 
   /* Some ports misuse CCmode.  */
@@ -5382,6 +5651,8 @@ simplify_immed_subreg (enum machine_mode outermode, rtx op,
            HOST_WIDE_INT tmp[MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_WIDE_INT];
            wide_int r;
 
+           if (GET_MODE_PRECISION (outer_submode) > MAX_BITSIZE_MODE_ANY_INT)
+             return NULL_RTX;
            for (u = 0; u < units; u++)
              {
                unsigned HOST_WIDE_INT buf = 0;
@@ -5393,10 +5664,13 @@ simplify_immed_subreg (enum machine_mode outermode, rtx op,
                tmp[u] = buf;
                base += HOST_BITS_PER_WIDE_INT;
              }
-           gcc_assert (GET_MODE_PRECISION (outer_submode)
-                       <= MAX_BITSIZE_MODE_ANY_INT);
            r = wide_int::from_array (tmp, units,
                                      GET_MODE_PRECISION (outer_submode));
+#if TARGET_SUPPORTS_WIDE_INT == 0
+           /* Make sure r will fit into CONST_INT or CONST_DOUBLE.  */
+           if (wi::min_precision (r, SIGNED) > HOST_BITS_PER_DOUBLE_INT)
+             return NULL_RTX;
+#endif
            elems[elem] = immed_wide_int_const (r, outer_submode);
          }
          break;
@@ -5463,8 +5737,8 @@ simplify_immed_subreg (enum machine_mode outermode, rtx op,
 /* Simplify SUBREG:OUTERMODE(OP:INNERMODE, BYTE)
    Return 0 if no simplifications are possible.  */
 rtx
-simplify_subreg (enum machine_mode outermode, rtx op,
-                enum machine_mode innermode, unsigned int byte)
+simplify_subreg (machine_mode outermode, rtx op,
+                machine_mode innermode, unsigned int byte)
 {
   /* Little bit of sanity checking.  */
   gcc_assert (innermode != VOIDmode);
@@ -5494,7 +5768,7 @@ simplify_subreg (enum machine_mode outermode, rtx op,
      or not at all if changing back op starting mode.  */
   if (GET_CODE (op) == SUBREG)
     {
-      enum machine_mode innermostmode = GET_MODE (SUBREG_REG (op));
+      machine_mode innermostmode = GET_MODE (SUBREG_REG (op));
       int final_offset = byte + SUBREG_BYTE (op);
       rtx newx;
 
@@ -5562,7 +5836,7 @@ simplify_subreg (enum machine_mode outermode, rtx op,
        {
          newx = gen_rtx_SUBREG (outermode, SUBREG_REG (op), final_offset);
          if (SUBREG_PROMOTED_VAR_P (op)
-             && SUBREG_PROMOTED_UNSIGNED_P (op) >= 0
+             && SUBREG_PROMOTED_SIGN (op) >= 0
              && GET_MODE_CLASS (outermode) == MODE_INT
              && IN_RANGE (GET_MODE_SIZE (outermode),
                           GET_MODE_SIZE (innermode),
@@ -5570,8 +5844,7 @@ simplify_subreg (enum machine_mode outermode, rtx op,
              && subreg_lowpart_p (newx))
            {
              SUBREG_PROMOTED_VAR_P (newx) = 1;
-             SUBREG_PROMOTED_UNSIGNED_SET
-               (newx, SUBREG_PROMOTED_UNSIGNED_P (op));
+             SUBREG_PROMOTED_SET (newx, SUBREG_PROMOTED_GET (op));
            }
          return newx;
        }
@@ -5688,8 +5961,8 @@ simplify_subreg (enum machine_mode outermode, rtx op,
 /* Make a SUBREG operation or equivalent if it folds.  */
 
 rtx
-simplify_gen_subreg (enum machine_mode outermode, rtx op,
-                    enum machine_mode innermode, unsigned int byte)
+simplify_gen_subreg (machine_mode outermode, rtx op,
+                    machine_mode innermode, unsigned int byte)
 {
   rtx newx;
 
@@ -5752,7 +6025,7 @@ rtx
 simplify_rtx (const_rtx x)
 {
   const enum rtx_code code = GET_CODE (x);
-  const enum machine_mode mode = GET_MODE (x);
+  const machine_mode mode = GET_MODE (x);
 
   switch (GET_RTX_CLASS (code))
     {