c++: Fix guard variable and attribute weak.
[gcc.git] / gcc / cse.c
index 8b9e4a116ac6c3b54435aeaa9213caec2b8172c2..79ee0ce80e3dd68a450cb2f493f79b19f098f4fa 100644 (file)
--- a/gcc/cse.c
+++ b/gcc/cse.c
@@ -1,5 +1,5 @@
 /* Common subexpression elimination for GNU compiler.
-   Copyright (C) 1987-2016 Free Software Foundation, Inc.
+   Copyright (C) 1987-2020 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -37,15 +37,12 @@ along with GCC; see the file COPYING3.  If not see
 #include "cfgcleanup.h"
 #include "alias.h"
 #include "toplev.h"
-#include "params.h"
 #include "rtlhooks-def.h"
 #include "tree-pass.h"
 #include "dbgcnt.h"
 #include "rtl-iter.h"
-
-#ifndef LOAD_EXTEND_OP
-#define LOAD_EXTEND_OP(M) UNKNOWN
-#endif
+#include "regs.h"
+#include "function-abi.h"
 
 /* The basic idea of common subexpression elimination is to go
    through the code, keeping a record of expressions that would
@@ -565,11 +562,10 @@ static struct table_elt *insert (rtx, struct table_elt *, unsigned,
 static void merge_equiv_classes (struct table_elt *, struct table_elt *);
 static void invalidate (rtx, machine_mode);
 static void remove_invalid_refs (unsigned int);
-static void remove_invalid_subreg_refs (unsigned int, unsigned int,
+static void remove_invalid_subreg_refs (unsigned int, poly_uint64,
                                        machine_mode);
 static void rehash_using_reg (rtx);
 static void invalidate_memory (void);
-static void invalidate_for_call (void);
 static rtx use_related_value (rtx, struct table_elt *);
 
 static inline unsigned canon_hash (rtx, machine_mode);
@@ -724,13 +720,14 @@ preferable (int cost_a, int regcost_a, int cost_b, int regcost_b)
 static int
 notreg_cost (rtx x, machine_mode mode, enum rtx_code outer, int opno)
 {
+  scalar_int_mode int_mode, inner_mode;
   return ((GET_CODE (x) == SUBREG
           && REG_P (SUBREG_REG (x))
-          && GET_MODE_CLASS (mode) == MODE_INT
-          && GET_MODE_CLASS (GET_MODE (SUBREG_REG (x))) == MODE_INT
-          && GET_MODE_SIZE (mode) < GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))
+          && is_int_mode (mode, &int_mode)
+          && is_int_mode (GET_MODE (SUBREG_REG (x)), &inner_mode)
+          && GET_MODE_SIZE (int_mode) < GET_MODE_SIZE (inner_mode)
           && subreg_lowpart_p (x)
-          && TRULY_NOOP_TRUNCATION_MODES_P (mode, GET_MODE (SUBREG_REG (x))))
+          && TRULY_NOOP_TRUNCATION_MODES_P (int_mode, inner_mode))
          ? 0
          : rtx_cost (x, mode, outer, opno, optimize_this_for_speed_p) * 2);
 }
@@ -1821,7 +1818,72 @@ check_dependence (const_rtx x, rtx exp, machine_mode mode, rtx addr)
     }
   return false;
 }
-\f
+
+/* Remove from the hash table, or mark as invalid, all expressions whose
+   values could be altered by storing in register X.  */
+
+static void
+invalidate_reg (rtx x)
+{
+  gcc_assert (GET_CODE (x) == REG);
+
+  /* If X is a register, dependencies on its contents are recorded
+     through the qty number mechanism.  Just change the qty number of
+     the register, mark it as invalid for expressions that refer to it,
+     and remove it itself.  */
+  unsigned int regno = REGNO (x);
+  unsigned int hash = HASH (x, GET_MODE (x));
+
+  /* Remove REGNO from any quantity list it might be on and indicate
+     that its value might have changed.  If it is a pseudo, remove its
+     entry from the hash table.
+
+     For a hard register, we do the first two actions above for any
+     additional hard registers corresponding to X.  Then, if any of these
+     registers are in the table, we must remove any REG entries that
+     overlap these registers.  */
+
+  delete_reg_equiv (regno);
+  REG_TICK (regno)++;
+  SUBREG_TICKED (regno) = -1;
+
+  if (regno >= FIRST_PSEUDO_REGISTER)
+    remove_pseudo_from_table (x, hash);
+  else
+    {
+      HOST_WIDE_INT in_table = TEST_HARD_REG_BIT (hard_regs_in_table, regno);
+      unsigned int endregno = END_REGNO (x);
+      unsigned int rn;
+      struct table_elt *p, *next;
+
+      CLEAR_HARD_REG_BIT (hard_regs_in_table, regno);
+
+      for (rn = regno + 1; rn < endregno; rn++)
+       {
+         in_table |= TEST_HARD_REG_BIT (hard_regs_in_table, rn);
+         CLEAR_HARD_REG_BIT (hard_regs_in_table, rn);
+         delete_reg_equiv (rn);
+         REG_TICK (rn)++;
+         SUBREG_TICKED (rn) = -1;
+       }
+
+      if (in_table)
+       for (hash = 0; hash < HASH_SIZE; hash++)
+         for (p = table[hash]; p; p = next)
+           {
+             next = p->next_same_hash;
+
+             if (!REG_P (p->exp) || REGNO (p->exp) >= FIRST_PSEUDO_REGISTER)
+               continue;
+
+             unsigned int tregno = REGNO (p->exp);
+             unsigned int tendregno = END_REGNO (p->exp);
+             if (tendregno > regno && tregno < endregno)
+               remove_from_table (p, hash);
+           }
+    }
+}
+
 /* Remove from the hash table, or mark as invalid, all expressions whose
    values could be altered by storing in X.  X is a register, a subreg, or
    a memory reference with nonvarying address (because, when a memory
@@ -1844,65 +1906,7 @@ invalidate (rtx x, machine_mode full_mode)
   switch (GET_CODE (x))
     {
     case REG:
-      {
-       /* If X is a register, dependencies on its contents are recorded
-          through the qty number mechanism.  Just change the qty number of
-          the register, mark it as invalid for expressions that refer to it,
-          and remove it itself.  */
-       unsigned int regno = REGNO (x);
-       unsigned int hash = HASH (x, GET_MODE (x));
-
-       /* Remove REGNO from any quantity list it might be on and indicate
-          that its value might have changed.  If it is a pseudo, remove its
-          entry from the hash table.
-
-          For a hard register, we do the first two actions above for any
-          additional hard registers corresponding to X.  Then, if any of these
-          registers are in the table, we must remove any REG entries that
-          overlap these registers.  */
-
-       delete_reg_equiv (regno);
-       REG_TICK (regno)++;
-       SUBREG_TICKED (regno) = -1;
-
-       if (regno >= FIRST_PSEUDO_REGISTER)
-         remove_pseudo_from_table (x, hash);
-       else
-         {
-           HOST_WIDE_INT in_table
-             = TEST_HARD_REG_BIT (hard_regs_in_table, regno);
-           unsigned int endregno = END_REGNO (x);
-           unsigned int tregno, tendregno, rn;
-           struct table_elt *p, *next;
-
-           CLEAR_HARD_REG_BIT (hard_regs_in_table, regno);
-
-           for (rn = regno + 1; rn < endregno; rn++)
-             {
-               in_table |= TEST_HARD_REG_BIT (hard_regs_in_table, rn);
-               CLEAR_HARD_REG_BIT (hard_regs_in_table, rn);
-               delete_reg_equiv (rn);
-               REG_TICK (rn)++;
-               SUBREG_TICKED (rn) = -1;
-             }
-
-           if (in_table)
-             for (hash = 0; hash < HASH_SIZE; hash++)
-               for (p = table[hash]; p; p = next)
-                 {
-                   next = p->next_same_hash;
-
-                   if (!REG_P (p->exp)
-                       || REGNO (p->exp) >= FIRST_PSEUDO_REGISTER)
-                     continue;
-
-                   tregno = REGNO (p->exp);
-                   tendregno = END_REGNO (p->exp);
-                   if (tendregno > regno && tregno < endregno)
-                     remove_from_table (p, hash);
-                 }
-         }
-      }
+      invalidate_reg (x);
       return;
 
     case SUBREG:
