]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/expmed.c
Optimize ODR enum streaming
[thirdparty/gcc.git] / gcc / expmed.c
index 9a92c940e57de028202598ac1ec4f41dbc796b8d..e7c03fbf92c04b46d7697aad96ad2fa14be4e8e1 100644 (file)
@@ -1,6 +1,6 @@
 /* Medium-level subroutines: convert bit-field store and extract
    and shifts, multiplies and divides to rtl instructions.
-   Copyright (C) 1987-2017 Free Software Foundation, Inc.
+   Copyright (C) 1987-2020 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -18,6 +18,8 @@ You should have received a copy of the GNU General Public License
 along with GCC; see the file COPYING3.  If not see
 <http://www.gnu.org/licenses/>.  */
 
+/* Work around tree-optimization/91825.  */
+#pragma GCC diagnostic warning "-Wmaybe-uninitialized"
 
 #include "config.h"
 #include "system.h"
@@ -50,14 +52,12 @@ struct target_expmed *this_target_expmed = &default_target_expmed;
 static bool store_integral_bit_field (rtx, opt_scalar_int_mode,
                                      unsigned HOST_WIDE_INT,
                                      unsigned HOST_WIDE_INT,
-                                     unsigned HOST_WIDE_INT,
-                                     unsigned HOST_WIDE_INT,
+                                     poly_uint64, poly_uint64,
                                      machine_mode, rtx, bool, bool);
 static void store_fixed_bit_field (rtx, opt_scalar_int_mode,
                                   unsigned HOST_WIDE_INT,
                                   unsigned HOST_WIDE_INT,
-                                  unsigned HOST_WIDE_INT,
-                                  unsigned HOST_WIDE_INT,
+                                  poly_uint64, poly_uint64,
                                   rtx, scalar_int_mode, bool);
 static void store_fixed_bit_field_1 (rtx, scalar_int_mode,
                                     unsigned HOST_WIDE_INT,
@@ -66,9 +66,12 @@ static void store_fixed_bit_field_1 (rtx, scalar_int_mode,
 static void store_split_bit_field (rtx, opt_scalar_int_mode,
                                   unsigned HOST_WIDE_INT,
                                   unsigned HOST_WIDE_INT,
-                                  unsigned HOST_WIDE_INT,
-                                  unsigned HOST_WIDE_INT,
+                                  poly_uint64, poly_uint64,
                                   rtx, scalar_int_mode, bool);
+static rtx extract_integral_bit_field (rtx, opt_scalar_int_mode,
+                                      unsigned HOST_WIDE_INT,
+                                      unsigned HOST_WIDE_INT, int, rtx,
+                                      machine_mode, machine_mode, bool, bool);
 static rtx extract_fixed_bit_field (machine_mode, rtx, opt_scalar_int_mode,
                                    unsigned HOST_WIDE_INT,
                                    unsigned HOST_WIDE_INT, rtx, int, bool);
@@ -468,8 +471,8 @@ static rtx
 adjust_bit_field_mem_for_reg (enum extraction_pattern pattern,
                              rtx op0, HOST_WIDE_INT bitsize,
                              HOST_WIDE_INT bitnum,
-                             unsigned HOST_WIDE_INT bitregion_start,
-                             unsigned HOST_WIDE_INT bitregion_end,
+                             poly_uint64 bitregion_start,
+                             poly_uint64 bitregion_end,
                              machine_mode fieldmode,
                              unsigned HOST_WIDE_INT *new_bitnum)
 {
@@ -510,17 +513,17 @@ adjust_bit_field_mem_for_reg (enum extraction_pattern pattern,
    offset is then BITNUM / BITS_PER_UNIT.  */
 
 static bool
-lowpart_bit_field_p (unsigned HOST_WIDE_INT bitnum,
-                    unsigned HOST_WIDE_INT bitsize,
+lowpart_bit_field_p (poly_uint64 bitnum, poly_uint64 bitsize,
                     machine_mode struct_mode)
 {
-  unsigned HOST_WIDE_INT regsize = REGMODE_NATURAL_SIZE (struct_mode);
+  poly_uint64 regsize = REGMODE_NATURAL_SIZE (struct_mode);
   if (BYTES_BIG_ENDIAN)
-    return (bitnum % BITS_PER_UNIT == 0
-           && (bitnum + bitsize == GET_MODE_BITSIZE (struct_mode)
-               || (bitnum + bitsize) % (regsize * BITS_PER_UNIT) == 0));
+    return (multiple_p (bitnum, BITS_PER_UNIT)
+           && (known_eq (bitnum + bitsize, GET_MODE_BITSIZE (struct_mode))
+               || multiple_p (bitnum + bitsize,
+                              regsize * BITS_PER_UNIT)));
   else
-    return bitnum % (regsize * BITS_PER_UNIT) == 0;
+    return multiple_p (bitnum, regsize * BITS_PER_UNIT);
 }
 
 /* Return true if -fstrict-volatile-bitfields applies to an access of OP0
@@ -533,8 +536,8 @@ static bool
 strict_volatile_bitfield_p (rtx op0, unsigned HOST_WIDE_INT bitsize,
                            unsigned HOST_WIDE_INT bitnum,
                            scalar_int_mode fieldmode,
-                           unsigned HOST_WIDE_INT bitregion_start,
-                           unsigned HOST_WIDE_INT bitregion_end)
+                           poly_uint64 bitregion_start,
+                           poly_uint64 bitregion_end)
 {
   unsigned HOST_WIDE_INT modesize = GET_MODE_BITSIZE (fieldmode);
 
@@ -561,9 +564,10 @@ strict_volatile_bitfield_p (rtx op0, unsigned HOST_WIDE_INT bitsize,
     return false;
 
   /* Check for cases where the C++ memory model applies.  */
-  if (bitregion_end != 0
-      && (bitnum - bitnum % modesize < bitregion_start
-         || bitnum - bitnum % modesize + modesize - 1 > bitregion_end))
+  if (maybe_ne (bitregion_end, 0U)
+      && (maybe_lt (bitnum - bitnum % modesize, bitregion_start)
+         || maybe_gt (bitnum - bitnum % modesize + modesize - 1,
+                      bitregion_end)))
     return false;
 
   return true;
@@ -597,7 +601,7 @@ store_bit_field_using_insv (const extraction_insn *insv, rtx op0,
                            unsigned HOST_WIDE_INT bitnum,
                            rtx value, scalar_int_mode value_mode)
 {
-  struct expand_operand ops[4];
+  class expand_operand ops[4];
   rtx value1;
   rtx xop0 = op0;
   rtx_insn *last = get_last_insn ();
@@ -727,8 +731,7 @@ store_bit_field_using_insv (const extraction_insn *insv, rtx op0,
 
 static bool
 store_bit_field_1 (rtx str_rtx, poly_uint64 bitsize, poly_uint64 bitnum,
-                  unsigned HOST_WIDE_INT bitregion_start,
-                  unsigned HOST_WIDE_INT bitregion_end,
+                  poly_uint64 bitregion_start, poly_uint64 bitregion_end,
                   machine_mode fieldmode,
                   rtx value, bool reverse, bool fallback_p)
 {
@@ -758,7 +761,7 @@ store_bit_field_1 (rtx str_rtx, poly_uint64 bitsize, poly_uint64 bitnum,
       && known_eq (bitsize, GET_MODE_BITSIZE (innermode))
       && multiple_p (bitnum, GET_MODE_BITSIZE (innermode), &pos))
     {
-      struct expand_operand ops[3];
+      class expand_operand ops[3];
       enum insn_code icode = optab_handler (vec_set_optab, outermode);
 
       create_fixed_operand (&ops[0], op0);
@@ -778,7 +781,7 @@ store_bit_field_1 (rtx str_rtx, poly_uint64 bitsize, poly_uint64 bitnum,
         In the latter case, use subreg on the rhs side, not lhs.  */
       rtx sub;
       HOST_WIDE_INT regnum;
-      HOST_WIDE_INT regsize = REGMODE_NATURAL_SIZE (GET_MODE (op0));
+      poly_uint64 regsize = REGMODE_NATURAL_SIZE (GET_MODE (op0));
       if (known_eq (bitnum, 0U)
          && known_eq (bitsize, GET_MODE_BITSIZE (GET_MODE (op0))))
        {
@@ -837,6 +840,27 @@ store_bit_field_1 (rtx str_rtx, poly_uint64 bitsize, poly_uint64 bitnum,
       if (MEM_P (op0))
        op0 = adjust_bitfield_address_size (op0, op0_mode.else_blk (),
                                            0, MEM_SIZE (op0));
+      else if (!op0_mode.exists ())
+       {
+         if (ibitnum == 0
+             && known_eq (ibitsize, GET_MODE_BITSIZE (GET_MODE (op0)))
+             && MEM_P (value)
+             && !reverse)
+           {
+             value = adjust_address (value, GET_MODE (op0), 0);
+             emit_move_insn (op0, value);
+             return true;
+           }
+         if (!fallback_p)
+           return false;
+         rtx temp = assign_stack_temp (GET_MODE (op0),
+                                       GET_MODE_SIZE (GET_MODE (op0)));
+         emit_move_insn (temp, op0);
+         store_bit_field_1 (temp, bitsize, bitnum, 0, 0, fieldmode, value,
+                            reverse, fallback_p);
+         emit_move_insn (op0, temp);
+         return true;
+       }
       else
        op0 = gen_lowpart (op0_mode.require (), op0);
     }
@@ -855,8 +879,8 @@ static bool
 store_integral_bit_field (rtx op0, opt_scalar_int_mode op0_mode,
                          unsigned HOST_WIDE_INT bitsize,
                          unsigned HOST_WIDE_INT bitnum,
-                         unsigned HOST_WIDE_INT bitregion_start,
-                         unsigned HOST_WIDE_INT bitregion_end,
+                         poly_uint64 bitregion_start,
+                         poly_uint64 bitregion_end,
                          machine_mode fieldmode,
                          rtx value, bool reverse, bool fallback_p)
 {
@@ -866,10 +890,10 @@ store_integral_bit_field (rtx op0, opt_scalar_int_mode op0_mode,
   if (!MEM_P (op0)
       && !reverse
       && lowpart_bit_field_p (bitnum, bitsize, op0_mode.require ())
-      && bitsize == GET_MODE_BITSIZE (fieldmode)
+      && known_eq (bitsize, GET_MODE_BITSIZE (fieldmode))
       && optab_handler (movstrict_optab, fieldmode) != CODE_FOR_nothing)
     {
-      struct expand_operand ops[2];
+      class expand_operand ops[2];
       enum insn_code icode = optab_handler (movstrict_optab, fieldmode);
       rtx arg0 = op0;
       unsigned HOST_WIDE_INT subreg_off;
@@ -909,8 +933,7 @@ store_integral_bit_field (rtx op0, opt_scalar_int_mode op0_mode,
         However, only do that if the value is not BLKmode.  */
 
       const bool backwards = WORDS_BIG_ENDIAN && fieldmode != BLKmode;
-      unsigned int nwords = (bitsize + (BITS_PER_WORD - 1)) / BITS_PER_WORD;
-      unsigned int i;
+      const int nwords = (bitsize + (BITS_PER_WORD - 1)) / BITS_PER_WORD;
       rtx_insn *last;
 
       /* This is the mode we must force value to, so that there will be enough
@@ -926,35 +949,31 @@ store_integral_bit_field (rtx op0, opt_scalar_int_mode op0_mode,
        value_mode = smallest_int_mode_for_size (nwords * BITS_PER_WORD);
 
       last = get_last_insn ();
-      for (i = 0; i < nwords; i++)
+      for (int i = 0; i < nwords; i++)
        {
-         /* If I is 0, use the low-order word in both field and target;
-            if I is 1, use the next to lowest word; and so on.  */
-         unsigned int wordnum = (backwards
-                                 ? GET_MODE_SIZE (value_mode) / UNITS_PER_WORD
-                                 - i - 1
-                                 : i);
-         unsigned int bit_offset = (backwards ^ reverse
-                                    ? MAX ((int) bitsize - ((int) i + 1)
-                                           * BITS_PER_WORD,
-                                           0)
-                                    : (int) i * BITS_PER_WORD);
-         rtx value_word = operand_subword_force (value, wordnum, value_mode);
-         unsigned HOST_WIDE_INT new_bitsize =
-           MIN (BITS_PER_WORD, bitsize - i * BITS_PER_WORD);
-
-         /* If the remaining chunk doesn't have full wordsize we have
-            to make sure that for big-endian machines the higher order
-            bits are used.  */
-         if (new_bitsize < BITS_PER_WORD && BYTES_BIG_ENDIAN && !backwards)
-           {
-             int shift = BITS_PER_WORD - new_bitsize;
-             rtx shift_rtx = gen_int_shift_amount (word_mode, shift);
-             value_word = simplify_expand_binop (word_mode, lshr_optab,
-                                                 value_word, shift_rtx,
-                                                 NULL_RTX, true,
-                                                 OPTAB_LIB_WIDEN);
-           }
+         /* Number of bits to be stored in this iteration, i.e. BITS_PER_WORD
+            except maybe for the last iteration.  */
+         const unsigned HOST_WIDE_INT new_bitsize
+           = MIN (BITS_PER_WORD, bitsize - i * BITS_PER_WORD);
+         /* Bit offset from the starting bit number in the target.  */
+         const unsigned int bit_offset
+           = backwards ^ reverse
+             ? MAX ((int) bitsize - (i + 1) * BITS_PER_WORD, 0)
+             : i * BITS_PER_WORD;
+         /* Starting word number in the value.  */
+         const unsigned int wordnum
+           = backwards
+             ? GET_MODE_SIZE (value_mode) / UNITS_PER_WORD - (i + 1)
+             : i;
+         /* The chunk of the value in word_mode.  We use bit-field extraction
+             in BLKmode to handle unaligned memory references and to shift the
+             last chunk right on big-endian machines if need be.  */
+         rtx value_word
+           = fieldmode == BLKmode
+             ? extract_bit_field (value, new_bitsize, wordnum * BITS_PER_WORD,
+                                  1, NULL_RTX, word_mode, word_mode, false,
+                                  NULL)
+             : operand_subword_force (value, wordnum, value_mode);
 
          if (!store_bit_field_1 (op0, new_bitsize,
                                  bitnum + bit_offset,
@@ -1082,8 +1101,7 @@ store_integral_bit_field (rtx op0, opt_scalar_int_mode op0_mode,
 
 void
 store_bit_field (rtx str_rtx, poly_uint64 bitsize, poly_uint64 bitnum,
-                unsigned HOST_WIDE_INT bitregion_start,
-                unsigned HOST_WIDE_INT bitregion_end,
+                poly_uint64 bitregion_start, poly_uint64 bitregion_end,
                 machine_mode fieldmode,
                 rtx value, bool reverse)
 {
@@ -1130,15 +1148,12 @@ store_bit_field (rtx str_rtx, poly_uint64 bitsize, poly_uint64 bitnum,
   /* Under the C++0x memory model, we must not touch bits outside the
      bit region.  Adjust the address to start at the beginning of the
      bit region.  */
-  if (MEM_P (str_rtx) && bitregion_start > 0)
+  if (MEM_P (str_rtx) && maybe_ne (bitregion_start, 0U))
     {
       scalar_int_mode best_mode;
       machine_mode addr_mode = VOIDmode;
-      HOST_WIDE_INT offset;
-
-      gcc_assert ((bitregion_start % BITS_PER_UNIT) == 0);
 
-      offset = bitregion_start / BITS_PER_UNIT;
+      poly_uint64 offset = exact_div (bitregion_start, BITS_PER_UNIT);
       bitnum -= bitregion_start;
       poly_int64 size = bits_to_bytes_round_up (bitnum + bitsize);
       bitregion_end -= bitregion_start;
@@ -1171,8 +1186,7 @@ static void
 store_fixed_bit_field (rtx op0, opt_scalar_int_mode op0_mode,
                       unsigned HOST_WIDE_INT bitsize,
                       unsigned HOST_WIDE_INT bitnum,
-                      unsigned HOST_WIDE_INT bitregion_start,
-                      unsigned HOST_WIDE_INT bitregion_end,
+                      poly_uint64 bitregion_start, poly_uint64 bitregion_end,
                       rtx value, scalar_int_mode value_mode, bool reverse)
 {
   /* There is a case not handled here:
@@ -1327,8 +1341,7 @@ static void
 store_split_bit_field (rtx op0, opt_scalar_int_mode op0_mode,
                       unsigned HOST_WIDE_INT bitsize,
                       unsigned HOST_WIDE_INT bitpos,
-                      unsigned HOST_WIDE_INT bitregion_start,
-                      unsigned HOST_WIDE_INT bitregion_end,
+                      poly_uint64 bitregion_start, poly_uint64 bitregion_end,
                       rtx value, scalar_int_mode value_mode, bool reverse)
 {
   unsigned int unit, total_bits, bitsdone = 0;
@@ -1376,9 +1389,9 @@ store_split_bit_field (rtx op0, opt_scalar_int_mode op0_mode,
         UNIT close to the end of the region as needed.  If op0 is a REG
         or SUBREG of REG, don't do this, as there can't be data races
         on a register and we can expand shorter code in some cases.  */
-      if (bitregion_end
+      if (maybe_ne (bitregion_end, 0U)
          && unit > BITS_PER_UNIT
-         && bitpos + bitsdone - thispos + unit > bitregion_end + 1
+         && maybe_gt (bitpos + bitsdone - thispos + unit, bitregion_end + 1)
          && !REG_P (op0)
          && (GET_CODE (op0) != SUBREG || !REG_P (SUBREG_REG (op0))))
        {
@@ -1504,7 +1517,7 @@ extract_bit_field_using_extv (const extraction_insn *extv, rtx op0,
                              int unsignedp, rtx target,
                              machine_mode mode, machine_mode tmode)
 {
-  struct expand_operand ops[4];
+  class expand_operand ops[4];
   rtx spec_target = target;
   rtx spec_target_subreg = 0;
   scalar_int_mode ext_mode = extv->field_mode;
@@ -1575,16 +1588,33 @@ extract_bit_field_using_extv (const extraction_insn *extv, rtx op0,
   return NULL_RTX;
 }
 
+/* See whether it would be valid to extract the part of OP0 described
+   by BITNUM and BITSIZE into a value of mode MODE using a subreg
+   operation.  Return the subreg if so, otherwise return null.  */
+
+static rtx
+extract_bit_field_as_subreg (machine_mode mode, rtx op0,
+                            poly_uint64 bitsize, poly_uint64 bitnum)
+{
+  poly_uint64 bytenum;
+  if (multiple_p (bitnum, BITS_PER_UNIT, &bytenum)
+      && known_eq (bitsize, GET_MODE_BITSIZE (mode))
+      && lowpart_bit_field_p (bitnum, bitsize, GET_MODE (op0))
+      && TRULY_NOOP_TRUNCATION_MODES_P (mode, GET_MODE (op0)))
+    return simplify_gen_subreg (mode, op0, GET_MODE (op0), bytenum);
+  return NULL_RTX;
+}
+
 /* A subroutine of extract_bit_field, with the same arguments.
    If FALLBACK_P is true, fall back to extract_fixed_bit_field
    if we can find no other means of implementing the operation.
    if FALLBACK_P is false, return NULL instead.  */
 
 static rtx
-extract_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
-                    unsigned HOST_WIDE_INT bitnum, int unsignedp, rtx target,
-                    machine_mode mode, machine_mode tmode,
-                    bool reverse, bool fallback_p, rtx *alt_rtl)
+extract_bit_field_1 (rtx str_rtx, poly_uint64 bitsize, poly_uint64 bitnum,
+                    int unsignedp, rtx target, machine_mode mode,
+                    machine_mode tmode, bool reverse, bool fallback_p,
+                    rtx *alt_rtl)
 {
   rtx op0 = str_rtx;
   machine_mode mode1;
@@ -1601,13 +1631,13 @@ extract_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
   /* If we have an out-of-bounds access to a register, just return an
      uninitialized register of the required mode.  This can occur if the
      source code contains an out-of-bounds access to a small array.  */
-  if (REG_P (op0) && bitnum >= GET_MODE_BITSIZE (GET_MODE (op0)))
+  if (REG_P (op0) && known_ge (bitnum, GET_MODE_BITSIZE (GET_MODE (op0))))
     return gen_reg_rtx (tmode);
 
   if (REG_P (op0)
       && mode == GET_MODE (op0)
-      && bitnum == 0
-      && bitsize == GET_MODE_BITSIZE (GET_MODE (op0)))
+      && known_eq (bitnum, 0U)
+      && known_eq (bitsize, GET_MODE_BITSIZE (GET_MODE (op0))))
     {
       if (reverse)
        op0 = flip_storage_order (mode, op0);
@@ -1619,33 +1649,33 @@ extract_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
   if (VECTOR_MODE_P (GET_MODE (op0))
       && !MEM_P (op0)
       && VECTOR_MODE_P (tmode)
-      && GET_MODE_SIZE (GET_MODE (op0)) > GET_MODE_SIZE (tmode))
+      && known_eq (bitsize, GET_MODE_BITSIZE (tmode))
+      && maybe_gt (GET_MODE_SIZE (GET_MODE (op0)), GET_MODE_SIZE (tmode)))
     {
       machine_mode new_mode = GET_MODE (op0);
       if (GET_MODE_INNER (new_mode) != GET_MODE_INNER (tmode))
        {
          scalar_mode inner_mode = GET_MODE_INNER (tmode);
-         unsigned int nunits = (GET_MODE_BITSIZE (GET_MODE (op0))
-                                / GET_MODE_UNIT_BITSIZE (tmode));
-         if (!mode_for_vector (inner_mode, nunits).exists (&new_mode)
-             || !VECTOR_MODE_P (new_mode)
-             || GET_MODE_SIZE (new_mode) != GET_MODE_SIZE (GET_MODE (op0))
-             || GET_MODE_INNER (new_mode) != GET_MODE_INNER (tmode)
-             || !targetm.vector_mode_supported_p (new_mode))
+         poly_uint64 nunits;
+         if (!multiple_p (GET_MODE_BITSIZE (GET_MODE (op0)),
+                          GET_MODE_UNIT_BITSIZE (tmode), &nunits)
+             || !related_vector_mode (tmode, inner_mode,
+                                      nunits).exists (&new_mode)
+             || maybe_ne (GET_MODE_SIZE (new_mode),
+                          GET_MODE_SIZE (GET_MODE (op0))))
            new_mode = VOIDmode;
        }
+      poly_uint64 pos;
       if (new_mode != VOIDmode
          && (convert_optab_handler (vec_extract_optab, new_mode, tmode)
              != CODE_FOR_nothing)
-         && ((bitnum + bitsize - 1) / GET_MODE_BITSIZE (tmode)
-             == bitnum / GET_MODE_BITSIZE (tmode)))
+         && multiple_p (bitnum, GET_MODE_BITSIZE (tmode), &pos))
        {
-         struct expand_operand ops[3];
+         class expand_operand ops[3];
          machine_mode outermode = new_mode;
          machine_mode innermode = tmode;
          enum insn_code icode
            = convert_optab_handler (vec_extract_optab, outermode, innermode);
-         unsigned HOST_WIDE_INT pos = bitnum / GET_MODE_BITSIZE (innermode);
 
          if (new_mode != GET_MODE (op0))
            op0 = gen_lowpart (new_mode, op0);
@@ -1686,8 +1716,8 @@ extract_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
        new_mode = MIN_MODE_VECTOR_INT;
 
       FOR_EACH_MODE_FROM (new_mode, new_mode)
-       if (GET_MODE_SIZE (new_mode) == GET_MODE_SIZE (GET_MODE (op0))
-           && GET_MODE_UNIT_SIZE (new_mode) == GET_MODE_SIZE (tmode)
+       if (known_eq (GET_MODE_SIZE (new_mode), GET_MODE_SIZE (GET_MODE (op0)))
+           && known_eq (GET_MODE_UNIT_SIZE (new_mode), GET_MODE_SIZE (tmode))
            && targetm.vector_mode_supported_p (new_mode))
          break;
       if (new_mode != VOIDmode)
@@ -1695,33 +1725,43 @@ extract_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
     }
 
   /* Use vec_extract patterns for extracting parts of vectors whenever
-     available.  */
+     available.  If that fails, see whether the current modes and bitregion
+     give a natural subreg.  */
   machine_mode outermode = GET_MODE (op0);
-  scalar_mode innermode = GET_MODE_INNER (outermode);
-  if (VECTOR_MODE_P (outermode)
-      && !MEM_P (op0)
-      && (convert_optab_handler (vec_extract_optab, outermode, innermode)
-         != CODE_FOR_nothing)
-      && ((bitnum + bitsize - 1) / GET_MODE_BITSIZE (innermode)
-         == bitnum / GET_MODE_BITSIZE (innermode)))
+  if (VECTOR_MODE_P (outermode) && !MEM_P (op0))
     {
-      struct expand_operand ops[3];
+      scalar_mode innermode = GET_MODE_INNER (outermode);
       enum insn_code icode
        = convert_optab_handler (vec_extract_optab, outermode, innermode);
-      unsigned HOST_WIDE_INT pos = bitnum / GET_MODE_BITSIZE (innermode);
+      poly_uint64 pos;
+      if (icode != CODE_FOR_nothing
+         && known_eq (bitsize, GET_MODE_BITSIZE (innermode))
+         && multiple_p (bitnum, GET_MODE_BITSIZE (innermode), &pos))
+       {
+         class expand_operand ops[3];
 
-      create_output_operand (&ops[0], target, innermode);
-      ops[0].target = 1;
-      create_input_operand (&ops[1], op0, outermode);
-      create_integer_operand (&ops[2], pos);
-      if (maybe_expand_insn (icode, 3, ops))
+         create_output_operand (&ops[0], target, innermode);
+         ops[0].target = 1;
+         create_input_operand (&ops[1], op0, outermode);
+         create_integer_operand (&ops[2], pos);
+         if (maybe_expand_insn (icode, 3, ops))
+           {
+             if (alt_rtl && ops[0].target)
+               *alt_rtl = target;
+             target = ops[0].value;
+             if (GET_MODE (target) != mode)
+               return gen_lowpart (tmode, target);
+             return target;
+           }
+       }
+      /* Using subregs is useful if we're extracting one register vector
+        from a multi-register vector.  extract_bit_field_as_subreg checks
+        for valid bitsize and bitnum, so we don't need to do that here.  */
+      if (VECTOR_MODE_P (mode))
        {
-         if (alt_rtl && ops[0].target)
-           *alt_rtl = target;
-         target = ops[0].value;
-         if (GET_MODE (target) != mode)
-           return gen_lowpart (tmode, target);
-         return target;
+         rtx sub = extract_bit_field_as_subreg (mode, op0, bitsize, bitnum);
+         if (sub)
+           return sub;
        }
     }
 
@@ -1745,7 +1785,7 @@ extract_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
        }
       else
        {
-         HOST_WIDE_INT size = GET_MODE_SIZE (GET_MODE (op0));
+         poly_int64 size = GET_MODE_SIZE (GET_MODE (op0));
          rtx mem = assign_stack_temp (GET_MODE (op0), size);
          emit_move_insn (mem, op0);
          op0 = adjust_bitfield_address_size (mem, BLKmode, 0, size);
@@ -1766,14 +1806,9 @@ extract_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
   /* Extraction of a full MODE1 value can be done with a subreg as long
      as the least significant bit of the value is the least significant
      bit of either OP0 or a word of OP0.  */
-  if (!MEM_P (op0)
-      && !reverse
-      && lowpart_bit_field_p (bitnum, bitsize, op0_mode.require ())
-      && bitsize == GET_MODE_BITSIZE (mode1)
-      && TRULY_NOOP_TRUNCATION_MODES_P (mode1, op0_mode.require ()))
+  if (!MEM_P (op0) && !reverse)
     {
-      rtx sub = simplify_gen_subreg (mode1, op0, op0_mode.require (),
-                                    bitnum / BITS_PER_UNIT);
+      rtx sub = extract_bit_field_as_subreg (mode1, op0, bitsize, bitnum);
       if (sub)
        return convert_extracted_bit_field (sub, mode, tmode, unsignedp);
     }
@@ -1789,6 +1824,39 @@ extract_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
       return convert_extracted_bit_field (op0, mode, tmode, unsignedp);
     }
 
+  /* If we have a memory source and a non-constant bit offset, restrict
+     the memory to the referenced bytes.  This is a worst-case fallback
+     but is useful for things like vector booleans.  */
+  if (MEM_P (op0) && !bitnum.is_constant ())
+    {
+      bytenum = bits_to_bytes_round_down (bitnum);
+      bitnum = num_trailing_bits (bitnum);
+      poly_uint64 bytesize = bits_to_bytes_round_up (bitnum + bitsize);
+      op0 = adjust_bitfield_address_size (op0, BLKmode, bytenum, bytesize);
+      op0_mode = opt_scalar_int_mode ();
+    }
+
+  /* It's possible we'll need to handle other cases here for
+     polynomial bitnum and bitsize.  */
+
+  /* From here on we need to be looking at a fixed-size insertion.  */
+  return extract_integral_bit_field (op0, op0_mode, bitsize.to_constant (),
+                                    bitnum.to_constant (), unsignedp,
+                                    target, mode, tmode, reverse, fallback_p);
+}
+
+/* Subroutine of extract_bit_field_1, with the same arguments, except
+   that BITSIZE and BITNUM are constant.  Handle cases specific to
+   integral modes.  If OP0_MODE is defined, it is the mode of OP0,
+   otherwise OP0 is a BLKmode MEM.  */
+
+static rtx
+extract_integral_bit_field (rtx op0, opt_scalar_int_mode op0_mode,
+                           unsigned HOST_WIDE_INT bitsize,
+                           unsigned HOST_WIDE_INT bitnum, int unsignedp,
+                           rtx target, machine_mode mode, machine_mode tmode,
+                           bool reverse, bool fallback_p)
+{
   /* Handle fields bigger than a word.  */
 
   if (bitsize > BITS_PER_WORD)
@@ -1808,12 +1876,17 @@ extract_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
 
       /* In case we're about to clobber a base register or something 
         (see gcc.c-torture/execute/20040625-1.c).   */
-      if (reg_mentioned_p (target, str_rtx))
+      if (reg_mentioned_p (target, op0))
        target = gen_reg_rtx (mode);
 
       /* Indicate for flow that the entire target reg is being set.  */
       emit_clobber (target);
 
+      /* The mode must be fixed-size, since extract_bit_field_1 handles
+        extractions from variable-sized objects before calling this
+        function.  */
+      unsigned int target_size
+       = GET_MODE_SIZE (GET_MODE (target)).to_constant ();
       last = get_last_insn ();
       for (i = 0; i < nwords; i++)
        {
@@ -1821,9 +1894,7 @@ extract_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
             if I is 1, use the next to lowest word; and so on.  */
          /* Word number in TARGET to use.  */
          unsigned int wordnum
-           = (backwards
-              ? GET_MODE_SIZE (GET_MODE (target)) / UNITS_PER_WORD - i - 1
-              : i);
+           = (backwards ? target_size / UNITS_PER_WORD - i - 1 : i);
          /* Offset from start of field in OP0.  */
          unsigned int bit_offset = (backwards ^ reverse
                                     ? MAX ((int) bitsize - ((int) i + 1)
@@ -1852,11 +1923,11 @@ extract_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
        {
          /* Unless we've filled TARGET, the upper regs in a multi-reg value
             need to be zero'd out.  */
-         if (GET_MODE_SIZE (GET_MODE (target)) > nwords * UNITS_PER_WORD)
+         if (target_size > nwords * UNITS_PER_WORD)
            {
              unsigned int i, total_words;
 
-             total_words = GET_MODE_SIZE (GET_MODE (target)) / UNITS_PER_WORD;
+             total_words = target_size / UNITS_PER_WORD;
              for (i = nwords; i < total_words; i++)
                emit_move_insn
                  (operand_subword (target,
@@ -1991,46 +2062,54 @@ extract_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
    If a TARGET is specified and we can store in it at no extra cost,
    we do so, and return TARGET.
    Otherwise, we return a REG of mode TMODE or MODE, with TMODE preferred
-   if they are equally easy.  */
+   if they are equally easy.
+
+   If the result can be stored at TARGET, and ALT_RTL is non-NULL,
+   then *ALT_RTL is set to TARGET (before legitimziation).  */
 
 rtx
-extract_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
-                  unsigned HOST_WIDE_INT bitnum, int unsignedp, rtx target,
-                  machine_mode mode, machine_mode tmode, bool reverse,
-                  rtx *alt_rtl)
+extract_bit_field (rtx str_rtx, poly_uint64 bitsize, poly_uint64 bitnum,
+                  int unsignedp, rtx target, machine_mode mode,
+                  machine_mode tmode, bool reverse, rtx *alt_rtl)
 {
   machine_mode mode1;
 
   /* Handle -fstrict-volatile-bitfields in the cases where it applies.  */
-  if (GET_MODE_BITSIZE (GET_MODE (str_rtx)) > 0)
+  if (maybe_ne (GET_MODE_BITSIZE (GET_MODE (str_rtx)), 0))
     mode1 = GET_MODE (str_rtx);
-  else if (target && GET_MODE_BITSIZE (GET_MODE (target)) > 0)
+  else if (target && maybe_ne (GET_MODE_BITSIZE (GET_MODE (target)), 0))
     mode1 = GET_MODE (target);
   else
     mode1 = tmode;
 
+  unsigned HOST_WIDE_INT ibitsize, ibitnum;
   scalar_int_mode int_mode;
-  if (is_a <scalar_int_mode> (mode1, &int_mode)
-      && strict_volatile_bitfield_p (str_rtx, bitsize, bitnum, int_mode, 0, 0))
+  if (bitsize.is_constant (&ibitsize)
+      && bitnum.is_constant (&ibitnum)
+      && is_a <scalar_int_mode> (mode1, &int_mode)
+      && strict_volatile_bitfield_p (str_rtx, ibitsize, ibitnum,
+                                    int_mode, 0, 0))
     {
       /* Extraction of a full INT_MODE value can be done with a simple load.
         We know here that the field can be accessed with one single
         instruction.  For targets that support unaligned memory,
         an unaligned access may be necessary.  */
-      if (bitsize == GET_MODE_BITSIZE (int_mode))
+      if (ibitsize == GET_MODE_BITSIZE (int_mode))
        {
          rtx result = adjust_bitfield_address (str_rtx, int_mode,
-                                               bitnum / BITS_PER_UNIT);
+                                               ibitnum / BITS_PER_UNIT);
          if (reverse)
            result = flip_storage_order (int_mode, result);
-         gcc_assert (bitnum % BITS_PER_UNIT == 0);
+         gcc_assert (ibitnum % BITS_PER_UNIT == 0);
          return convert_extracted_bit_field (result, mode, tmode, unsignedp);
        }
 
-      str_rtx = narrow_bit_field_mem (str_rtx, int_mode, bitsize, bitnum,
-                                     &bitnum);
-      gcc_assert (bitnum + bitsize <= GET_MODE_BITSIZE (int_mode));
+      str_rtx = narrow_bit_field_mem (str_rtx, int_mode, ibitsize, ibitnum,
+                                     &ibitnum);
+      gcc_assert (ibitnum + ibitsize <= GET_MODE_BITSIZE (int_mode));
       str_rtx = copy_to_reg (str_rtx);
+      return extract_bit_field_1 (str_rtx, ibitsize, ibitnum, unsignedp,
+                                 target, mode, tmode, reverse, true, alt_rtl);
     }
 
   return extract_bit_field_1 (str_rtx, bitsize, bitnum, unsignedp,
@@ -2298,7 +2377,7 @@ extract_low_bits (machine_mode mode, machine_mode src_mode, rtx src)
       /* simplify_gen_subreg can't be used here, as if simplify_subreg
         fails, it will happily create (subreg (symbol_ref)) or similar
         invalid SUBREGs.  */
-      unsigned int byte = subreg_lowpart_offset (mode, src_mode);
+      poly_uint64 byte = subreg_lowpart_offset (mode, src_mode);
       rtx ret = simplify_subreg (mode, src, src_mode, byte);
       if (ret)
        return ret;
@@ -2314,7 +2393,7 @@ extract_low_bits (machine_mode mode, machine_mode src_mode, rtx src)
   if (GET_MODE_CLASS (mode) == MODE_CC || GET_MODE_CLASS (src_mode) == MODE_CC)
     return NULL_RTX;
 
-  if (GET_MODE_BITSIZE (mode) == GET_MODE_BITSIZE (src_mode)
+  if (known_eq (GET_MODE_BITSIZE (mode), GET_MODE_BITSIZE (src_mode))
       && targetm.modes_tieable_p (mode, src_mode))
     {
       rtx x = gen_lowpart_common (mode, src);
@@ -2332,6 +2411,10 @@ extract_low_bits (machine_mode mode, machine_mode src_mode, rtx src)
     return NULL_RTX;
 
   src = gen_lowpart (src_int_mode, src);
+  if (!validate_subreg (int_mode, src_int_mode, src,
+                       subreg_lowpart_offset (int_mode, src_int_mode)))
+    return NULL_RTX;
+
   src = convert_modes (int_mode, src_int_mode, src, true);
   src = gen_lowpart (mode, src);
   return src;
@@ -2443,9 +2526,8 @@ expand_shift_1 (enum tree_code code, machine_mode mode, rtx shifted,
       && CONST_INT_P (op1)
       && INTVAL (op1) == BITS_PER_UNIT
       && GET_MODE_SIZE (scalar_mode) == 2
-      && optab_handler (bswap_optab, HImode) != CODE_FOR_nothing)
-    return expand_unop (HImode, bswap_optab, shifted, NULL_RTX,
-                                 unsignedp);
+      && optab_handler (bswap_optab, mode) != CODE_FOR_nothing)
+    return expand_unop (mode, bswap_optab, shifted, NULL_RTX, unsignedp);
 
   if (op1 == const0_rtx)
     return shifted;
@@ -3284,20 +3366,29 @@ expand_mult_const (machine_mode mode, rtx op0, HOST_WIDE_INT val,
          /* Write a REG_EQUAL note on the last insn so that we can cse
             multiplication sequences.  Note that if ACCUM is a SUBREG,
             we've set the inner register and must properly indicate that.  */
-          tem = op0, nmode = mode;
-          accum_inner = accum;
-          if (GET_CODE (accum) == SUBREG)
+         tem = op0, nmode = mode;
+         accum_inner = accum;
+         if (GET_CODE (accum) == SUBREG)
            {
              accum_inner = SUBREG_REG (accum);
              nmode = GET_MODE (accum_inner);
              tem = gen_lowpart (nmode, op0);
            }
 
-          insn = get_last_insn ();
-          set_dst_reg_note (insn, REG_EQUAL,
-                           gen_rtx_MULT (nmode, tem,
-                                         gen_int_mode (val_so_far, nmode)),
-                           accum_inner);
+         /* Don't add a REG_EQUAL note if tem is a paradoxical SUBREG.
+            In that case, only the low bits of accum would be guaranteed to
+            be equal to the content of the REG_EQUAL note, the upper bits
+            can be anything.  */
+         if (!paradoxical_subreg_p (tem))
+           {
+             insn = get_last_insn ();
+             wide_int wval_so_far
+               = wi::uhwi (val_so_far,
+                           GET_MODE_PRECISION (as_a <scalar_mode> (nmode)));
+             rtx c = immed_wide_int_const (wval_so_far, nmode);
+             set_dst_reg_note (insn, REG_EQUAL, gen_rtx_MULT (nmode, tem, c),
+                               accum_inner);
+           }
        }
     }
 
@@ -3619,7 +3710,7 @@ choose_multiplier (unsigned HOST_WIDE_INT d, int n, int precision,
     {
       unsigned HOST_WIDE_INT mask = (HOST_WIDE_INT_1U << n) - 1;
       *multiplier_ptr = mhigh.to_uhwi () & mask;
-      return mhigh.to_uhwi () >= mask;
+      return mhigh.to_uhwi () > mask;
     }
   else
     {
@@ -3811,7 +3902,7 @@ expmed_mult_highpart_optab (scalar_int_mode mode, rtx op0, rtx op1,
 
 /* Emit code to multiply OP0 and OP1 (where OP1 is an integer constant),
    putting the high half of the result in TARGET if that is convenient,
-   and return where the result is.  If the operation can not be performed,
+   and return where the result is.  If the operation cannot be performed,
    0 is returned.
 
    MODE is the mode of operation and result.
@@ -4421,6 +4512,11 @@ expand_divmod (int rem_flag, enum tree_code code, machine_mode mode,
                HOST_WIDE_INT d = INTVAL (op1);
                unsigned HOST_WIDE_INT abs_d;
 
+               /* Not prepared to handle division/remainder by
+                  0xffffffffffffffff8000000000000000 etc.  */
+               if (d == HOST_WIDE_INT_MIN && size > HOST_BITS_PER_WIDE_INT)
+                 break;
+
                /* Since d might be INT_MIN, we have to cast to
                   unsigned HOST_WIDE_INT before negating to avoid
                   undefined signed overflow.  */
@@ -4463,9 +4559,7 @@ expand_divmod (int rem_flag, enum tree_code code, machine_mode mode,
                             || (optab_handler (sdivmod_optab, int_mode)
                                 != CODE_FOR_nothing)))
                  ;
-               else if (EXACT_POWER_OF_2_OR_ZERO_P (abs_d)
-                        && (size <= HOST_BITS_PER_WIDE_INT
-                            || abs_d != (unsigned HOST_WIDE_INT) d))
+               else if (EXACT_POWER_OF_2_OR_ZERO_P (abs_d))
                  {
                    if (rem_flag)
                      {
@@ -5227,13 +5321,14 @@ make_tree (tree type, rtx x)
 
     case CONST_VECTOR:
       {
-       int units = CONST_VECTOR_NUNITS (x);
+       unsigned int npatterns = CONST_VECTOR_NPATTERNS (x);
+       unsigned int nelts_per_pattern = CONST_VECTOR_NELTS_PER_PATTERN (x);
        tree itype = TREE_TYPE (type);
-       int i;
 
        /* Build a tree with vector elements.  */
-       tree_vector_builder elts (type, units, 1);
-       for (i = 0; i < units; ++i)
+       tree_vector_builder elts (type, npatterns, nelts_per_pattern);
+       unsigned int count = elts.encoded_nelts ();
+       for (unsigned int i = 0; i < count; ++i)
          {
            rtx elt = CONST_VECTOR_ELT (x, i);
            elts.quick_push (make_tree (itype, elt));
@@ -5295,22 +5390,7 @@ make_tree (tree type, rtx x)
       return fold_convert (type, make_tree (t, XEXP (x, 0)));
 
     case CONST:
-      {
-       rtx op = XEXP (x, 0);
-       if (GET_CODE (op) == VEC_DUPLICATE)
-         {
-           tree elt_tree = make_tree (TREE_TYPE (type), XEXP (op, 0));
-           return build_vector_from_val (type, elt_tree);
-         }
-       if (GET_CODE (op) == VEC_SERIES)
-         {
-           tree itype = TREE_TYPE (type);
-           tree base_tree = make_tree (itype, XEXP (op, 0));
-           tree step_tree = make_tree (itype, XEXP (op, 1));
-           return build_vec_series (type, base_tree, step_tree);
-         }
-       return make_tree (type, op);
-      }
+      return make_tree (type, XEXP (x, 0));
 
     case SYMBOL_REF:
       t = SYMBOL_REF_DECL (x);
@@ -5367,7 +5447,7 @@ emit_cstore (rtx target, enum insn_code icode, enum rtx_code code,
             int unsignedp, rtx x, rtx y, int normalizep,
             machine_mode target_mode)
 {
-  struct expand_operand ops[4];
+  class expand_operand ops[4];
   rtx op0, comparison, subtarget;
   rtx_insn *last;
   scalar_int_mode result_mode = targetm.cstore_mode (icode);
@@ -5410,11 +5490,14 @@ emit_cstore (rtx target, enum insn_code icode, enum rtx_code code,
      If STORE_FLAG_VALUE does not have the sign bit set when
      interpreted in MODE, we can do this conversion as unsigned, which
      is usually more efficient.  */
-  if (GET_MODE_SIZE (int_target_mode) > GET_MODE_SIZE (result_mode))
+  if (GET_MODE_PRECISION (int_target_mode) > GET_MODE_PRECISION (result_mode))
     {
-      convert_move (target, subtarget,
-                   val_signbit_known_clear_p (result_mode,
-                                              STORE_FLAG_VALUE));
+      gcc_assert (GET_MODE_PRECISION (result_mode) != 1
+                 || STORE_FLAG_VALUE == 1 || STORE_FLAG_VALUE == -1);
+
+      bool unsignedp = (STORE_FLAG_VALUE >= 0);
+      convert_move (target, subtarget, unsignedp);
+
       op0 = target;
       result_mode = int_target_mode;
     }
@@ -5493,6 +5576,9 @@ emit_store_flag_1 (rtx target, enum rtx_code code, rtx op0, rtx op1,
   if (mode == VOIDmode)
     mode = GET_MODE (op0);
 
+  if (CONST_SCALAR_INT_P (op1))
+    canonicalize_comparison (mode, &code, &op1);
+
   /* For some comparisons with 1 and -1, we can convert this to
      comparisons with zero.  This will often produce more opportunities for
      store-flag insns.  */
@@ -5993,6 +6079,11 @@ emit_store_flag (rtx target, enum rtx_code code, rtx op0, rtx op1,
       if (!HAVE_conditional_move)
        return 0;
 
+      /* Do not turn a trapping comparison into a non-trapping one.  */
+      if ((code != EQ && code != NE && code != UNEQ && code != LTGT)
+         && flag_trapping_math)
+       return 0;
+
       /* Try using a setcc instruction for ORDERED/UNORDERED, followed by a
         conditional move.  */
       tem = emit_store_flag_1 (subtarget, first_code, op0, op1, mode, 0,
@@ -6037,6 +6128,17 @@ emit_store_flag_force (rtx target, enum rtx_code code, rtx op0, rtx op1,
   if (tem != 0)
     return tem;
 
+  /* If one operand is constant, make it the second one.  Only do this
+     if the other operand is not constant as well.  */
+  if (swap_commutative_operands_p (op0, op1))
+    {
+      std::swap (op0, op1);
+      code = swap_condition (code);
+    }
+
+  if (mode == VOIDmode)
+    mode = GET_MODE (op0);
+
   if (!target)
     target = gen_reg_rtx (word_mode);
 
@@ -6097,6 +6199,106 @@ emit_store_flag_force (rtx target, enum rtx_code code, rtx op0, rtx op1,
 
   return target;
 }
+
+/* Helper function for canonicalize_cmp_for_target.  Swap between inclusive
+   and exclusive ranges in order to create an equivalent comparison.  See
+   canonicalize_cmp_for_target for the possible cases.  */
+
+static enum rtx_code
+equivalent_cmp_code (enum rtx_code code)
+{
+  switch (code)
+    {
+    case GT:
+      return GE;
+    case GE:
+      return GT;
+    case LT:
+      return LE;
+    case LE:
+      return LT;
+    case GTU:
+      return GEU;
+    case GEU:
+      return GTU;
+    case LTU:
+      return LEU;
+    case LEU:
+      return LTU;
+
+    default:
+      return code;
+    }
+}
+
+/* Choose the more appropiate immediate in scalar integer comparisons.  The
+   purpose of this is to end up with an immediate which can be loaded into a
+   register in fewer moves, if possible.
+
+   For each integer comparison there exists an equivalent choice:
+     i)   a >  b or a >= b + 1
+     ii)  a <= b or a <  b + 1
+     iii) a >= b or a >  b - 1
+     iv)  a <  b or a <= b - 1
+
+   MODE is the mode of the first operand.
+   CODE points to the comparison code.
+   IMM points to the rtx containing the immediate.  *IMM must satisfy
+   CONST_SCALAR_INT_P on entry and continues to satisfy CONST_SCALAR_INT_P
+   on exit.  */
+
+void
+canonicalize_comparison (machine_mode mode, enum rtx_code *code, rtx *imm)
+{
+  if (!SCALAR_INT_MODE_P (mode))
+    return;
+
+  int to_add = 0;
+  enum signop sgn = unsigned_condition_p (*code) ? UNSIGNED : SIGNED;
+
+  /* Extract the immediate value from the rtx.  */
+  wide_int imm_val = rtx_mode_t (*imm, mode);
+
+  if (*code == GT || *code == GTU || *code == LE || *code == LEU)
+    to_add = 1;
+  else if (*code == GE || *code == GEU || *code == LT || *code == LTU)
+    to_add = -1;
+  else
+    return;
+
+  /* Check for overflow/underflow in the case of signed values and
+     wrapping around in the case of unsigned values.  If any occur
+     cancel the optimization.  */
+  wi::overflow_type overflow = wi::OVF_NONE;
+  wide_int imm_modif;
+
+  if (to_add == 1)
+    imm_modif = wi::add (imm_val, 1, sgn, &overflow);
+  else
+    imm_modif = wi::sub (imm_val, 1, sgn, &overflow);
+
+  if (overflow)
+    return;
+
+  /* The following creates a pseudo; if we cannot do that, bail out.  */
+  if (!can_create_pseudo_p ())
+    return;
+
+  rtx reg = gen_rtx_REG (mode, LAST_VIRTUAL_REGISTER + 1);
+  rtx new_imm = immed_wide_int_const (imm_modif, mode);
+
+  rtx_insn *old_rtx = gen_move_insn (reg, *imm);
+  rtx_insn *new_rtx = gen_move_insn (reg, new_imm);
+
+  /* Update the immediate and the code.  */
+  if (insn_cost (old_rtx, true) > insn_cost (new_rtx, true))
+    {
+      *code = equivalent_cmp_code (*code);
+      *imm = new_imm;
+    }
+}
+
+
 \f
 /* Perform possibly multi-word comparison and conditional jump to LABEL
    if ARG1 OP ARG2 true where ARG1 and ARG2 are of mode MODE.  This is