Use vec<> in build_vector
[gcc.git] / gcc / combine.c
index 2fbfed4c416ed9eaa3b79dfd24ec968016ce116c..1832c3cb2bca0c1caa115a9761263090efccf538 100644 (file)
@@ -370,7 +370,7 @@ static int label_tick_ebb_start;
 /* Mode used to compute significance in reg_stat[].nonzero_bits.  It is the
    largest integer mode that can fit in HOST_BITS_PER_WIDE_INT.  */
 
-static machine_mode nonzero_bits_mode;
+static scalar_int_mode nonzero_bits_mode;
 
 /* Nonzero when reg_stat[].nonzero_bits and reg_stat[].sign_bit_copies can
    be safely used.  It is zero while computing them and after combine has
@@ -414,13 +414,12 @@ static struct undobuf undobuf;
 
 static int n_occurrences;
 
-static rtx reg_nonzero_bits_for_combine (const_rtx, machine_mode, const_rtx,
-                                        machine_mode,
-                                        unsigned HOST_WIDE_INT,
+static rtx reg_nonzero_bits_for_combine (const_rtx, scalar_int_mode,
+                                        scalar_int_mode,
                                         unsigned HOST_WIDE_INT *);
-static rtx reg_num_sign_bit_copies_for_combine (const_rtx, machine_mode, const_rtx,
-                                               machine_mode,
-                                               unsigned int, unsigned int *);
+static rtx reg_num_sign_bit_copies_for_combine (const_rtx, scalar_int_mode,
+                                               scalar_int_mode,
+                                               unsigned int *);
 static void do_SUBST (rtx *, rtx);
 static void do_SUBST_INT (int *, int);
 static void init_reg_last (void);
@@ -445,7 +444,6 @@ static rtx expand_compound_operation (rtx);
 static const_rtx expand_field_assignment (const_rtx);
 static rtx make_extraction (machine_mode, rtx, HOST_WIDE_INT,
                            rtx, unsigned HOST_WIDE_INT, int, int, int);
-static rtx extract_left_shift (rtx, int);
 static int get_pos_from_mask (unsigned HOST_WIDE_INT,
                              unsigned HOST_WIDE_INT *);
 static rtx canon_reg_for_combine (rtx, rtx);
@@ -459,9 +457,9 @@ static int rtx_equal_for_field_assignment_p (rtx, rtx, bool = false);
 static rtx make_field_assignment (rtx);
 static rtx apply_distributive_law (rtx);
 static rtx distribute_and_simplify_rtx (rtx, int);
-static rtx simplify_and_const_int_1 (machine_mode, rtx,
+static rtx simplify_and_const_int_1 (scalar_int_mode, rtx,
                                     unsigned HOST_WIDE_INT);
-static rtx simplify_and_const_int (rtx, machine_mode, rtx,
+static rtx simplify_and_const_int (rtx, scalar_int_mode, rtx,
                                   unsigned HOST_WIDE_INT);
 static int merge_outer_ops (enum rtx_code *, HOST_WIDE_INT *, enum rtx_code,
                            HOST_WIDE_INT, machine_mode, int *);
@@ -1159,7 +1157,7 @@ combine_instructions (rtx_insn *f, unsigned int nregs)
   uid_insn_cost = XCNEWVEC (int, max_uid_known + 1);
   gcc_obstack_init (&insn_link_obstack);
 
-  nonzero_bits_mode = mode_for_size (HOST_BITS_PER_WIDE_INT, MODE_INT, 0);
+  nonzero_bits_mode = int_mode_for_size (HOST_BITS_PER_WIDE_INT, 0).require ();
 
   /* Don't use reg_stat[].nonzero_bits when computing it.  This can cause
      problems when, for example, we have j <<= 1 in a loop.  */
@@ -2013,7 +2011,7 @@ can_combine_p (rtx_insn *insn, rtx_insn *i3, rtx_insn *pred ATTRIBUTE_UNUSED,
 
       if (REG_P (src)
          && ((REGNO (dest) < FIRST_PSEUDO_REGISTER
-              && ! HARD_REGNO_MODE_OK (REGNO (dest), GET_MODE (dest)))
+              && !targetm.hard_regno_mode_ok (REGNO (dest), GET_MODE (dest)))
              /* Don't extend the life of a hard register unless it is
                 user variable (if we have few registers) or it can't
                 fit into the desired register (meaning something special
@@ -2022,7 +2020,8 @@ can_combine_p (rtx_insn *insn, rtx_insn *i3, rtx_insn *pred ATTRIBUTE_UNUSED,
                 reload can't handle a conflict with constraints of other
                 inputs.  */
              || (REGNO (src) < FIRST_PSEUDO_REGISTER
-                 && ! HARD_REGNO_MODE_OK (REGNO (src), GET_MODE (src)))))
+                 && !targetm.hard_regno_mode_ok (REGNO (src),
+                                                 GET_MODE (src)))))
        return 0;
     }
   else if (GET_CODE (dest) != CC0)