@@ -1997,12 +2001,11 @@ remove_invalid_refs (unsigned int regno)
 /* Likewise for a subreg with subreg_reg REGNO, subreg_byte OFFSET,
    and mode MODE.  */
 static void
-remove_invalid_subreg_refs (unsigned int regno, unsigned int offset,
+remove_invalid_subreg_refs (unsigned int regno, poly_uint64 offset,
                            machine_mode mode)
 {
   unsigned int i;
   struct table_elt *p, *next;
-  unsigned int end = offset + (GET_MODE_SIZE (mode) - 1);
 
   for (i = 0; i < HASH_SIZE; i++)
     for (p = table[i]; p; p = next)
@@ -2014,9 +2017,9 @@ remove_invalid_subreg_refs (unsigned int regno, unsigned int offset,
            && (GET_CODE (exp) != SUBREG
                || !REG_P (SUBREG_REG (exp))
                || REGNO (SUBREG_REG (exp)) != regno
-               || (((SUBREG_BYTE (exp)
-                     + (GET_MODE_SIZE (GET_MODE (exp)) - 1)) >= offset)
-                   && SUBREG_BYTE (exp) <= end))
+               || ranges_maybe_overlap_p (SUBREG_BYTE (exp),
+                                          GET_MODE_SIZE (GET_MODE (exp)),
+                                          offset, GET_MODE_SIZE (mode)))
            && refers_to_regno_p (regno, p->exp))
          remove_from_table (p, i);
       }
@@ -2074,23 +2077,31 @@ rehash_using_reg (rtx x)
 }
 \f
 /* Remove from the hash table any expression that is a call-clobbered
-   register.  Also update their TICK values.  */
+   register in INSN.  Also update their TICK values.  */
 
 static void
-invalidate_for_call (void)
+invalidate_for_call (rtx_insn *insn)
 {
-  unsigned int regno, endregno;
-  unsigned int i;
+  unsigned int regno;
   unsigned hash;
   struct table_elt *p, *next;
   int in_table = 0;
   hard_reg_set_iterator hrsi;
 
-  /* Go through all the hard registers.  For each that is clobbered in
-     a CALL_INSN, remove the register from quantity chains and update
+  /* Go through all the hard registers.  For each that might be clobbered
+     in call insn INSN, remove the register from quantity chains and update
      reg_tick if defined.  Also see if any of these registers is currently
-     in the table.  */
-  EXECUTE_IF_SET_IN_HARD_REG_SET (regs_invalidated_by_call, 0, regno, hrsi)
+     in the table.
+
+     ??? We could be more precise for partially-clobbered registers,
+     and only invalidate values that actually occupy the clobbered part
+     of the registers.  It doesn't seem worth the effort though, since
+     we shouldn't see this situation much before RA.  Whatever choice
+     we make here has to be consistent with the table walk below,
+     so any change to this test will require a change there too.  */
+  HARD_REG_SET callee_clobbers
+    = insn_callee_abi (insn).full_and_partial_reg_clobbers ();
+  EXECUTE_IF_SET_IN_HARD_REG_SET (callee_clobbers, 0, regno, hrsi)
     {
       delete_reg_equiv (regno);
       if (REG_TICK (regno) >= 0)
@@ -2115,15 +2126,11 @@ invalidate_for_call (void)
              || REGNO (p->exp) >= FIRST_PSEUDO_REGISTER)
            continue;
 
-         regno = REGNO (p->exp);
-         endregno = END_REGNO (p->exp);
-
-         for (i = regno; i < endregno; i++)
-           if (TEST_HARD_REG_BIT (regs_invalidated_by_call, i))
-             {
-               remove_from_table (p, hash);
-               break;
-             }
+         /* This must use the same test as above rather than the
+            more accurate clobbers_reg_p.  */
+         if (overlaps_hard_reg_set_p (callee_clobbers, GET_MODE (p->exp),
+                                      REGNO (p->exp)))
+           remove_from_table (p, hash);
        }
 }
 \f
@@ -2310,7 +2317,8 @@ hash_rtx_cb (const_rtx x, machine_mode mode,
          {
            hash += (((unsigned int) SUBREG << 7)
                     + REGNO (SUBREG_REG (x))
-                    + (SUBREG_BYTE (x) / UNITS_PER_WORD));
+                    + (constant_lower_bound (SUBREG_BYTE (x))
+                       / UNITS_PER_WORD));
            return hash;
          }
        break;
@@ -2326,6 +2334,15 @@ hash_rtx_cb (const_rtx x, machine_mode mode,
        hash += CONST_WIDE_INT_ELT (x, i);
       return hash;
 
+    case CONST_POLY_INT:
+      {
+       inchash::hash h;
+       h.add_int (hash);
+       for (unsigned int i = 0; i < NUM_POLY_INT_COEFFS; ++i)
+         h.add_wide_int (CONST_POLY_INT_COEFFS (x)[i]);
+       return h.end ();
+      }
+
     case CONST_DOUBLE:
       /* This is like the general case, except that it only counts
         the integers representing the constant.  */
@@ -2347,11 +2364,11 @@ hash_rtx_cb (const_rtx x, machine_mode mode,
        int units;
        rtx elt;
 
-       units = CONST_VECTOR_NUNITS (x);
+       units = const_vector_encoded_nelts (x);
 
        for (i = 0; i < units; ++i)
          {
-           elt = CONST_VECTOR_ELT (x, i);
+           elt = CONST_VECTOR_ENCODED_ELT (x, i);
            hash += hash_rtx_cb (elt, GET_MODE (elt),
                                  do_not_record_p, hash_arg_in_memory_p,
                                  have_reg_qty, cb);
@@ -2365,7 +2382,7 @@ hash_rtx_cb (const_rtx x, machine_mode mode,
       /* We don't hash on the address of the CODE_LABEL to avoid bootstrap
         differences and differences between each stage's debugging dumps.  */
         hash += (((unsigned int) LABEL_REF << 7)
-                 + CODE_LABEL_NUMBER (LABEL_REF_LABEL (x)));
+                 + CODE_LABEL_NUMBER (label_ref_label (x)));
       return hash;
 
     case SYMBOL_REF:
@@ -2520,6 +2537,10 @@ hash_rtx_cb (const_rtx x, machine_mode mode,
          hash += (unsigned int) XINT (x, i);
          break;
 
+       case 'p':
+         hash += constant_lower_bound (SUBREG_BYTE (x));
+         break;
+
        case '0': case 't':
          /* Unused.  */
          break;
@@ -2618,7 +2639,7 @@ exp_equiv_p (const_rtx x, const_rtx y, int validate, bool for_gcse)
       return x == y;
 
     case LABEL_REF:
-      return LABEL_REF_LABEL (x) == LABEL_REF_LABEL (y);
+      return label_ref_label (x) == label_ref_label (y);
 
     case SYMBOL_REF:
       return XSTR (x, 0) == XSTR (y, 0);
@@ -2770,6 +2791,11 @@ exp_equiv_p (const_rtx x, const_rtx y, int validate, bool for_gcse)
            return 0;
          break;
 
+       case 'p':
+         if (maybe_ne (SUBREG_BYTE (x), SUBREG_BYTE (y)))
+           return 0;
+         break;
+
        case '0':
        case 't':
          break;
@@ -3097,6 +3123,7 @@ fold_rtx (rtx x, rtx_insn *insn)
   int i;
   rtx new_rtx = 0;
   int changed = 0;
+  poly_int64 xval;
 
   /* Operands of X.  */
   /* Workaround -Wmaybe-uninitialized false positive during
@@ -3507,7 +3534,7 @@ fold_rtx (rtx x, rtx_insn *insn)
                : lookup_as_function (folded_arg0, MINUS);
 
              if (y != 0 && GET_CODE (XEXP (y, 1)) == LABEL_REF
-                 && LABEL_REF_LABEL (XEXP (y, 1)) == LABEL_REF_LABEL (const_arg1))
+                 && label_ref_label (XEXP (y, 1)) == label_ref_label (const_arg1))
                return XEXP (y, 0);
 
              /* Now try for a CONST of a MINUS like the above.  */
@@ -3515,7 +3542,7 @@ fold_rtx (rtx x, rtx_insn *insn)
                        : lookup_as_function (folded_arg0, CONST))) != 0
                  && GET_CODE (XEXP (y, 0)) == MINUS
                  && GET_CODE (XEXP (XEXP (y, 0), 1)) == LABEL_REF
-                 && LABEL_REF_LABEL (XEXP (XEXP (y, 0), 1)) == LABEL_REF_LABEL (const_arg1))
+                 && label_ref_label (XEXP (XEXP (y, 0), 1)) == label_ref_label (const_arg1))
                return XEXP (XEXP (y, 0), 0);
            }
 
@@ -3527,7 +3554,7 @@ fold_rtx (rtx x, rtx_insn *insn)
                : lookup_as_function (folded_arg1, MINUS);
 
              if (y != 0 && GET_CODE (XEXP (y, 1)) == LABEL_REF
-                 && LABEL_REF_LABEL (XEXP (y, 1)) == LABEL_REF_LABEL (const_arg0))
+                 && label_ref_label (XEXP (y, 1)) == label_ref_label (const_arg0))
                return XEXP (y, 0);
 
              /* Now try for a CONST of a MINUS like the above.  */
@@ -3535,7 +3562,7 @@ fold_rtx (rtx x, rtx_insn *insn)
                        : lookup_as_function (folded_arg1, CONST))) != 0
                  && GET_CODE (XEXP (y, 0)) == MINUS
                  && GET_CODE (XEXP (XEXP (y, 0), 1)) == LABEL_REF
-                 && LABEL_REF_LABEL (XEXP (XEXP (y, 0), 1)) == LABEL_REF_LABEL (const_arg0))
+                 && label_ref_label (XEXP (XEXP (y, 0), 1)) == label_ref_label (const_arg0))
                return XEXP (XEXP (y, 0), 0);
            }
 
@@ -3577,12 +3604,11 @@ fold_rtx (rtx x, rtx_insn *insn)
        case MINUS:
          /* If we have (MINUS Y C), see if Y is known to be (PLUS Z C2).
             If so, produce (PLUS Z C2-C).  */