@@ -2212,8 +2211,8 @@ combinable_i3pat (rtx_insn *i3, rtx *loc, rtx i2dest, rtx i1dest, rtx i0dest,
 
          || (REG_P (inner_dest)
              && REGNO (inner_dest) < FIRST_PSEUDO_REGISTER
-             && (! HARD_REGNO_MODE_OK (REGNO (inner_dest),
-                                       GET_MODE (inner_dest))))
+             && !targetm.hard_regno_mode_ok (REGNO (inner_dest),
+                                             GET_MODE (inner_dest)))
          || (i1_not_in_src && reg_overlap_mentioned_p (i1dest, src))
          || (i0_not_in_src && reg_overlap_mentioned_p (i0dest, src)))
        return 0;
@@ -2226,9 +2225,7 @@ combinable_i3pat (rtx_insn *i3, rtx *loc, rtx i2dest, rtx i1dest, rtx i0dest,
         STACK_POINTER_REGNUM, since these are always considered to be
         live.  Similarly for ARG_POINTER_REGNUM if it is fixed.  */
       subdest = dest;
-      if (GET_CODE (subdest) == SUBREG
-         && (GET_MODE_SIZE (GET_MODE (subdest))
-             >= GET_MODE_SIZE (GET_MODE (SUBREG_REG (subdest)))))
+      if (GET_CODE (subdest) == SUBREG && !partial_subreg_p (subdest))
        subdest = SUBREG_REG (subdest);
       if (pi3dest_killed
          && REG_P (subdest)
@@ -2458,8 +2455,8 @@ can_change_dest_mode (rtx x, int added_sets, machine_mode mode)
   /* Allow hard registers if the new mode is legal, and occupies no more
      registers than the old mode.  */
   if (regno < FIRST_PSEUDO_REGISTER)
-    return (HARD_REGNO_MODE_OK (regno, mode)
-           && REG_NREGS (x) >= hard_regno_nregs[regno][mode]);
+    return (targetm.hard_regno_mode_ok (regno, mode)
+           && REG_NREGS (x) >= hard_regno_nregs (regno, mode));
 
   /* Or a pseudo that is only used once.  */
   return (regno < reg_n_sets_max
@@ -2647,6 +2644,7 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
   rtx other_pat = 0;
   rtx new_other_notes;
   int i;
+  scalar_int_mode dest_mode, temp_mode;
 
   /* Immediately return if any of I0,I1,I2 are the same insn (I3 can
      never be).  */
@@ -2849,33 +2847,40 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
      constant.  */
   if (i1 == 0
       && (temp_expr = single_set (i2)) != 0
+      && is_a <scalar_int_mode> (GET_MODE (SET_DEST (temp_expr)), &temp_mode)
       && CONST_SCALAR_INT_P (SET_SRC (temp_expr))
       && GET_CODE (PATTERN (i3)) == SET
       && CONST_SCALAR_INT_P (SET_SRC (PATTERN (i3)))
       && reg_subword_p (SET_DEST (PATTERN (i3)), SET_DEST (temp_expr)))
     {
       rtx dest = SET_DEST (PATTERN (i3));
+      rtx temp_dest = SET_DEST (temp_expr);
       int offset = -1;
       int width = 0;
-      
+
       if (GET_CODE (dest) == ZERO_EXTRACT)
        {
          if (CONST_INT_P (XEXP (dest, 1))
-             && CONST_INT_P (XEXP (dest, 2)))
+             && CONST_INT_P (XEXP (dest, 2))
+             && is_a <scalar_int_mode> (GET_MODE (XEXP (dest, 0)),
+                                        &dest_mode))
            {
              width = INTVAL (XEXP (dest, 1));
              offset = INTVAL (XEXP (dest, 2));
              dest = XEXP (dest, 0);
              if (BITS_BIG_ENDIAN)
-               offset = GET_MODE_PRECISION (GET_MODE (dest)) - width - offset;
+               offset = GET_MODE_PRECISION (dest_mode) - width - offset;
            }
        }
       else
        {
          if (GET_CODE (dest) == STRICT_LOW_PART)
            dest = XEXP (dest, 0);
-         width = GET_MODE_PRECISION (GET_MODE (dest));
-         offset = 0;
+         if (is_a <scalar_int_mode> (GET_MODE (dest), &dest_mode))
+           {
+             width = GET_MODE_PRECISION (dest_mode);
+             offset = 0;
+           }
        }
 
       if (offset >= 0)
@@ -2884,9 +2889,9 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
          if (subreg_lowpart_p (dest))
            ;
          /* Handle the case where inner is twice the size of outer.  */
-         else if (GET_MODE_PRECISION (GET_MODE (SET_DEST (temp_expr)))
-                  == 2 * GET_MODE_PRECISION (GET_MODE (dest)))
-           offset += GET_MODE_PRECISION (GET_MODE (dest));
+         else if (GET_MODE_PRECISION (temp_mode)
+                  == 2 * GET_MODE_PRECISION (dest_mode))
+           offset += GET_MODE_PRECISION (dest_mode);
          /* Otherwise give up for now.  */
          else
            offset = -1;
@@ -2897,23 +2902,22 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
          rtx inner = SET_SRC (PATTERN (i3));
          rtx outer = SET_SRC (temp_expr);
 
-         wide_int o
-           = wi::insert (rtx_mode_t (outer, GET_MODE (SET_DEST (temp_expr))),
-                         rtx_mode_t (inner, GET_MODE (dest)),
-                         offset, width);
+         wide_int o = wi::insert (rtx_mode_t (outer, temp_mode),
+                                  rtx_mode_t (inner, dest_mode),
+                                  offset, width);
 
          combine_merges++;
          subst_insn = i3;
          subst_low_luid = DF_INSN_LUID (i2);
          added_sets_2 = added_sets_1 = added_sets_0 = 0;
-         i2dest = SET_DEST (temp_expr);
+         i2dest = temp_dest;
          i2dest_killed = dead_or_set_p (i2, i2dest);
 
          /* Replace the source in I2 with the new constant and make the
             resulting insn the new pattern for I3.  Then skip to where we
             validate the pattern.  Everything was set up above.  */
          SUBST (SET_SRC (temp_expr),
-                immed_wide_int_const (o, GET_MODE (SET_DEST (temp_expr))));
+                immed_wide_int_const (o, temp_mode));
 
          newpat = PATTERN (i2);
 
@@ -3485,7 +3489,10 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
      i3, and one from i2.  Combining then splitting the parallel results
      in the original i2 again plus an invalid insn (which we delete).
      The net effect is only to move instructions around, which makes
-     debug info less accurate.  */
+     debug info less accurate.
+
+     If the remaining SET came from I2 its destination should not be used
+     between I2 and I3.  See PR82024.  */
 
   if (!(added_sets_2 && i1 == 0)
       && is_parallel_of_n_reg_sets (newpat, 2)
@@ -3514,11 +3521,17 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
               && insn_nothrow_p (i3)
               && !side_effects_p (SET_SRC (set0)))
        {
-         newpat = set1;
-         insn_code_number = recog_for_combine (&newpat, i3, &new_i3_notes);
+         rtx dest = SET_DEST (set1);
+         if (GET_CODE (dest) == SUBREG)
+           dest = SUBREG_REG (dest);
+         if (!reg_used_between_p (dest, i2, i3))
+           {
+             newpat = set1;
+             insn_code_number = recog_for_combine (&newpat, i3, &new_i3_notes);
 
-         if (insn_code_number >= 0)
-           changed_i3_dest = 1;
+             if (insn_code_number >= 0)
+               changed_i3_dest = 1;
+           }
        }
 
       if (insn_code_number < 0)
@@ -5434,11 +5447,11 @@ subst (rtx x, rtx from, rtx to, int in_dest, int in_cond, int unique_copy)
                     FROM to CC0.  */
 
                  if (GET_CODE (to) == SUBREG
-                     && ! MODES_TIEABLE_P (GET_MODE (to),
-                                           GET_MODE (SUBREG_REG (to)))
+                     && !targetm.modes_tieable_p (GET_MODE (to),
+                                                  GET_MODE (SUBREG_REG (to)))
                      && ! (code == SUBREG
-                           && MODES_TIEABLE_P (GET_MODE (x),
-                                               GET_MODE (SUBREG_REG (to))))
+                           && (targetm.modes_tieable_p
+                               (GET_MODE (x), GET_MODE (SUBREG_REG (to)))))
                      && (!HAVE_cc0
                          || (! (code == SET
                                 && i == 1
@@ -6489,7 +6502,7 @@ simplify_if_then_else (rtx x)
       rtx cond_op0 = XEXP (cond, 0);
       rtx cond_op1 = XEXP (cond, 1);
       enum rtx_code op = UNKNOWN, extend_op = UNKNOWN;
-      machine_mode m = int_mode;
+      scalar_int_mode m = int_mode;
       rtx z = 0, c1 = NULL_RTX;
 
       if ((GET_CODE (t) == PLUS || GET_CODE (t) == MINUS
@@ -6877,10 +6890,8 @@ simplify_set (rtx x)
   /* If we have (set (cc0) (subreg ...)), we try to remove the subreg
      in SRC.  */
   if (dest == cc0_rtx
-      && GET_CODE (src) == SUBREG
-      && subreg_lowpart_p (src)
-      && (GET_MODE_PRECISION (GET_MODE (src))
-         < GET_MODE_PRECISION (GET_MODE (SUBREG_REG (src)))))
+      && partial_subreg_p (src)
+      && subreg_lowpart_p (src))
     {
       rtx inner = SUBREG_REG (src);
       machine_mode inner_mode = GET_MODE (inner);
@@ -7422,9 +7433,9 @@ make_extraction (machine_mode mode, rtx inner, HOST_WIDE_INT pos,
      ignore the POS lowest bits, etc.  */
   machine_mode is_mode = GET_MODE (inner);
   machine_mode inner_mode;
-  machine_mode wanted_inner_mode;
-  machine_mode wanted_inner_reg_mode = word_mode;
-  machine_mode pos_mode = word_mode;
+  scalar_int_mode wanted_inner_mode;
+  scalar_int_mode wanted_inner_reg_mode = word_mode;
+  scalar_int_mode pos_mode = word_mode;
   machine_mode extraction_mode = word_mode;
   rtx new_rtx = 0;
   rtx orig_pos_rtx = pos_rtx;
@@ -7629,7 +7640,7 @@ make_extraction (machine_mode mode, rtx inner, HOST_WIDE_INT pos,
   /* Never narrow an object, since that might not be safe.  */
 
   if (mode != VOIDmode
-      && GET_MODE_SIZE (extraction_mode) < GET_MODE_SIZE (mode))
+      && partial_subreg_p (extraction_mode, mode))
     extraction_mode = mode;
 
   if (!MEM_P (inner))
@@ -7676,7 +7687,7 @@ make_extraction (machine_mode mode, rtx inner, HOST_WIDE_INT pos,
   if (wanted_inner_mode != VOIDmode
       && inner_mode != wanted_inner_mode
       && ! pos_rtx
-      && GET_MODE_SIZE (wanted_inner_mode) < GET_MODE_SIZE (is_mode)
+      && partial_subreg_p (wanted_inner_mode, is_mode)
       && MEM_P (inner)
       && ! mode_dependent_address_p (XEXP (inner, 0), MEM_ADDR_SPACE (inner))
       && ! MEM_VOLATILE_P (inner))
@@ -7789,14 +7800,14 @@ make_extraction (machine_mode mode, rtx inner, HOST_WIDE_INT pos,
   return new_rtx;
 }
 \f
-/* See if X contains an ASHIFT of COUNT or more bits that can be commuted
-   with any other operations in X.  Return X without that shift if so.  */
+/* See if X (of mode MODE) contains an ASHIFT of COUNT or more bits that
+   can be commuted with any other operations in X.  Return X without
+   that shift if so.  */
 
 static rtx
-extract_left_shift (rtx x, int count)
+extract_left_shift (scalar_int_mode mode, rtx x, int count)
 {
   enum rtx_code code = GET_CODE (x);
-  machine_mode mode = GET_MODE (x);
   rtx tem;
 
   switch (code)
@@ -7812,7 +7823,7 @@ extract_left_shift (rtx x, int count)
       break;
 
     case NEG:  case NOT:
-      if ((tem = extract_left_shift (XEXP (x, 0), count)) != 0)
+      if ((tem = extract_left_shift (mode, XEXP (x, 0), count)) != 0)
        return simplify_gen_unary (code, mode, tem, mode);
 
       break;
@@ -7823,7 +7834,7 @@ extract_left_shift (rtx x, int count)
       if (CONST_INT_P (XEXP (x, 1))
          && (UINTVAL (XEXP (x, 1))
              & (((HOST_WIDE_INT_1U << count)) - 1)) == 0
-         && (tem = extract_left_shift (XEXP (x, 0), count)) != 0)
+         && (tem = extract_left_shift (mode, XEXP (x, 0), count)) != 0)
        {
          HOST_WIDE_INT val = INTVAL (XEXP (x, 1)) >> count;
          return simplify_gen_binary (code, mode, tem,
@@ -7851,7 +7862,7 @@ extract_left_shift (rtx x, int count)
    - Return a new rtx, which the caller returns directly.  */
 
 static rtx
-make_compound_operation_int (machine_mode mode, rtx *x_ptr,
+make_compound_operation_int (scalar_int_mode mode, rtx *x_ptr,
                             enum rtx_code in_code,
                             enum rtx_code *next_code_ptr)
 {
@@ -7965,8 +7976,8 @@ make_compound_operation_int (machine_mode mode, rtx *x_ptr,
          && (i = exact_log2 (UINTVAL (XEXP (x, 1)) + 1)) >= 0)
        {
          new_rtx = make_compound_operation (XEXP (XEXP (x, 0), 0), next_code);
-         new_rtx = make_extraction (mode, new_rtx, 0, XEXP (XEXP (x, 0), 1), i, 1,
-                                0, in_code == COMPARE);
+         new_rtx = make_extraction (mode, new_rtx, 0, XEXP (XEXP (x, 0), 1),
+                                    i, 1, 0, in_code == COMPARE);
        }
 
       /* Same as previous, but for (subreg (lshiftrt ...)) in first op.  */
@@ -8005,10 +8016,10 @@ make_compound_operation_int (machine_mode mode, rtx *x_ptr,
        {
          /* Apply the distributive law, and then try to make extractions.  */
          new_rtx = gen_rtx_fmt_ee (GET_CODE (XEXP (x, 0)), mode,
-                               gen_rtx_AND (mode, XEXP (XEXP (x, 0), 0),
-                                            XEXP (x, 1)),
-                               gen_rtx_AND (mode, XEXP (XEXP (x, 0), 1),
-                                            XEXP (x, 1)));
+                                   gen_rtx_AND (mode, XEXP (XEXP (x, 0), 0),
+                                                XEXP (x, 1)),
+                                   gen_rtx_AND (mode, XEXP (XEXP (x, 0), 1),
+                                                XEXP (x, 1)));
          new_rtx = make_compound_operation (new_rtx, in_code);
        }
 
@@ -8022,9 +8033,9 @@ make_compound_operation_int (machine_mode mode, rtx *x_ptr,
        {
          new_rtx = make_compound_operation (XEXP (XEXP (x, 0), 0), next_code);
          new_rtx = make_extraction (mode, new_rtx,
-                                (GET_MODE_PRECISION (mode)
-                                 - INTVAL (XEXP (XEXP (x, 0), 1))),
-                                NULL_RTX, i, 1, 0, in_code == COMPARE);
+                                    (GET_MODE_PRECISION (mode)
+                                     - INTVAL (XEXP (XEXP (x, 0), 1))),
+                                    NULL_RTX, i, 1, 0, in_code == COMPARE);
        }
 
       /* On machines without logical shifts, if the operand of the AND is
@@ -8044,8 +8055,10 @@ make_compound_operation_int (machine_mode mode, rtx *x_ptr,
          if ((INTVAL (XEXP (x, 1)) & ~mask) == 0)
            SUBST (XEXP (x, 0),
                   gen_rtx_ASHIFTRT (mode,
-                                    make_compound_operation
-                                    (XEXP (XEXP (x, 0), 0), next_code),
+                                    make_compound_operation (XEXP (XEXP (x,
+                                                                         0),
+                                                                   0),
+                                                             next_code),
                                     XEXP (XEXP (x, 0), 1)));
        }
 
@@ -8055,9 +8068,9 @@ make_compound_operation_int (machine_mode mode, rtx *x_ptr,
         we are in a COMPARE.  */
       else if ((i = exact_log2 (UINTVAL (XEXP (x, 1)) + 1)) >= 0)
        new_rtx = make_extraction (mode,
-                              make_compound_operation (XEXP (x, 0),
-                                                       next_code),
-                              0, NULL_RTX, i, 1, 0, in_code == COMPARE);
+                                  make_compound_operation (XEXP (x, 0),
+                                                           next_code),
+                                  0, NULL_RTX, i, 1, 0, in_code == COMPARE);
 
       /* If we are in a comparison and this is an AND with a power of two,
         convert this into the appropriate bit extract.  */
@@ -8108,9 +8121,9 @@ make_compound_operation_int (machine_mode mode, rtx *x_ptr,
          && (nonzero_bits (XEXP (x, 0), mode) & (1 << (mode_width - 1))) == 0)
        {
          new_rtx = gen_rtx_ASHIFTRT (mode,
-                                 make_compound_operation (XEXP (x, 0),
-                                                          next_code),
-                                 XEXP (x, 1));
+                                     make_compound_operation (XEXP (x, 0),
+                                                              next_code),
+                                     XEXP (x, 1));
          break;
        }
 
@@ -8131,9 +8144,9 @@ make_compound_operation_int (machine_mode mode, rtx *x_ptr,
        {
          new_rtx = make_compound_operation (XEXP (lhs, 0), next_code);
          new_rtx = make_extraction (mode, new_rtx,
-                                INTVAL (rhs) - INTVAL (XEXP (lhs, 1)),
-                                NULL_RTX, mode_width - INTVAL (rhs),
-                                code == LSHIFTRT, 0, in_code == COMPARE);
+                                    INTVAL (rhs) - INTVAL (XEXP (lhs, 1)),
+                                    NULL_RTX, mode_width - INTVAL (rhs),
+                                    code == LSHIFTRT, 0, in_code == COMPARE);
          break;
        }
 
@@ -8149,10 +8162,11 @@ make_compound_operation_int (machine_mode mode, rtx *x_ptr,
          && INTVAL (rhs) >= 0
          && INTVAL (rhs) < HOST_BITS_PER_WIDE_INT
          && INTVAL (rhs) < mode_width
-         && (new_rtx = extract_left_shift (lhs, INTVAL (rhs))) != 0)
-       new_rtx = make_extraction (mode, make_compound_operation (new_rtx, next_code),
-                              0, NULL_RTX, mode_width - INTVAL (rhs),
-                              code == LSHIFTRT, 0, in_code == COMPARE);
+         && (new_rtx = extract_left_shift (mode, lhs, INTVAL (rhs))) != 0)
+       new_rtx = make_extraction (mode, make_compound_operation (new_rtx,
+                                                                 next_code),
+                                  0, NULL_RTX, mode_width - INTVAL (rhs),
+                                  code == LSHIFTRT, 0, in_code == COMPARE);
 
       break;
 
@@ -8196,7 +8210,7 @@ make_compound_operation_int (machine_mode mode, rtx *x_ptr,
                   to (subreg:QI (lshiftrt:SI (reg:SI) (const_int 7)) 0).  */
                || (GET_CODE (inner) == AND
                    && CONST_INT_P (XEXP (inner, 1))
-                   && GET_MODE_SIZE (mode) < GET_MODE_SIZE (GET_MODE (inner))
+                   && partial_subreg_p (x)
                    && exact_log2 (UINTVAL (XEXP (inner, 1)))
                       >= GET_MODE_BITSIZE (mode) - 1)))
          subreg_code = SET;
@@ -8209,7 +8223,7 @@ make_compound_operation_int (machine_mode mode, rtx *x_ptr,
          tem = simplified;
 
        if (GET_CODE (tem) != GET_CODE (inner)
-           && GET_MODE_SIZE (mode) < GET_MODE_SIZE (GET_MODE (inner))
+           && partial_subreg_p (x)
            && subreg_lowpart_p (x))
          {
            rtx newer
@@ -8220,8 +8234,9 @@ make_compound_operation_int (machine_mode mode, rtx *x_ptr,
            if (GET_CODE (newer) != SUBREG)
              newer = make_compound_operation (newer, in_code);
 
-           /* force_to_mode can expand compounds.  If it just re-expanded the
-              compound, use gen_lowpart to convert to the desired mode.  */
+           /* force_to_mode can expand compounds.  If it just re-expanded
+              the compound, use gen_lowpart to convert to the desired
+              mode.  */
            if (rtx_equal_p (newer, x)
                /* Likewise if it re-expanded the compound only partially.
                   This happens for SUBREG of ZERO_EXTRACT if they extract
@@ -8463,7 +8478,7 @@ static rtx
 gen_lowpart_or_truncate (machine_mode mode, rtx x)
 {
   if (!CONST_INT_P (x)
-      && GET_MODE_SIZE (mode) < GET_MODE_SIZE (GET_MODE (x))
+      && partial_subreg_p (mode, GET_MODE (x))
       && !TRULY_NOOP_TRUNCATION_MODES_P (mode, GET_MODE (x))
       && !(REG_P (x) && reg_truncated_to_mode (mode, x)))
     {
@@ -8518,7 +8533,7 @@ force_to_mode (rtx x, machine_mode mode, unsigned HOST_WIDE_INT mask,
   /* It is not valid to do a right-shift in a narrower mode
      than the one it came in with.  */
   if ((code == LSHIFTRT || code == ASHIFTRT)
-      && GET_MODE_PRECISION (mode) < GET_MODE_PRECISION (GET_MODE (x)))
+      && partial_subreg_p (mode, GET_MODE (x)))
     op_mode = GET_MODE (x);
 
   /* Truncate MASK to fit OP_MODE.  */
@@ -8555,8 +8570,7 @@ force_to_mode (rtx x, machine_mode mode, unsigned HOST_WIDE_INT mask,
      if the constant masks to zero all the bits the mode doesn't have.  */
   if (GET_CODE (x) == SUBREG
       && subreg_lowpart_p (x)
-      && ((GET_MODE_SIZE (GET_MODE (x))
-          < GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))))
+      && (partial_subreg_p (x)
          || (0 == (mask
                    & GET_MODE_MASK (GET_MODE (x))
                    & ~GET_MODE_MASK (GET_MODE (SUBREG_REG (x)))))))
@@ -9550,8 +9564,7 @@ make_field_assignment (rtx x)
 
   if (GET_CODE (src) == AND && GET_CODE (XEXP (src, 0)) == SUBREG
       && subreg_lowpart_p (XEXP (src, 0))
-      && (GET_MODE_SIZE (GET_MODE (XEXP (src, 0)))
-         < GET_MODE_SIZE (GET_MODE (SUBREG_REG (XEXP (src, 0)))))
+      && partial_subreg_p (XEXP (src, 0))
       && GET_CODE (SUBREG_REG (XEXP (src, 0))) == ROTATE
       && CONST_INT_P (XEXP (SUBREG_REG (XEXP (src, 0)), 0))
       && INTVAL (XEXP (SUBREG_REG (XEXP (src, 0)), 0)) == -2
@@ -9905,7 +9918,7 @@ distribute_and_simplify_rtx (rtx x, int n)
    (const_int CONSTOP)).  Otherwise, return NULL_RTX.  */
 
 static rtx
-simplify_and_const_int_1 (machine_mode mode, rtx varop,
+simplify_and_const_int_1 (scalar_int_mode mode, rtx varop,
                          unsigned HOST_WIDE_INT constop)
 {
   unsigned HOST_WIDE_INT nonzero;
@@ -9965,19 +9978,20 @@ simplify_and_const_int_1 (machine_mode mode, rtx varop,
      won't match a pattern either with or without this.  */
 
   if (GET_CODE (varop) == IOR || GET_CODE (varop) == XOR)
-    return
-      gen_lowpart
-       (mode,
-        apply_distributive_law
-        (simplify_gen_binary (GET_CODE (varop), GET_MODE (varop),
-                              simplify_and_const_int (NULL_RTX,
-                                                      GET_MODE (varop),
-                                                      XEXP (varop, 0),
-                                                      constop),
-                              simplify_and_const_int (NULL_RTX,
-                                                      GET_MODE (varop),
-                                                      XEXP (varop, 1),
-                                                      constop))));
+    {
+      scalar_int_mode varop_mode = as_a <scalar_int_mode> (GET_MODE (varop));
+      return
+       gen_lowpart
+         (mode,
+          apply_distributive_law
+          (simplify_gen_binary (GET_CODE (varop), varop_mode,
+                                simplify_and_const_int (NULL_RTX, varop_mode,
+                                                        XEXP (varop, 0),
+                                                        constop),
+                                simplify_and_const_int (NULL_RTX, varop_mode,
+                                                        XEXP (varop, 1),
+                                                        constop))));
+    }
 
   /* If VAROP is PLUS, and the constant is a mask of low bits, distribute
      the AND and see if one of the operands simplifies to zero.  If so, we
@@ -10020,7 +10034,7 @@ simplify_and_const_int_1 (machine_mode mode, rtx varop,
    X is zero, we are to always construct the equivalent form.  */
 
 static rtx
-simplify_and_const_int (rtx x, machine_mode mode, rtx varop,
+simplify_and_const_int (rtx x, scalar_int_mode mode, rtx varop,
                        unsigned HOST_WIDE_INT constop)
 {
   rtx tem = simplify_and_const_int_1 (mode, varop, constop);
@@ -10035,17 +10049,15 @@ simplify_and_const_int (rtx x, machine_mode mode, rtx varop,
   return x;
 }
 \f
-/* Given a REG, X, compute which bits in X can be nonzero.
+/* Given a REG X of mode XMODE, compute which bits in X can be nonzero.
    We don't care about bits outside of those defined in MODE.
 
    For most X this is simply GET_MODE_MASK (GET_MODE (MODE)), but if X is
    a shift, AND, or zero_extract, we can do better.  */
 
 static rtx
-reg_nonzero_bits_for_combine (const_rtx x, machine_mode mode,
-                             const_rtx known_x ATTRIBUTE_UNUSED,
-                             machine_mode known_mode ATTRIBUTE_UNUSED,
-                             unsigned HOST_WIDE_INT known_ret ATTRIBUTE_UNUSED,
+reg_nonzero_bits_for_combine (const_rtx x, scalar_int_mode xmode,
+                             scalar_int_mode mode,
                              unsigned HOST_WIDE_INT *nonzero)
 {
   rtx tem;
@@ -10086,8 +10098,7 @@ reg_nonzero_bits_for_combine (const_rtx x, machine_mode mode,
   if (tem)
     {
       if (SHORT_IMMEDIATES_SIGN_EXTEND)
-       tem = sign_extend_short_imm (tem, GET_MODE (x),
-                                    GET_MODE_PRECISION (mode));
+       tem = sign_extend_short_imm (tem, xmode, GET_MODE_PRECISION (mode));
 
       return tem;
     }
@@ -10096,9 +10107,9 @@ reg_nonzero_bits_for_combine (const_rtx x, machine_mode mode,
     {
       unsigned HOST_WIDE_INT mask = rsp->nonzero_bits;
 
-      if (GET_MODE_PRECISION (GET_MODE (x)) < GET_MODE_PRECISION (mode))
+      if (GET_MODE_PRECISION (xmode) < GET_MODE_PRECISION (mode))
        /* We don't know anything about the upper bits.  */
-       mask |= GET_MODE_MASK (mode) ^ GET_MODE_MASK (GET_MODE (x));
+       mask |= GET_MODE_MASK (mode) ^ GET_MODE_MASK (xmode);
 
       *nonzero &= mask;
     }
@@ -10106,17 +10117,14 @@ reg_nonzero_bits_for_combine (const_rtx x, machine_mode mode,
   return NULL;
 }
 
-/* Return the number of bits at the high-order end of X that are known to
-   be equal to the sign bit.  X will be used in mode MODE; if MODE is
-   VOIDmode, X will be used in its own mode.  The returned value  will always
-   be between 1 and the number of bits in MODE.  */
+/* Given a reg X of mode XMODE, return the number of bits at the high-order
+   end of X that are known to be equal to the sign bit.  X will be used
+   in mode MODE; the returned value will always be between 1 and the
+   number of bits in MODE.  */
 
 static rtx
-reg_num_sign_bit_copies_for_combine (const_rtx x, machine_mode mode,
-                                    const_rtx known_x ATTRIBUTE_UNUSED,
-                                    machine_mode known_mode
-                                    ATTRIBUTE_UNUSED,
-                                    unsigned int known_ret ATTRIBUTE_UNUSED,
+reg_num_sign_bit_copies_for_combine (const_rtx x, scalar_int_mode xmode,
+                                    scalar_int_mode mode,
                                     unsigned int *result)
 {
   rtx tem;
@@ -10145,7 +10153,7 @@ reg_num_sign_bit_copies_for_combine (const_rtx x, machine_mode mode,
     return tem;
 
   if (nonzero_sign_valid && rsp->sign_bit_copies != 0
-      && GET_MODE_PRECISION (GET_MODE (x)) == GET_MODE_PRECISION (mode))
+      && GET_MODE_PRECISION (xmode) == GET_MODE_PRECISION (mode))
     *result = rsp->sign_bit_copies;
 
   return NULL;
@@ -10316,9 +10324,9 @@ merge_outer_ops (enum rtx_code *pop0, HOST_WIDE_INT *pconst0, enum rtx_code op1,
    result of the shift is subject to operation OUTER_CODE with operand
    OUTER_CONST.  */
 
-static machine_mode
+static scalar_int_mode
 try_widen_shift_mode (enum rtx_code code, rtx op, int count,
-                     machine_mode orig_mode, machine_mode mode,
+                     scalar_int_mode orig_mode, scalar_int_mode mode,
                      enum rtx_code outer_code, HOST_WIDE_INT outer_const)
 {
   gcc_assert (GET_MODE_PRECISION (mode) > GET_MODE_PRECISION (orig_mode));
@@ -13325,7 +13333,7 @@ reg_truncated_to_mode (machine_mode mode, const_rtx x)
   if (truncated == 0
       || rsp->truncation_label < label_tick_ebb_start)
     return false;
-  if (GET_MODE_SIZE (truncated) <= GET_MODE_SIZE (mode))
+  if (!partial_subreg_p (mode, truncated))
     return true;
   if (TRULY_NOOP_TRUNCATION_MODES_P (mode, truncated))
     return true;
@@ -13348,9 +13356,10 @@ record_truncated_value (rtx x)
       machine_mode original_mode = GET_MODE (SUBREG_REG (x));
       truncated_mode = GET_MODE (x);
 
-      if (GET_MODE_SIZE (original_mode) <= GET_MODE_SIZE (truncated_mode))
+      if (!partial_subreg_p (truncated_mode, original_mode))
        return true;
 
+      truncated_mode = GET_MODE (x);
       if (TRULY_NOOP_TRUNCATION_MODES_P (truncated_mode, original_mode))
        return true;
 
@@ -13366,8 +13375,7 @@ record_truncated_value (rtx x)
   rsp = &reg_stat[REGNO (x)];
   if (rsp->truncated_to_mode == 0
       || rsp->truncation_label < label_tick_ebb_start
-      || (GET_MODE_SIZE (truncated_mode)
-         < GET_MODE_SIZE (rsp->truncated_to_mode)))
+      || partial_subreg_p (truncated_mode, rsp->truncated_to_mode))
     {
       rsp->truncated_to_mode = truncated_mode;
       rsp->truncation_label = label_tick;
@@ -13891,8 +13899,7 @@ move_deaths (rtx x, rtx maybe_kill_insn, int from_luid, rtx_insn *to_insn,
             the remaining registers in place of NOTE.  */
 
          if (note != 0 && regno < FIRST_PSEUDO_REGISTER
-             && (GET_MODE_SIZE (GET_MODE (XEXP (note, 0)))
-                 > GET_MODE_SIZE (GET_MODE (x))))
+             && partial_subreg_p (GET_MODE (x), GET_MODE (XEXP (note, 0))))
            {
              unsigned int deadregno = REGNO (XEXP (note, 0));
              unsigned int deadend = END_REGNO (XEXP (note, 0));
@@ -13911,8 +13918,8 @@ move_deaths (rtx x, rtx maybe_kill_insn, int from_luid, rtx_insn *to_insn,
             their own REG_DEAD notes lying around.  */
          else if ((note == 0
                    || (note != 0
-                       && (GET_MODE_SIZE (GET_MODE (XEXP (note, 0)))
-                           < GET_MODE_SIZE (GET_MODE (x)))))
+                       && partial_subreg_p (GET_MODE (XEXP (note, 0)),
+                                            GET_MODE (x))))
                   && regno < FIRST_PSEUDO_REGISTER
                   && REG_NREGS (x) > 1)
            {
@@ -13921,7 +13928,7 @@ move_deaths (rtx x, rtx maybe_kill_insn, int from_luid, rtx_insn *to_insn,
              rtx oldnotes = 0;
 
              if (note)
-               offset = hard_regno_nregs[regno][GET_MODE (XEXP (note, 0))];
+               offset = hard_regno_nregs (regno, GET_MODE (XEXP (note, 0)));
              else
                offset = 1;
 
@@ -14533,7 +14540,7 @@ distribute_notes (rtx notes, rtx_insn *from_insn, rtx_insn *i3, rtx_insn *i2,
                         not already dead or set.  */
 
                      for (i = regno; i < endregno;
-                          i += hard_regno_nregs[i][reg_raw_mode[i]])
+                          i += hard_regno_nregs (i, reg_raw_mode[i]))
                        {
                          rtx piece = regno_reg_rtx[i];
                          basic_block bb = this_basic_block;