-         if (const_arg1 != 0 && CONST_INT_P (const_arg1))
+         if (const_arg1 != 0 && poly_int_rtx_p (const_arg1, &xval))
            {
              rtx y = lookup_as_function (XEXP (x, 0), PLUS);
-             if (y && CONST_INT_P (XEXP (y, 1)))
-               return fold_rtx (plus_constant (mode, copy_rtx (y),
-                                               -INTVAL (const_arg1)),
+             if (y && poly_int_rtx_p (XEXP (y, 1)))
+               return fold_rtx (plus_constant (mode, copy_rtx (y), -xval),
                                 NULL);
            }
 
@@ -3610,13 +3636,13 @@ fold_rtx (rtx x, rtx_insn *insn)
              enum rtx_code associate_code;
 
              if (is_shift
-                 && (INTVAL (const_arg1) >= GET_MODE_PRECISION (mode)
+                 && (INTVAL (const_arg1) >= GET_MODE_UNIT_PRECISION (mode)
                      || INTVAL (const_arg1) < 0))
                {
                  if (SHIFT_COUNT_TRUNCATED)
-                   canon_const_arg1 = GEN_INT (INTVAL (const_arg1)
-                                               & (GET_MODE_BITSIZE (mode)
-                                                  - 1));
+                   canon_const_arg1 = gen_int_shift_amount
+                     (mode, (INTVAL (const_arg1)
+                             & (GET_MODE_UNIT_BITSIZE (mode) - 1)));
                  else
                    break;
                }
@@ -3659,12 +3685,13 @@ fold_rtx (rtx x, rtx_insn *insn)
                 break;
 
              if (is_shift
-                 && (INTVAL (inner_const) >= GET_MODE_PRECISION (mode)
+                 && (INTVAL (inner_const) >= GET_MODE_UNIT_PRECISION (mode)
                      || INTVAL (inner_const) < 0))
                {
                  if (SHIFT_COUNT_TRUNCATED)
-                   inner_const = GEN_INT (INTVAL (inner_const)
-                                          & (GET_MODE_BITSIZE (mode) - 1));
+                   inner_const = gen_int_shift_amount
+                     (mode, (INTVAL (inner_const)
+                             & (GET_MODE_UNIT_BITSIZE (mode) - 1)));
                  else
                    break;
                }
@@ -3689,12 +3716,13 @@ fold_rtx (rtx x, rtx_insn *insn)
 
              if (is_shift
                  && CONST_INT_P (new_const)
-                 && INTVAL (new_const) >= GET_MODE_PRECISION (mode))
+                 && INTVAL (new_const) >= GET_MODE_UNIT_PRECISION (mode))
                {
                  /* As an exception, we can turn an ASHIFTRT of this
                     form into a shift of the number of bits - 1.  */
                  if (code == ASHIFTRT)
-                   new_const = GEN_INT (GET_MODE_BITSIZE (mode) - 1);
+                   new_const = gen_int_shift_amount
+                     (mode, GET_MODE_UNIT_BITSIZE (mode) - 1);
                  else if (!side_effects_p (XEXP (y, 0)))
                    return CONST0_RTX (mode);
                  else
@@ -3782,17 +3810,20 @@ equiv_constant (rtx x)
       /* See if we previously assigned a constant value to this SUBREG.  */
       if ((new_rtx = lookup_as_function (x, CONST_INT)) != 0
          || (new_rtx = lookup_as_function (x, CONST_WIDE_INT)) != 0
+         || (NUM_POLY_INT_COEFFS > 1
+             && (new_rtx = lookup_as_function (x, CONST_POLY_INT)) != 0)
           || (new_rtx = lookup_as_function (x, CONST_DOUBLE)) != 0
           || (new_rtx = lookup_as_function (x, CONST_FIXED)) != 0)
         return new_rtx;
 
       /* If we didn't and if doing so makes sense, see if we previously
         assigned a constant value to the enclosing word mode SUBREG.  */
-      if (GET_MODE_SIZE (mode) < GET_MODE_SIZE (word_mode)
-         && GET_MODE_SIZE (word_mode) < GET_MODE_SIZE (imode))
+      if (known_lt (GET_MODE_SIZE (mode), UNITS_PER_WORD)
+         && known_lt (UNITS_PER_WORD, GET_MODE_SIZE (imode)))
        {
-         int byte = SUBREG_BYTE (x) - subreg_lowpart_offset (mode, word_mode);
-         if (byte >= 0 && (byte % UNITS_PER_WORD) == 0)
+         poly_int64 byte = (SUBREG_BYTE (x)
+                            - subreg_lowpart_offset (mode, word_mode));
+         if (known_ge (byte, 0) && multiple_p (byte, UNITS_PER_WORD))
            {
              rtx y = gen_rtx_SUBREG (word_mode, SUBREG_REG (x), byte);
              new_rtx = lookup_as_function (y, CONST_INT);
@@ -3806,7 +3837,7 @@ equiv_constant (rtx x)
         the subreg.  Note that the upper bits of paradoxical subregs
         are undefined, so they cannot be said to equal anything.  */
       if (REG_P (SUBREG_REG (x))
-         && GET_MODE_SIZE (mode) <= GET_MODE_SIZE (imode)
+         && !paradoxical_subreg_p (x)
          && (new_rtx = equiv_constant (SUBREG_REG (x))) != 0)
         return simplify_subreg (mode, new_rtx, imode, SUBREG_BYTE (x));
 
@@ -3956,10 +3987,9 @@ record_jump_cond (enum rtx_code code, machine_mode mode, rtx op0,
      if we test MODE instead, we can get an infinite recursion
      alternating between two modes each wider than MODE.  */
 
-  if (code == NE && GET_CODE (op0) == SUBREG
-      && subreg_lowpart_p (op0)
-      && (GET_MODE_SIZE (GET_MODE (op0))
-         < GET_MODE_SIZE (GET_MODE (SUBREG_REG (op0)))))
+  if (code == NE
+      && partial_subreg_p (op0)
+      && subreg_lowpart_p (op0))
     {
       machine_mode inner_mode = GET_MODE (SUBREG_REG (op0));
       rtx tem = record_jump_cond_subreg (inner_mode, op1);
@@ -3968,10 +3998,9 @@ record_jump_cond (enum rtx_code code, machine_mode mode, rtx op0,
                          reversed_nonequality);
     }
 
-  if (code == NE && GET_CODE (op1) == SUBREG
-      && subreg_lowpart_p (op1)
-      && (GET_MODE_SIZE (GET_MODE (op1))
-         < GET_MODE_SIZE (GET_MODE (SUBREG_REG (op1)))))
+  if (code == NE
+      && partial_subreg_p (op1)
+      && subreg_lowpart_p (op1))
     {
       machine_mode inner_mode = GET_MODE (SUBREG_REG (op1));
       rtx tem = record_jump_cond_subreg (inner_mode, op0);
@@ -4158,10 +4187,10 @@ struct set
      The size of this field should match the size of the mode
      field of struct rtx_def (see rtl.h).  */
   ENUM_BITFIELD(machine_mode) mode : 8;
-  /* A constant equivalent for SET_SRC, if any.  */
-  rtx src_const;
   /* Hash value of constant equivalent for SET_SRC.  */
   unsigned src_const_hash;
+  /* A constant equivalent for SET_SRC, if any.  */
+  rtx src_const;
   /* Table entry for constant equivalent for SET_SRC, if any.  */
   struct table_elt *src_const_elt;
   /* Table entry for the destination address.  */
@@ -4238,6 +4267,15 @@ try_back_substitute_reg (rtx set, rtx_insn *insn)
                  && (reg_mentioned_p (dest, XEXP (note, 0))
                      || rtx_equal_p (src, XEXP (note, 0))))
                remove_note (insn, note);
+
+             /* If INSN has a REG_ARGS_SIZE note, move it to PREV.  */
+             note = find_reg_note (insn, REG_ARGS_SIZE, NULL_RTX);
+             if (note != 0)
+               {
+                 remove_note (insn, note);
+                 gcc_assert (!find_reg_note (prev, REG_ARGS_SIZE, NULL_RTX));
+                 set_unique_reg_note (prev, REG_ARGS_SIZE, XEXP (note, 0));
+               }
            }
        }
     }
@@ -4555,14 +4593,17 @@ cse_insn (rtx_insn *insn)
               && CONST_INT_P (XEXP (SET_DEST (sets[0].rtl), 2)))
        {
          rtx dest_reg = XEXP (SET_DEST (sets[0].rtl), 0);
+         /* This is the mode of XEXP (tem, 0) as well.  */
+         scalar_int_mode dest_mode
+           = as_a <scalar_int_mode> (GET_MODE (dest_reg));
          rtx width = XEXP (SET_DEST (sets[0].rtl), 1);
          rtx pos = XEXP (SET_DEST (sets[0].rtl), 2);
          HOST_WIDE_INT val = INTVAL (XEXP (tem, 0));
          HOST_WIDE_INT mask;
          unsigned int shift;
          if (BITS_BIG_ENDIAN)
-           shift = GET_MODE_PRECISION (GET_MODE (dest_reg))
-             - INTVAL (pos) - INTVAL (width);
+           shift = (GET_MODE_PRECISION (dest_mode)
+                    - INTVAL (pos) - INTVAL (width));
          else
            shift = INTVAL (pos);
          if (INTVAL (width) == HOST_BITS_PER_WIDE_INT)
@@ -4607,6 +4648,7 @@ cse_insn (rtx_insn *insn)
       /* Set nonzero if we need to call force_const_mem on with the
         contents of src_folded before using it.  */
       int src_folded_force_flag = 0;
+      scalar_int_mode int_mode;
 
       dest = SET_DEST (sets[i].rtl);
       src = SET_SRC (sets[i].rtl);
@@ -4844,17 +4886,16 @@ cse_insn (rtx_insn *insn)
         wider mode.  */
 
       if (src_const && src_related == 0 && CONST_INT_P (src_const)
-         && GET_MODE_CLASS (mode) == MODE_INT
-         && GET_MODE_PRECISION (mode) < BITS_PER_WORD)
+         && is_int_mode (mode, &int_mode)
+         && GET_MODE_PRECISION (int_mode) < BITS_PER_WORD)
        {
-         machine_mode wider_mode;
-
-         for (wider_mode = GET_MODE_WIDER_MODE (mode);
-              wider_mode != VOIDmode
-              && GET_MODE_PRECISION (wider_mode) <= BITS_PER_WORD
-              && src_related == 0;
-              wider_mode = GET_MODE_WIDER_MODE (wider_mode))
+         opt_scalar_int_mode wider_mode_iter;
+         FOR_EACH_WIDER_MODE (wider_mode_iter, int_mode)
            {
+             scalar_int_mode wider_mode = wider_mode_iter.require ();
+             if (GET_MODE_PRECISION (wider_mode) > BITS_PER_WORD)
+               break;
+
              struct table_elt *const_elt
                = lookup (src_const, HASH (src_const, wider_mode), wider_mode);
 
@@ -4865,9 +4906,12 @@ cse_insn (rtx_insn *insn)
                   const_elt; const_elt = const_elt->next_same_value)
                if (REG_P (const_elt->exp))
                  {
-                   src_related = gen_lowpart (mode, const_elt->exp);
+                   src_related = gen_lowpart (int_mode, const_elt->exp);
                    break;
                  }
+
+             if (src_related != 0)
+               break;
            }
        }
 
@@ -4878,16 +4922,19 @@ cse_insn (rtx_insn *insn)
         value.  */
 
       if (flag_expensive_optimizations && ! src_related
+         && is_a <scalar_int_mode> (mode, &int_mode)
          && GET_CODE (src) == AND && CONST_INT_P (XEXP (src, 1))
-         && GET_MODE_SIZE (mode) < UNITS_PER_WORD)
+         && GET_MODE_SIZE (int_mode) < UNITS_PER_WORD)
        {
-         machine_mode tmode;
+         opt_scalar_int_mode tmode_iter;
          rtx new_and = gen_rtx_AND (VOIDmode, NULL_RTX, XEXP (src, 1));
 
-         for (tmode = GET_MODE_WIDER_MODE (mode);
-              GET_MODE_SIZE (tmode) <= UNITS_PER_WORD;
-              tmode = GET_MODE_WIDER_MODE (tmode))
+         FOR_EACH_WIDER_MODE (tmode_iter, int_mode)
            {
+             scalar_int_mode tmode = tmode_iter.require ();
+             if (GET_MODE_SIZE (tmode) > UNITS_PER_WORD)
+               break;
+
              rtx inner = gen_lowpart (tmode, XEXP (src, 0));
              struct table_elt *larger_elt;
 
@@ -4904,7 +4951,7 @@ cse_insn (rtx_insn *insn)
                    if (REG_P (larger_elt->exp))
                      {
                        src_related
-                         = gen_lowpart (mode, larger_elt->exp);
+                         = gen_lowpart (int_mode, larger_elt->exp);
                        break;
                      }
 
@@ -4919,28 +4966,30 @@ cse_insn (rtx_insn *insn)
         also have such operations, but this is only likely to be
         beneficial on these machines.  */
 
+      rtx_code extend_op;
       if (flag_expensive_optimizations && src_related == 0
-         && (GET_MODE_SIZE (mode) < UNITS_PER_WORD)
-         && GET_MODE_CLASS (mode) == MODE_INT
          && MEM_P (src) && ! do_not_record
-         && LOAD_EXTEND_OP (mode) != UNKNOWN)
+         && is_a <scalar_int_mode> (mode, &int_mode)
+         && (extend_op = load_extend_op (int_mode)) != UNKNOWN)
        {
          struct rtx_def memory_extend_buf;
          rtx memory_extend_rtx = &memory_extend_buf;
-         machine_mode tmode;
 
          /* Set what we are trying to extend and the operation it might
             have been extended with.  */
          memset (memory_extend_rtx, 0, sizeof (*memory_extend_rtx));
-         PUT_CODE (memory_extend_rtx, LOAD_EXTEND_OP (mode));
+         PUT_CODE (memory_extend_rtx, extend_op);
          XEXP (memory_extend_rtx, 0) = src;
 
-         for (tmode = GET_MODE_WIDER_MODE (mode);
-              GET_MODE_SIZE (tmode) <= UNITS_PER_WORD;
-              tmode = GET_MODE_WIDER_MODE (tmode))
+         opt_scalar_int_mode tmode_iter;
+         FOR_EACH_WIDER_MODE (tmode_iter, int_mode)
            {
              struct table_elt *larger_elt;
 
+             scalar_int_mode tmode = tmode_iter.require ();
+             if (GET_MODE_SIZE (tmode) > UNITS_PER_WORD)
+               break;
+
              PUT_MODE (memory_extend_rtx, tmode);
              larger_elt = lookup (memory_extend_rtx,
                                   HASH (memory_extend_rtx, tmode), tmode);
@@ -4951,7 +5000,7 @@ cse_insn (rtx_insn *insn)
                   larger_elt; larger_elt = larger_elt->next_same_value)
                if (REG_P (larger_elt->exp))
                  {
-                   src_related = gen_lowpart (mode, larger_elt->exp);
+                   src_related = gen_lowpart (int_mode, larger_elt->exp);
                    break;
                  }
 
@@ -5005,8 +5054,8 @@ cse_insn (rtx_insn *insn)
              && ! (src != 0
                    && GET_CODE (src) == SUBREG
                    && GET_MODE (src) == GET_MODE (p->exp)
-                   && (GET_MODE_SIZE (GET_MODE (SUBREG_REG (src)))
-                       < GET_MODE_SIZE (GET_MODE (SUBREG_REG (p->exp))))))
+                   && partial_subreg_p (GET_MODE (SUBREG_REG (src)),
+                                        GET_MODE (SUBREG_REG (p->exp)))))
            continue;
 
          if (src && GET_CODE (src) == code && rtx_equal_p (src, p->exp))
@@ -5116,8 +5165,8 @@ cse_insn (rtx_insn *insn)
              && ! (src != 0
                    && GET_CODE (src) == SUBREG
                    && GET_MODE (src) == GET_MODE (elt->exp)
-                   && (GET_MODE_SIZE (GET_MODE (SUBREG_REG (src)))
-                       < GET_MODE_SIZE (GET_MODE (SUBREG_REG (elt->exp))))))
+                   && partial_subreg_p (GET_MODE (SUBREG_REG (src)),
+                                        GET_MODE (SUBREG_REG (elt->exp)))))
            {
              elt = elt->next_same_value;
              continue;
@@ -5175,23 +5224,6 @@ cse_insn (rtx_insn *insn)
              src_elt_cost = MAX_COST;
            }
 
-         /* Avoid creation of overlapping memory moves.  */
-         if (MEM_P (trial) && MEM_P (dest) && !rtx_equal_p (trial, dest))
-           {
-             rtx src, dest;
-
-             /* BLKmode moves are not handled by cse anyway.  */
-             if (GET_MODE (trial) == BLKmode)
-               break;
-
-             src = canon_rtx (trial);
-             dest = canon_rtx (SET_DEST (sets[i].rtl));
-
-             if (!MEM_P (src) || !MEM_P (dest)
-                 || !nonoverlapping_memrefs_p (src, dest, false))
-               break;
-           }
-
          /* Try to optimize
             (set (reg:M N) (const_int A))
             (set (reg:M2 O) (const_int B))
@@ -5202,8 +5234,9 @@ cse_insn (rtx_insn *insn)
              && CONST_INT_P (XEXP (SET_DEST (sets[i].rtl), 1))
              && CONST_INT_P (XEXP (SET_DEST (sets[i].rtl), 2))
              && REG_P (XEXP (SET_DEST (sets[i].rtl), 0))
-             && (GET_MODE_PRECISION (GET_MODE (SET_DEST (sets[i].rtl)))
-                 >= INTVAL (XEXP (SET_DEST (sets[i].rtl), 1)))
+             && (known_ge
+                 (GET_MODE_PRECISION (GET_MODE (SET_DEST (sets[i].rtl))),
+                  INTVAL (XEXP (SET_DEST (sets[i].rtl), 1))))
              && ((unsigned) INTVAL (XEXP (SET_DEST (sets[i].rtl), 1))
                  + (unsigned) INTVAL (XEXP (SET_DEST (sets[i].rtl), 2))
                  <= HOST_BITS_PER_WIDE_INT))
@@ -5228,8 +5261,11 @@ cse_insn (rtx_insn *insn)
                  HOST_WIDE_INT val = INTVAL (dest_cst);
                  HOST_WIDE_INT mask;
                  unsigned int shift;
+                 /* This is the mode of DEST_CST as well.  */
+                 scalar_int_mode dest_mode
+                   = as_a <scalar_int_mode> (GET_MODE (dest_reg));
                  if (BITS_BIG_ENDIAN)
-                   shift = GET_MODE_PRECISION (GET_MODE (dest_reg))
+                   shift = GET_MODE_PRECISION (dest_mode)
                            - INTVAL (pos) - INTVAL (width);
                  else
                    shift = INTVAL (pos);
@@ -5239,7 +5275,7 @@ cse_insn (rtx_insn *insn)
                    mask = (HOST_WIDE_INT_1 << INTVAL (width)) - 1;
                  val &= ~(mask << shift);
                  val |= (INTVAL (trial) & mask) << shift;
-                 val = trunc_int_for_mode (val, GET_MODE (dest_reg));
+                 val = trunc_int_for_mode (val, dest_mode);
                  validate_unshare_change (insn, &SET_DEST (sets[i].rtl),
                                           dest_reg, 1);
                  validate_unshare_change (insn, &SET_SRC (sets[i].rtl),
@@ -5318,6 +5354,12 @@ cse_insn (rtx_insn *insn)
            /* Do nothing for this case.  */
            ;
 
+         /* Do not replace anything with a MEM, except the replacement
+            is a no-op.  This allows this loop to terminate.  */
+         else if (MEM_P (trial) && !rtx_equal_p (trial, SET_SRC(sets[i].rtl)))
+           /* Do nothing for this case.  */
+           ;
+
          /* Look for a substitution that makes a valid insn.  */
          else if (validate_unshare_change (insn, &SET_SRC (sets[i].rtl),
                                            trial, 0))
@@ -5767,7 +5809,7 @@ cse_insn (rtx_insn *insn)
          if (GET_CODE (XEXP (tem, 0)) == USE
              && MEM_P (XEXP (XEXP (tem, 0), 0)))
            invalidate (XEXP (XEXP (tem, 0), 0), VOIDmode);
-      invalidate_for_call ();
+      invalidate_for_call (insn);
     }
 
   /* Now invalidate everything set by this instruction.
@@ -5953,11 +5995,11 @@ cse_insn (rtx_insn *insn)
           already entered SRC and DEST of the SET in the table.  */
 
        if (GET_CODE (dest) == SUBREG
-           && (((GET_MODE_SIZE (GET_MODE (SUBREG_REG (dest))) - 1)
-                / UNITS_PER_WORD)
-               == (GET_MODE_SIZE (GET_MODE (dest)) - 1) / UNITS_PER_WORD)
-           && (GET_MODE_SIZE (GET_MODE (dest))
-               >= GET_MODE_SIZE (GET_MODE (SUBREG_REG (dest))))
+           && (known_equal_after_align_down
+               (GET_MODE_SIZE (GET_MODE (SUBREG_REG (dest))) - 1,
+                GET_MODE_SIZE (GET_MODE (dest)) - 1,
+                UNITS_PER_WORD))
+           && !partial_subreg_p (dest)
            && sets[i].src_elt != 0)
          {
            machine_mode new_mode = GET_MODE (SUBREG_REG (dest));
@@ -5969,7 +6011,6 @@ cse_insn (rtx_insn *insn)
                rtx new_src = 0;
                unsigned src_hash;
                struct table_elt *src_elt;
-               int byte = 0;
 
                /* Ignore invalid entries.  */
                if (!REG_P (elt->exp)
@@ -5982,13 +6023,8 @@ cse_insn (rtx_insn *insn)
                  new_src = elt->exp;
                else
                  {
-                   /* Calculate big endian correction for the SUBREG_BYTE.
-                      We have already checked that M1 (GET_MODE (dest))
-                      is not narrower than M2 (new_mode).  */
-                   if (BYTES_BIG_ENDIAN)
-                     byte = (GET_MODE_SIZE (GET_MODE (dest))
-                             - GET_MODE_SIZE (new_mode));
-
+                   poly_uint64 byte
+                     = subreg_lowpart_offset (new_mode, GET_MODE (dest));
                    new_src = simplify_gen_subreg (new_mode, elt->exp,
                                                   GET_MODE (dest), byte);
                  }
@@ -6127,8 +6163,11 @@ invalidate_from_sets_and_clobbers (rtx_insn *insn)
   if (CALL_P (insn))
     {
       for (tem = CALL_INSN_FUNCTION_USAGE (insn); tem; tem = XEXP (tem, 1))
-       if (GET_CODE (XEXP (tem, 0)) == CLOBBER)
-         invalidate (SET_DEST (XEXP (tem, 0)), VOIDmode);
+       {
+         rtx temx = XEXP (tem, 0);
+         if (GET_CODE (temx) == CLOBBER)
+           invalidate (SET_DEST (temx), VOIDmode);
+       }
     }
 
   /* Ensure we invalidate the destination register of a CALL insn.
@@ -6374,7 +6413,7 @@ cse_find_path (basic_block first_bb, struct cse_basic_block_data *data,
   if (follow_jumps)
     {
       bb = data->path[path_size - 1].bb;
-      while (bb && path_size < PARAM_VALUE (PARAM_MAX_CSE_PATH_LENGTH))
+      while (bb && path_size < param_max_cse_path_length)
        {
          if (single_succ_p (bb))
            e = single_succ_edge (bb);
@@ -6424,7 +6463,7 @@ cse_dump_path (struct cse_basic_block_data *data, int nsets, FILE *f)
   fprintf (f, ";; Following path with %d sets: ", nsets);
   for (path_entry = 0; path_entry < data->path_size; path_entry++)
     fprintf (f, "%d ", (data->path[path_entry].bb)->index);
-  fputc ('\n', dump_file);
+  fputc ('\n', f);
   fflush (f);
 }
 
@@ -6497,10 +6536,10 @@ check_for_label_ref (rtx_insn *insn)
       if (GET_CODE (x) == LABEL_REF
          && !LABEL_REF_NONLOCAL_P (x)
          && (!JUMP_P (insn)
-             || !label_is_jump_target_p (LABEL_REF_LABEL (x), insn))
-         && LABEL_P (LABEL_REF_LABEL (x))
-         && INSN_UID (LABEL_REF_LABEL (x)) != 0
-         && !find_reg_note (insn, REG_LABEL_OPERAND, LABEL_REF_LABEL (x)))
+             || !label_is_jump_target_p (label_ref_label (x), insn))
+         && LABEL_P (label_ref_label (x))
+         && INSN_UID (label_ref_label (x)) != 0
+         && !find_reg_note (insn, REG_LABEL_OPERAND, label_ref_label (x)))
        return true;
     }
   return false;
@@ -6552,7 +6591,7 @@ cse_extended_basic_block (struct cse_basic_block_data *ebb_data)
             FIXME: This is a real kludge and needs to be done some other
                    way.  */
          if (NONDEBUG_INSN_P (insn)
-             && num_insns++ > PARAM_VALUE (PARAM_MAX_CSE_INSNS))
+             && num_insns++ > param_max_cse_insns)
            {
              flush_hash_table ();
              num_insns = 0;
@@ -6645,6 +6684,7 @@ cse_extended_basic_block (struct cse_basic_block_data *ebb_data)
         equivalences due to the condition being tested.  */
       insn = BB_END (bb);
       if (path_entry < path_size - 1
+         && EDGE_COUNT (bb->succs) == 2
          && JUMP_P (insn)
          && single_set (insn)
          && any_condjump_p (insn))
@@ -6695,7 +6735,7 @@ cse_main (rtx_insn *f ATTRIBUTE_UNUSED, int nregs)
   init_cse_reg_info (nregs);
 
   ebb_data.path = XNEWVEC (struct branch_path,
-                          PARAM_VALUE (PARAM_MAX_CSE_PATH_LENGTH));
+                          param_max_cse_path_length);
 
   cse_cfg_altered = false;
   cse_jumps_altered = false;
@@ -6958,11 +6998,18 @@ insn_live_p (rtx_insn *insn, int *counts)
     {
       rtx_insn *next;
 
+      if (DEBUG_MARKER_INSN_P (insn))
+       return true;
+
       for (next = NEXT_INSN (insn); next; next = NEXT_INSN (next))
        if (NOTE_P (next))
          continue;
        else if (!DEBUG_INSN_P (next))
          return true;
+       /* If we find an inspection point, such as a debug begin stmt,
+          we want to keep the earlier debug insn.  */
+       else if (DEBUG_MARKER_INSN_P (next))
+         return true;
        else if (INSN_VAR_LOCATION_DECL (insn) == INSN_VAR_LOCATION_DECL (next))
          return false;
 
@@ -7045,17 +7092,17 @@ delete_trivially_dead_insns (rtx_insn *insns, int nreg)
 
   timevar_push (TV_DELETE_TRIVIALLY_DEAD);
   /* First count the number of times each register is used.  */
-  if (MAY_HAVE_DEBUG_INSNS)
+  if (MAY_HAVE_DEBUG_BIND_INSNS)
     {
       counts = XCNEWVEC (int, nreg * 3);
       for (insn = insns; insn; insn = NEXT_INSN (insn))
-       if (DEBUG_INSN_P (insn))
+       if (DEBUG_BIND_INSN_P (insn))
          count_reg_usage (INSN_VAR_LOCATION_LOC (insn), counts + nreg,
                           NULL_RTX, 1);
        else if (INSN_P (insn))
          {
            count_reg_usage (insn, counts, NULL_RTX, 1);
-           note_stores (PATTERN (insn), count_stores, counts + nreg * 2);
+           note_stores (insn, count_stores, counts + nreg * 2);
          }
       /* If there can be debug insns, COUNTS are 3 consecutive arrays.
         First one counts how many times each pseudo is used outside
@@ -7107,12 +7154,15 @@ delete_trivially_dead_insns (rtx_insn *insns, int nreg)
       if (! live_insn && dbg_cnt (delete_trivial_dead))
        {
          if (DEBUG_INSN_P (insn))
-           count_reg_usage (INSN_VAR_LOCATION_LOC (insn), counts + nreg,
-                            NULL_RTX, -1);
+           {
+             if (DEBUG_BIND_INSN_P (insn))
+               count_reg_usage (INSN_VAR_LOCATION_LOC (insn), counts + nreg,
+                                NULL_RTX, -1);
+           }
          else
            {
              rtx set;
-             if (MAY_HAVE_DEBUG_INSNS
+             if (MAY_HAVE_DEBUG_BIND_INSNS
                  && (set = single_set (insn)) != NULL_RTX
                  && is_dead_reg (SET_DEST (set), counts)
                  /* Used at least once in some DEBUG_INSN.  */
@@ -7152,10 +7202,10 @@ delete_trivially_dead_insns (rtx_insn *insns, int nreg)
        }
     }
 
-  if (MAY_HAVE_DEBUG_INSNS)
+  if (MAY_HAVE_DEBUG_BIND_INSNS)
     {
       for (insn = get_last_insn (); insn; insn = PREV_INSN (insn))
-       if (DEBUG_INSN_P (insn))
+       if (DEBUG_BIND_INSN_P (insn))
          {
            /* If this debug insn references a dead register that wasn't replaced
               with an DEBUG_EXPR, reset the DEBUG_INSN.  */
@@ -7651,7 +7701,7 @@ rest_of_handle_cse2 (void)
       cse_cfg_altered |= cleanup_cfg (CLEANUP_CFG_CHANGED);
       timevar_pop (TV_JUMP);
     }
-  else if (tem == 1)
+  else if (tem == 1 || cse_cfg_altered)
     cse_cfg_altered |= cleanup_cfg (0);
 
   cse_not_expected = 1;
@@ -7725,7 +7775,7 @@ rest_of_handle_cse_after_global_opts (void)
       cse_cfg_altered |= cleanup_cfg (CLEANUP_CFG_CHANGED);
       timevar_pop (TV_JUMP);
     }
-  else if (tem == 1)
+  else if (tem == 1 || cse_cfg_altered)
     cse_cfg_altered |= cleanup_cfg (0);
 
   flag_cse_follow_jumps = save_cfj;