re PR target/65697 (__atomic memory barriers not strong enough for __sync builtins)
[gcc.git] / gcc / cse.c
index 319b5f89abbc15096432d8ee2c29bb06545cf305..100c9c83e769faf920d15c98bb614c35b80e8b5d 100644 (file)
--- a/gcc/cse.c
+++ b/gcc/cse.c
@@ -1,5 +1,5 @@
 /* Common subexpression elimination for GNU compiler.
-   Copyright (C) 1987-2014 Free Software Foundation, Inc.
+   Copyright (C) 1987-2015 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -25,15 +25,30 @@ along with GCC; see the file COPYING3.  If not see
 #include "tm_p.h"
 #include "hard-reg-set.h"
 #include "regs.h"
+#include "predict.h"
+#include "function.h"
+#include "dominance.h"
+#include "cfg.h"
+#include "cfgrtl.h"
+#include "cfganal.h"
+#include "cfgcleanup.h"
 #include "basic-block.h"
 #include "flags.h"
 #include "insn-config.h"
 #include "recog.h"
-#include "function.h"
+#include "symtab.h"
+#include "alias.h"
+#include "tree.h"
+#include "expmed.h"
+#include "dojump.h"
+#include "explow.h"
+#include "calls.h"
+#include "emit-rtl.h"
+#include "varasm.h"
+#include "stmt.h"
 #include "expr.h"
 #include "diagnostic-core.h"
 #include "toplev.h"
-#include "ggc.h"
 #include "except.h"
 #include "target.h"
 #include "params.h"
@@ -41,7 +56,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-pass.h"
 #include "df.h"
 #include "dbgcnt.h"
-#include "hash-set.h"
 #include "rtl-iter.h"
 
 /* The basic idea of common subexpression elimination is to go
@@ -255,15 +269,6 @@ struct qty_table_elem
 /* The table of all qtys, indexed by qty number.  */
 static struct qty_table_elem *qty_table;
 
-/* Structure used to pass arguments via for_each_rtx to function
-   cse_change_cc_mode.  */
-struct change_cc_mode_args
-{
-  rtx_insn *insn;
-  rtx newreg;
-};
-
-#ifdef HAVE_cc0
 /* For machines that have a CC0, we do not record its value in the hash
    table since its use is guaranteed to be the insn immediately following
    its definition and any other insn is presumed to invalidate it.
@@ -274,8 +279,7 @@ struct change_cc_mode_args
    the mode in which the constant should be interpreted.  */
 
 static rtx this_insn_cc0, prev_insn_cc0;
-static enum machine_mode this_insn_cc0_mode, prev_insn_cc0_mode;
-#endif
+static machine_mode this_insn_cc0_mode, prev_insn_cc0_mode;
 
 /* Insn being scanned.  */
 
@@ -553,42 +557,42 @@ static bool fixed_base_plus_p (rtx x);
 static int notreg_cost (rtx, enum rtx_code, int);
 static int preferable (int, int, int, int);
 static void new_basic_block (void);
-static void make_new_qty (unsigned int, enum machine_mode);
+static void make_new_qty (unsigned int, machine_mode);
 static void make_regs_eqv (unsigned int, unsigned int);
 static void delete_reg_equiv (unsigned int);
 static int mention_regs (rtx);
 static int insert_regs (rtx, struct table_elt *, int);
 static void remove_from_table (struct table_elt *, unsigned);
 static void remove_pseudo_from_table (rtx, unsigned);
-static struct table_elt *lookup (rtx, unsigned, enum machine_mode);
-static struct table_elt *lookup_for_remove (rtx, unsigned, enum machine_mode);
+static struct table_elt *lookup (rtx, unsigned, machine_mode);
+static struct table_elt *lookup_for_remove (rtx, unsigned, machine_mode);
 static rtx lookup_as_function (rtx, enum rtx_code);
 static struct table_elt *insert_with_costs (rtx, struct table_elt *, unsigned,
-                                           enum machine_mode, int, int);
+                                           machine_mode, int, int);
 static struct table_elt *insert (rtx, struct table_elt *, unsigned,
-                                enum machine_mode);
+                                machine_mode);
 static void merge_equiv_classes (struct table_elt *, struct table_elt *);
-static void invalidate (rtx, enum machine_mode);
+static void invalidate (rtx, machine_mode);
 static void remove_invalid_refs (unsigned int);
 static void remove_invalid_subreg_refs (unsigned int, unsigned int,
-                                       enum machine_mode);
+                                       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, enum machine_mode);
-static inline unsigned safe_hash (rtx, enum machine_mode);
+static inline unsigned canon_hash (rtx, machine_mode);
+static inline unsigned safe_hash (rtx, machine_mode);
 static inline unsigned hash_rtx_string (const char *);
 
 static rtx canon_reg (rtx, rtx_insn *);
 static enum rtx_code find_comparison_args (enum rtx_code, rtx *, rtx *,
-                                          enum machine_mode *,
-                                          enum machine_mode *);
+                                          machine_mode *,
+                                          machine_mode *);
 static rtx fold_rtx (rtx, rtx_insn *);
 static rtx equiv_constant (rtx);
 static void record_jump_equiv (rtx_insn *, bool);
-static void record_jump_cond (enum rtx_code, enum machine_mode, rtx, rtx,
+static void record_jump_cond (enum rtx_code, machine_mode, rtx, rtx,
                              int);
 static void cse_insn (rtx_insn *);
 static void cse_prescan_path (struct cse_basic_block_data *);
@@ -603,10 +607,9 @@ static struct cse_reg_info * get_cse_reg_info (unsigned int regno);
 static void flush_hash_table (void);
 static bool insn_live_p (rtx_insn *, int *);
 static bool set_live_p (rtx, rtx_insn *, int *);
-static int cse_change_cc_mode (rtx *, void *);
 static void cse_change_cc_mode_insn (rtx_insn *, rtx);
 static void cse_change_cc_mode_insns (rtx_insn *, rtx_insn *, rtx);
-static enum machine_mode cse_cc_succs (basic_block, basic_block, rtx, rtx,
+static machine_mode cse_cc_succs (basic_block, basic_block, rtx, rtx,
                                       bool);
 \f
 
@@ -867,16 +870,14 @@ new_basic_block (void)
        }
     }
 
-#ifdef HAVE_cc0
   prev_insn_cc0 = 0;
-#endif
 }
 
 /* Say that register REG contains a quantity in mode MODE not in any
    register before and initialize that quantity.  */
 
 static void
-make_new_qty (unsigned int reg, enum machine_mode mode)
+make_new_qty (unsigned int reg, machine_mode mode)
 {
   int q;
   struct qty_table_elem *ent;
@@ -1221,7 +1222,7 @@ compute_const_anchors (rtx cst,
 
 static void
 insert_const_anchor (HOST_WIDE_INT anchor, rtx reg, HOST_WIDE_INT offs,
-                    enum machine_mode mode)
+                    machine_mode mode)
 {
   struct table_elt *elt;
   unsigned hash;
@@ -1254,7 +1255,7 @@ insert_const_anchor (HOST_WIDE_INT anchor, rtx reg, HOST_WIDE_INT offs,
    register-offset expressions using REG.  */
 
 static void
-insert_const_anchors (rtx reg, rtx cst, enum machine_mode mode)
+insert_const_anchors (rtx reg, rtx cst, machine_mode mode)
 {
   HOST_WIDE_INT lower_base, lower_offs, upper_base, upper_offs;
 
@@ -1331,7 +1332,7 @@ find_reg_offset_for_const (struct table_elt *anchor_elt, HOST_WIDE_INT offs,
    otherwise.  */
 
 static rtx
-try_const_anchors (rtx src_const, enum machine_mode mode)
+try_const_anchors (rtx src_const, machine_mode mode)
 {
   struct table_elt *lower_elt, *upper_elt;
   HOST_WIDE_INT lower_base, lower_offs, upper_base, upper_offs;
@@ -1471,7 +1472,7 @@ remove_pseudo_from_table (rtx x, unsigned int hash)
    looks like X.  */
 
 static struct table_elt *
-lookup (rtx x, unsigned int hash, enum machine_mode mode)
+lookup (rtx x, unsigned int hash, machine_mode mode)
 {
   struct table_elt *p;
 
@@ -1487,7 +1488,7 @@ lookup (rtx x, unsigned int hash, enum machine_mode mode)
    Also ignore discrepancies in the machine mode of a register.  */
 
 static struct table_elt *
-lookup_for_remove (rtx x, unsigned int hash, enum machine_mode mode)
+lookup_for_remove (rtx x, unsigned int hash, machine_mode mode)
 {
   struct table_elt *p;
 
@@ -1560,7 +1561,7 @@ lookup_as_function (rtx x, enum rtx_code code)
 
 static struct table_elt *
 insert_with_costs (rtx x, struct table_elt *classp, unsigned int hash,
-                  enum machine_mode mode, int cost, int reg_cost)
+                  machine_mode mode, int cost, int reg_cost)
 {
   struct table_elt *elt;
 
@@ -1725,7 +1726,7 @@ insert_with_costs (rtx x, struct table_elt *classp, unsigned int hash,
 
 static struct table_elt *
 insert (rtx x, struct table_elt *classp, unsigned int hash,
-       enum machine_mode mode)
+       machine_mode mode)
 {
   return
     insert_with_costs (x, classp, hash, mode, COST (x), approx_reg_cost (x));
@@ -1758,7 +1759,7 @@ merge_equiv_classes (struct table_elt *class1, struct table_elt *class2)
     {
       unsigned int hash;
       rtx exp = elt->exp;
-      enum machine_mode mode = elt->mode;
+      machine_mode mode = elt->mode;
 
       next = elt->next_same_value;
 
@@ -1790,6 +1791,8 @@ merge_equiv_classes (struct table_elt *class1, struct table_elt *class2)
            }
          new_elt = insert (exp, class1, hash, mode);
          new_elt->in_memory = hash_arg_in_memory;
+         if (GET_CODE (exp) == ASM_OPERANDS && elt->cost == MAX_COST)
+           new_elt->cost = MAX_COST;
        }
     }
 }
@@ -1818,7 +1821,7 @@ flush_hash_table (void)
    ADDR are as for canon_anti_dependence.  */
 
 static bool
-check_dependence (const_rtx x, rtx exp, enum machine_mode mode, rtx addr)
+check_dependence (const_rtx x, rtx exp, machine_mode mode, rtx addr)
 {
   subrtx_iterator::array_type array;
   FOR_EACH_SUBRTX (iter, array, x, NONCONST)
@@ -1843,7 +1846,7 @@ check_dependence (const_rtx x, rtx exp, enum machine_mode mode, rtx addr)
    or it may be either of those plus a numeric offset.  */
 
 static void
-invalidate (rtx x, enum machine_mode full_mode)
+invalidate (rtx x, machine_mode full_mode)
 {
   int i;
   struct table_elt *p;
@@ -1879,7 +1882,7 @@ invalidate (rtx x, enum machine_mode full_mode)
          {
            HOST_WIDE_INT in_table
              = TEST_HARD_REG_BIT (hard_regs_in_table, regno);
-           unsigned int endregno = END_HARD_REGNO (x);
+           unsigned int endregno = END_REGNO (x);
            unsigned int tregno, tendregno, rn;
            struct table_elt *p, *next;
 
@@ -1905,7 +1908,7 @@ invalidate (rtx x, enum machine_mode full_mode)
                      continue;
 
                    tregno = REGNO (p->exp);
-                   tendregno = END_HARD_REGNO (p->exp);
+                   tendregno = END_REGNO (p->exp);
                    if (tendregno > regno && tregno < endregno)
                      remove_from_table (p, hash);
                  }
@@ -1965,6 +1968,22 @@ invalidate (rtx x, enum machine_mode full_mode)
       gcc_unreachable ();
     }
 }
+
+/* Invalidate DEST.  Used when DEST is not going to be added
+   into the hash table for some reason, e.g. do_not_record
+   flagged on it.  */
+
+static void
+invalidate_dest (rtx dest)
+{
+  if (REG_P (dest)
+      || GET_CODE (dest) == SUBREG
+      || MEM_P (dest))
+    invalidate (dest, VOIDmode);
+  else if (GET_CODE (dest) == STRICT_LOW_PART
+          || GET_CODE (dest) == ZERO_EXTRACT)
+    invalidate (XEXP (dest, 0), GET_MODE (dest));
+}
 \f
 /* Remove all expressions that refer to register REGNO,
    since they are already invalid, and we are about to
@@ -1981,8 +2000,7 @@ remove_invalid_refs (unsigned int regno)
     for (p = table[i]; p; p = next)
       {
        next = p->next_same_hash;
-       if (!REG_P (p->exp)
-           && refers_to_regno_p (regno, regno + 1, p->exp, (rtx *) 0))
+       if (!REG_P (p->exp) && refers_to_regno_p (regno, p->exp))
          remove_from_table (p, i);
       }
 }
@@ -1991,7 +2009,7 @@ remove_invalid_refs (unsigned int regno)
    and mode MODE.  */
 static void
 remove_invalid_subreg_refs (unsigned int regno, unsigned int offset,
-                           enum machine_mode mode)
+                           machine_mode mode)
 {
   unsigned int i;
   struct table_elt *p, *next;
@@ -2010,7 +2028,7 @@ remove_invalid_subreg_refs (unsigned int regno, unsigned int offset,
                || (((SUBREG_BYTE (exp)
                      + (GET_MODE_SIZE (GET_MODE (exp)) - 1)) >= offset)
                    && SUBREG_BYTE (exp) <= end))
-           && refers_to_regno_p (regno, regno + 1, p->exp, (rtx *) 0))
+           && refers_to_regno_p (regno, p->exp))
          remove_from_table (p, i);
       }
 }
@@ -2109,7 +2127,7 @@ invalidate_for_call (void)
            continue;
 
          regno = REGNO (p->exp);
-         endregno = END_HARD_REGNO (p->exp);
+         endregno = END_REGNO (p->exp);
 
          for (i = regno; i < endregno; i++)
            if (TEST_HARD_REG_BIT (regs_invalidated_by_call, i))
@@ -2212,7 +2230,7 @@ hash_rtx_string (const char *ps)
    When the callback returns true, we continue with the new rtx.  */
 
 unsigned
-hash_rtx_cb (const_rtx x, enum machine_mode mode,
+hash_rtx_cb (const_rtx x, machine_mode mode,
              int *do_not_record_p, int *hash_arg_in_memory_p,
              bool have_reg_qty, hash_rtx_callback_function cb)
 {
@@ -2220,7 +2238,7 @@ hash_rtx_cb (const_rtx x, enum machine_mode mode,
   unsigned hash = 0;
   enum rtx_code code;
   const char *fmt;
-  enum machine_mode newmode;
+  machine_mode newmode;
   rtx newx;
 
   /* Used to turn recursion into iteration.  We can't rely on GCC's
@@ -2358,7 +2376,7 @@ hash_rtx_cb (const_rtx x, enum 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 (XEXP (x, 0)));
+                 + CODE_LABEL_NUMBER (LABEL_REF_LABEL (x)));
       return hash;
 
     case SYMBOL_REF:
@@ -2539,7 +2557,7 @@ hash_rtx_cb (const_rtx x, enum machine_mode mode,
    is just (int) MEM plus the hash code of the address.  */
 
 unsigned
-hash_rtx (const_rtx x, enum machine_mode mode, int *do_not_record_p,
+hash_rtx (const_rtx x, machine_mode mode, int *do_not_record_p,
          int *hash_arg_in_memory_p, bool have_reg_qty)
 {
   return hash_rtx_cb (x, mode, do_not_record_p,
@@ -2552,7 +2570,7 @@ hash_rtx (const_rtx x, enum machine_mode mode, int *do_not_record_p,
    does not have the MEM_READONLY_P flag set.  */
 
 static inline unsigned
-canon_hash (rtx x, enum machine_mode mode)
+canon_hash (rtx x, machine_mode mode)
 {
   return hash_rtx (x, mode, &do_not_record, &hash_arg_in_memory, true);
 }
@@ -2561,7 +2579,7 @@ canon_hash (rtx x, enum machine_mode mode)
    and hash_arg_in_memory are not changed.  */
 
 static inline unsigned
-safe_hash (rtx x, enum machine_mode mode)
+safe_hash (rtx x, machine_mode mode)
 {
   int dummy_do_not_record;
   return hash_rtx (x, mode, &dummy_do_not_record, NULL, true);
@@ -2611,7 +2629,7 @@ exp_equiv_p (const_rtx x, const_rtx y, int validate, bool for_gcse)
       return x == y;
 
     case LABEL_REF:
-      return XEXP (x, 0) == XEXP (y, 0);
+      return LABEL_REF_LABEL (x) == LABEL_REF_LABEL (y);
 
     case SYMBOL_REF:
       return XSTR (x, 0) == XSTR (y, 0);
@@ -2881,7 +2899,7 @@ canon_reg (rtx x, rtx_insn *insn)
 
 static enum rtx_code
 find_comparison_args (enum rtx_code code, rtx *parg1, rtx *parg2,
-                     enum machine_mode *pmode1, enum machine_mode *pmode2)
+                     machine_mode *pmode1, machine_mode *pmode2)
 {
   rtx arg1, arg2;
   hash_set<rtx> *visited = NULL;
@@ -2973,7 +2991,7 @@ find_comparison_args (enum rtx_code code, rtx *parg1, rtx *parg2,
 
       for (; p; p = p->next_same_value)
        {
-         enum machine_mode inner_mode = GET_MODE (p->exp);
+         machine_mode inner_mode = GET_MODE (p->exp);
 #ifdef FLOAT_STORE_FLAG_VALUE
          REAL_VALUE_TYPE fsfv;
 #endif
@@ -3085,15 +3103,17 @@ static rtx
 fold_rtx (rtx x, rtx_insn *insn)
 {
   enum rtx_code code;
-  enum machine_mode mode;
+  machine_mode mode;
   const char *fmt;
   int i;
   rtx new_rtx = 0;
   int changed = 0;
 
   /* Operands of X.  */
-  rtx folded_arg0;
-  rtx folded_arg1;
+  /* Workaround -Wmaybe-uninitialized false positive during
+     profiledbootstrap by initializing them.  */
+  rtx folded_arg0 = NULL_RTX;
+  rtx folded_arg1 = NULL_RTX;
 
   /* Constant equivalents of first three operands of X;
      0 when no such equivalent is known.  */
@@ -3103,7 +3123,7 @@ fold_rtx (rtx x, rtx_insn *insn)
 
   /* The mode of the first operand of X.  We need this for sign and zero
      extends.  */
-  enum machine_mode mode_arg0;
+  machine_mode mode_arg0;
 
   if (x == 0)
     return x;
@@ -3114,6 +3134,15 @@ fold_rtx (rtx x, rtx_insn *insn)
     {
     case MEM:
     case SUBREG:
+    /* The first operand of a SIGN/ZERO_EXTRACT has a different meaning
+       than it would in other contexts.  Basically its mode does not
+       signify the size of the object read.  That information is carried
+       by size operand.    If we happen to have a MEM of the appropriate
+       mode in our tables with a constant value we could simplify the
+       extraction incorrectly if we allowed substitution of that value
+       for the MEM.   */
+    case ZERO_EXTRACT:
+    case SIGN_EXTRACT:
       if ((new_rtx = equiv_constant (x)) != NULL_RTX)
         return new_rtx;
       return x;
@@ -3130,10 +3159,8 @@ fold_rtx (rtx x, rtx_insn *insn)
     case EXPR_LIST:
       return x;
 
-#ifdef HAVE_cc0
     case CC0:
       return prev_insn_cc0;
-#endif
 
     case ASM_OPERANDS:
       if (insn)
@@ -3144,12 +3171,10 @@ fold_rtx (rtx x, rtx_insn *insn)
        }
       return x;
 
-#ifdef NO_FUNCTION_CSE
     case CALL:
-      if (CONSTANT_P (XEXP (XEXP (x, 0), 0)))
+      if (NO_FUNCTION_CSE && CONSTANT_P (XEXP (XEXP (x, 0), 0)))
        return x;
       break;
-#endif
 
     /* Anything else goes through the loop below.  */
     default:
@@ -3170,7 +3195,7 @@ fold_rtx (rtx x, rtx_insn *insn)
     if (fmt[i] == 'e')
       {
        rtx folded_arg = XEXP (x, i), const_arg;
-       enum machine_mode mode_arg = GET_MODE (folded_arg);
+       machine_mode mode_arg = GET_MODE (folded_arg);
 
        switch (GET_CODE (folded_arg))
          {
@@ -3187,7 +3212,6 @@ fold_rtx (rtx x, rtx_insn *insn)
            const_arg = folded_arg;
            break;
 
-#ifdef HAVE_cc0
          case CC0:
            /* The cc0-user and cc0-setter may be in different blocks if
               the cc0-setter potentially traps.  In that case PREV_INSN_CC0
@@ -3211,7 +3235,6 @@ fold_rtx (rtx x, rtx_insn *insn)
                const_arg = equiv_constant (folded_arg);
              }
            break;
-#endif
 
          default:
            folded_arg = fold_rtx (folded_arg, insn);
@@ -3316,7 +3339,7 @@ fold_rtx (rtx x, rtx_insn *insn)
        {
          struct table_elt *p0, *p1;
          rtx true_rtx, false_rtx;
-         enum machine_mode mode_arg1;
+         machine_mode mode_arg1;
 
          if (SCALAR_FLOAT_MODE_P (mode))
            {
@@ -3495,7 +3518,7 @@ fold_rtx (rtx x, rtx_insn *insn)
                : lookup_as_function (folded_arg0, MINUS);
 
              if (y != 0 && GET_CODE (XEXP (y, 1)) == LABEL_REF
-                 && XEXP (XEXP (y, 1), 0) == XEXP (const_arg1, 0))
+                 && 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.  */
@@ -3503,7 +3526,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
-                 && XEXP (XEXP (XEXP (y, 0), 1), 0) == XEXP (const_arg1, 0))
+                 && LABEL_REF_LABEL (XEXP (XEXP (y, 0), 1)) == LABEL_REF_LABEL (const_arg1))
                return XEXP (XEXP (y, 0), 0);
            }
 
@@ -3515,7 +3538,7 @@ fold_rtx (rtx x, rtx_insn *insn)
                : lookup_as_function (folded_arg1, MINUS);
 
              if (y != 0 && GET_CODE (XEXP (y, 1)) == LABEL_REF
-                 && XEXP (XEXP (y, 1), 0) == XEXP (const_arg0, 0))
+                 && 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.  */
@@ -3523,7 +3546,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
-                 && XEXP (XEXP (XEXP (y, 0), 1), 0) == XEXP (const_arg0, 0))
+                 && LABEL_REF_LABEL (XEXP (XEXP (y, 0), 1)) == LABEL_REF_LABEL (const_arg0))
                return XEXP (XEXP (y, 0), 0);
            }
 
@@ -3763,8 +3786,8 @@ equiv_constant (rtx x)
 
   if (GET_CODE (x) == SUBREG)
     {
-      enum machine_mode mode = GET_MODE (x);
-      enum machine_mode imode = GET_MODE (SUBREG_REG (x));
+      machine_mode mode = GET_MODE (x);
+      machine_mode imode = GET_MODE (SUBREG_REG (x));
       rtx new_rtx;
 
       /* See if we previously assigned a constant value to this SUBREG.  */
@@ -3841,7 +3864,7 @@ record_jump_equiv (rtx_insn *insn, bool taken)
   int cond_known_true;
   rtx op0, op1;
   rtx set;
-  enum machine_mode mode, mode0, mode1;
+  machine_mode mode, mode0, mode1;
   int reversed_nonequality = 0;
   enum rtx_code code;
 
@@ -3885,9 +3908,9 @@ record_jump_equiv (rtx_insn *insn, bool taken)
    MODE, and we should assume OP has MODE iff it is naturally modeless.  */
 
 static rtx
-record_jump_cond_subreg (enum machine_mode mode, rtx op)
+record_jump_cond_subreg (machine_mode mode, rtx op)
 {
-  enum machine_mode op_mode = GET_MODE (op);
+  machine_mode op_mode = GET_MODE (op);
   if (op_mode == mode || op_mode == VOIDmode)
     return op;
   return lowpart_subreg (mode, op, op_mode);
@@ -3899,7 +3922,7 @@ record_jump_cond_subreg (enum machine_mode mode, rtx op)
    above function and called recursively.  */
 
 static void
-record_jump_cond (enum rtx_code code, enum machine_mode mode, rtx op0,
+record_jump_cond (enum rtx_code code, machine_mode mode, rtx op0,
                  rtx op1, int reversed_nonequality)
 {
   unsigned op0_hash, op1_hash;
@@ -3914,7 +3937,7 @@ record_jump_cond (enum rtx_code code, enum machine_mode mode, rtx op0,
   /* Note that GET_MODE (op0) may not equal MODE.  */
   if (code == EQ && paradoxical_subreg_p (op0))
     {
-      enum machine_mode inner_mode = GET_MODE (SUBREG_REG (op0));
+      machine_mode inner_mode = GET_MODE (SUBREG_REG (op0));
       rtx tem = record_jump_cond_subreg (inner_mode, op1);
       if (tem)
        record_jump_cond (code, mode, SUBREG_REG (op0), tem,
@@ -3923,7 +3946,7 @@ record_jump_cond (enum rtx_code code, enum machine_mode mode, rtx op0,
 
   if (code == EQ && paradoxical_subreg_p (op1))
     {
-      enum machine_mode inner_mode = GET_MODE (SUBREG_REG (op1));
+      machine_mode inner_mode = GET_MODE (SUBREG_REG (op1));
       rtx tem = record_jump_cond_subreg (inner_mode, op0);
       if (tem)
        record_jump_cond (code, mode, SUBREG_REG (op1), tem,
@@ -3942,7 +3965,7 @@ record_jump_cond (enum rtx_code code, enum machine_mode mode, rtx op0,
       && (GET_MODE_SIZE (GET_MODE (op0))
          < GET_MODE_SIZE (GET_MODE (SUBREG_REG (op0)))))
     {
-      enum machine_mode inner_mode = GET_MODE (SUBREG_REG (op0));
+      machine_mode inner_mode = GET_MODE (SUBREG_REG (op0));
       rtx tem = record_jump_cond_subreg (inner_mode, op1);
       if (tem)
        record_jump_cond (code, mode, SUBREG_REG (op0), tem,
@@ -3954,7 +3977,7 @@ record_jump_cond (enum rtx_code code, enum machine_mode mode, rtx op0,
       && (GET_MODE_SIZE (GET_MODE (op1))
          < GET_MODE_SIZE (GET_MODE (SUBREG_REG (op1)))))
     {
-      enum machine_mode inner_mode = GET_MODE (SUBREG_REG (op1));
+      machine_mode inner_mode = GET_MODE (SUBREG_REG (op1));
       rtx tem = record_jump_cond_subreg (inner_mode, op0);
       if (tem)
        record_jump_cond (code, mode, SUBREG_REG (op1), tem,
@@ -4257,7 +4280,7 @@ find_sets_in_insn (rtx_insn *insn, struct set **psets)
     {
       int i, lim = XVECLEN (x, 0);
 
-      /* Go over the epressions of the PARALLEL in forward order, to
+      /* Go over the expressions of the PARALLEL in forward order, to
         put them in the same order in the SETS array.  */
       for (i = 0; i < lim; i++)
        {
@@ -4486,11 +4509,9 @@ cse_insn (rtx_insn *insn)
     sets = XALLOCAVEC (struct set, XVECLEN (x, 0));
 
   this_insn = insn;
-#ifdef HAVE_cc0
   /* Records what this insn does to set CC0.  */
   this_insn_cc0 = 0;
   this_insn_cc0_mode = VOIDmode;
-#endif
 
   /* Find all regs explicitly clobbered in this insn,
      to ensure they are not replaced with any other regs
@@ -4526,7 +4547,7 @@ cse_insn (rtx_insn *insn)
       rtx src, dest;
       rtx src_folded;
       struct table_elt *elt = 0, *p;
-      enum machine_mode mode;
+      machine_mode mode;
       rtx src_eqv_here;
       rtx src_const = 0;
       rtx src_related = 0;
@@ -4558,7 +4579,7 @@ cse_insn (rtx_insn *insn)
 
       if (src_eqv)
        {
-         enum machine_mode eqvmode = mode;
+         machine_mode eqvmode = mode;
          if (GET_CODE (dest) == STRICT_LOW_PART)
            eqvmode = GET_MODE (SUBREG_REG (XEXP (dest, 0)));
          do_not_record = 0;
@@ -4633,12 +4654,27 @@ cse_insn (rtx_insn *insn)
          && REGNO (dest) >= FIRST_PSEUDO_REGISTER)
        sets[i].src_volatile = 1;
 
-      /* Also do not record result of a non-volatile inline asm with
-        more than one result or with clobbers, we do not want CSE to
-        break the inline asm apart.  */
       else if (GET_CODE (src) == ASM_OPERANDS
               && GET_CODE (x) == PARALLEL)
-       sets[i].src_volatile = 1;
+       {
+         /* Do not record result of a non-volatile inline asm with
+            more than one result.  */
+         if (n_sets > 1)
+           sets[i].src_volatile = 1;
+
+         int j, lim = XVECLEN (x, 0);
+         for (j = 0; j < lim; j++)
+           {
+             rtx y = XVECEXP (x, 0, j);
+             /* And do not record result of a non-volatile inline asm
+                with "memory" clobber.  */
+             if (GET_CODE (y) == CLOBBER && MEM_P (XEXP (y, 0)))
+               {
+                 sets[i].src_volatile = 1;
+                 break;
+               }
+           }
+       }
 
 #if 0
       /* It is no longer clear why we used to do this, but it doesn't
@@ -4770,7 +4806,7 @@ cse_insn (rtx_insn *insn)
          && GET_MODE_CLASS (mode) == MODE_INT
          && GET_MODE_PRECISION (mode) < BITS_PER_WORD)
        {
-         enum machine_mode wider_mode;
+         machine_mode wider_mode;
 
          for (wider_mode = GET_MODE_WIDER_MODE (mode);
               wider_mode != VOIDmode
@@ -4804,7 +4840,7 @@ cse_insn (rtx_insn *insn)
          && GET_CODE (src) == AND && CONST_INT_P (XEXP (src, 1))
          && GET_MODE_SIZE (mode) < UNITS_PER_WORD)
        {
-         enum machine_mode tmode;
+         machine_mode tmode;
          rtx new_and = gen_rtx_AND (VOIDmode, NULL_RTX, XEXP (src, 1));
 
          for (tmode = GET_MODE_WIDER_MODE (mode);
@@ -4851,7 +4887,7 @@ cse_insn (rtx_insn *insn)
        {
          struct rtx_def memory_extend_buf;
          rtx memory_extend_rtx = &memory_extend_buf;
-         enum machine_mode tmode;
+         machine_mode tmode;
 
          /* Set what we are trying to extend and the operation it might
             have been extended with.  */
@@ -5229,8 +5265,8 @@ cse_insn (rtx_insn *insn)
            ;
 
          /* Look for a substitution that makes a valid insn.  */
-         else if (validate_unshare_change
-                    (insn, &SET_SRC (sets[i].rtl), trial, 0))
+         else if (validate_unshare_change (insn, &SET_SRC (sets[i].rtl),
+                                           trial, 0))
            {
              rtx new_rtx = canon_reg (SET_SRC (sets[i].rtl), insn);
 
@@ -5444,7 +5480,8 @@ cse_insn (rtx_insn *insn)
             and hope for the best.  */
          if (n_sets == 1)
            {
-             rtx new_rtx, note;
+             rtx_jump_insn *new_rtx;
+             rtx note;
 
              new_rtx = emit_jump_insn_before (gen_jump (XEXP (src, 0)), insn);
              JUMP_LABEL (new_rtx) = XEXP (src, 0);
@@ -5459,7 +5496,7 @@ cse_insn (rtx_insn *insn)
                }
 
              delete_insn_and_edges (insn);
-             insn = as_a <rtx_insn *> (new_rtx);
+             insn = new_rtx;
            }
          else
            INSN_CODE (insn) = -1;
@@ -5474,20 +5511,21 @@ cse_insn (rtx_insn *insn)
 
       else if (do_not_record)
        {
-         if (REG_P (dest) || GET_CODE (dest) == SUBREG)
-           invalidate (dest, VOIDmode);
-         else if (MEM_P (dest))
-           invalidate (dest, VOIDmode);
-         else if (GET_CODE (dest) == STRICT_LOW_PART
-                  || GET_CODE (dest) == ZERO_EXTRACT)
-           invalidate (XEXP (dest, 0), GET_MODE (dest));
+         invalidate_dest (dest);
          sets[i].rtl = 0;
        }
 
       if (sets[i].rtl != 0 && dest != SET_DEST (sets[i].rtl))
-       sets[i].dest_hash = HASH (SET_DEST (sets[i].rtl), mode);
+       {
+         do_not_record = 0;
+         sets[i].dest_hash = HASH (SET_DEST (sets[i].rtl), mode);
+         if (do_not_record)
+           {
+             invalidate_dest (SET_DEST (sets[i].rtl));
+             sets[i].rtl = 0;
+           }
+       }
 
-#ifdef HAVE_cc0
       /* If setting CC0, record what it was set to, or a constant, if it
         is equivalent to a constant.  If it is being set to a floating-point
         value, make a COMPARE with the appropriate constant of 0.  If we
@@ -5502,7 +5540,6 @@ cse_insn (rtx_insn *insn)
            this_insn_cc0 = gen_rtx_COMPARE (VOIDmode, this_insn_cc0,
                                             CONST0_RTX (mode));
        }
-#endif
     }
 
   /* Now enter all non-volatile source expressions in the hash table
@@ -5518,7 +5555,7 @@ cse_insn (rtx_insn *insn)
       struct table_elt *elt;
       struct table_elt *classp = sets[0].src_elt;
       rtx dest = SET_DEST (sets[0].rtl);
-      enum machine_mode eqvmode = GET_MODE (dest);
+      machine_mode eqvmode = GET_MODE (dest);
 
       if (GET_CODE (dest) == STRICT_LOW_PART)
        {
@@ -5564,7 +5601,7 @@ cse_insn (rtx_insn *insn)
            struct table_elt *classp = src_eqv_elt;
            rtx src = sets[i].src;
            rtx dest = SET_DEST (sets[i].rtl);
-           enum machine_mode mode
+           machine_mode mode
              = GET_MODE (src) == VOIDmode ? GET_MODE (dest) : GET_MODE (src);
 
            /* It's possible that we have a source value known to be
@@ -5591,6 +5628,12 @@ cse_insn (rtx_insn *insn)
                  }
                elt = insert (src, classp, sets[i].src_hash, mode);
                elt->in_memory = sets[i].src_in_memory;
+               /* If inline asm has any clobbers, ensure we only reuse
+                  existing inline asms and never try to put the ASM_OPERANDS
+                  into an insn that isn't inline asm.  */
+               if (GET_CODE (src) == ASM_OPERANDS
+                   && GET_CODE (x) == PARALLEL)
+                 elt->cost = MAX_COST;
                sets[i].src_elt = classp = elt;
              }
            if (sets[i].src_const && sets[i].src_const_elt == 0
@@ -5614,7 +5657,7 @@ cse_insn (rtx_insn *insn)
        {
          rtx x = sets[i].inner_dest;
          struct table_elt *elt;
-         enum machine_mode mode;
+         machine_mode mode;
          unsigned hash;
 
          if (MEM_P (x))
@@ -5848,7 +5891,7 @@ cse_insn (rtx_insn *insn)
                >= GET_MODE_SIZE (GET_MODE (SUBREG_REG (dest))))
            && sets[i].src_elt != 0)
          {
-           enum machine_mode new_mode = GET_MODE (SUBREG_REG (dest));
+           machine_mode new_mode = GET_MODE (SUBREG_REG (dest));
            struct table_elt *elt, *classp = 0;
 
            for (elt = sets[i].src_elt->first_same_value; elt;
@@ -5904,6 +5947,9 @@ cse_insn (rtx_insn *insn)
                      }
                    src_elt = insert (new_src, classp, src_hash, new_mode);
                    src_elt->in_memory = elt->in_memory;
+                   if (GET_CODE (new_src) == ASM_OPERANDS
+                       && elt->cost == MAX_COST)
+                     src_elt->cost = MAX_COST;
                  }
                else if (classp && classp != src_elt->first_same_value)
                  /* Show that two things that we've seen before are
@@ -6382,10 +6428,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 (XEXP (x, 0), insn))
-         && LABEL_P (XEXP (x, 0))
-         && INSN_UID (XEXP (x, 0)) != 0
-         && !find_reg_note (insn, REG_LABEL_OPERAND, XEXP (x, 0)))
+             || !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;
@@ -6464,8 +6510,7 @@ cse_extended_basic_block (struct cse_basic_block_data *ebb_data)
                  && check_for_label_ref (insn))
                recorded_label_ref = true;
 
-#ifdef HAVE_cc0
-             if (NONDEBUG_INSN_P (insn))
+             if (HAVE_cc0 && NONDEBUG_INSN_P (insn))
                {
                  /* If the previous insn sets CC0 and this insn no
                     longer references CC0, delete the previous insn.
@@ -6492,7 +6537,6 @@ cse_extended_basic_block (struct cse_basic_block_data *ebb_data)
                      prev_insn_cc0_mode = this_insn_cc0_mode;
                    }
                }
-#endif
            }
        }
 
@@ -6541,11 +6585,9 @@ cse_extended_basic_block (struct cse_basic_block_data *ebb_data)
          record_jump_equiv (insn, taken);
        }
 
-#ifdef HAVE_cc0
       /* Clear the CC0-tracking related insns, they can't provide
         useful information across basic block boundaries.  */
       prev_insn_cc0 = 0;
-#endif
     }
 
   gcc_assert (next_qty <= max_qty);
@@ -6796,21 +6838,17 @@ static bool
 set_live_p (rtx set, rtx_insn *insn ATTRIBUTE_UNUSED, /* Only used with HAVE_cc0.  */
            int *counts)
 {
-#ifdef HAVE_cc0
-  rtx tem;
-#endif
+  rtx_insn *tem;
 
   if (set_noop_p (set))
     ;
 
-#ifdef HAVE_cc0
   else if (GET_CODE (SET_DEST (set)) == CC0
           && !side_effects_p (SET_SRC (set))
           && ((tem = next_nonnote_nondebug_insn (insn)) == NULL_RTX
               || !INSN_P (tem)
               || !reg_referenced_p (cc0_rtx, PATTERN (tem))))
     return false;
-#endif
   else if (!is_dead_reg (SET_DEST (set), counts)
           || side_effects_p (SET_SRC (set)))
     return true;
@@ -6961,6 +6999,12 @@ delete_trivially_dead_insns (rtx_insn *insns, int nreg)
       /* If no debug insns can be present, COUNTS is just an array
         which counts how many times each pseudo is used.  */
     }
+  /* Pseudo PIC register should be considered as used due to possible
+     new usages generated.  */
+  if (!reload_completed
+      && pic_offset_table_rtx
+      && REGNO (pic_offset_table_rtx) >= FIRST_PSEUDO_REGISTER)
+    counts[REGNO (pic_offset_table_rtx)]++;
   /* Go from the last insn to the first and delete insns that only set unused
      registers or copy a register to itself.  As we delete an insn, remove
      usage counts for registers it uses.
@@ -7070,26 +7114,26 @@ delete_trivially_dead_insns (rtx_insn *insns, int nreg)
   return ndead;
 }
 
-/* This function is called via for_each_rtx.  The argument, NEWREG, is
-   a condition code register with the desired mode.  If we are looking
-   at the same register in a different mode, replace it with
-   NEWREG.  */
+/* If LOC contains references to NEWREG in a different mode, change them
+   to use NEWREG instead.  */
 
-static int
-cse_change_cc_mode (rtx *loc, void *data)
+static void
+cse_change_cc_mode (subrtx_ptr_iterator::array_type &array,
+                   rtx *loc, rtx_insn *insn, rtx newreg)
 {
-  struct change_cc_mode_args* args = (struct change_cc_mode_args*)data;
-
-  if (*loc
-      && REG_P (*loc)
-      && REGNO (*loc) == REGNO (args->newreg)
-      && GET_MODE (*loc) != GET_MODE (args->newreg))
+  FOR_EACH_SUBRTX_PTR (iter, array, loc, NONCONST)
     {
-      validate_change (args->insn, loc, args->newreg, 1);
-
-      return -1;
+      rtx *loc = *iter;
+      rtx x = *loc;
+      if (x
+         && REG_P (x)
+         && REGNO (x) == REGNO (newreg)
+         && GET_MODE (x) != GET_MODE (newreg))
+       {
+         validate_change (insn, loc, newreg, 1);
+         iter.skip_subrtxes ();
+       }
     }
-  return 0;
 }
 
 /* Change the mode of any reference to the register REGNO (NEWREG) to
@@ -7098,17 +7142,14 @@ cse_change_cc_mode (rtx *loc, void *data)
 static void
 cse_change_cc_mode_insn (rtx_insn *insn, rtx newreg)
 {
-  struct change_cc_mode_args args;
   int success;
 
   if (!INSN_P (insn))
     return;
 
-  args.insn = insn;
-  args.newreg = newreg;
-
-  for_each_rtx (&PATTERN (insn), cse_change_cc_mode, &args);
-  for_each_rtx (&REG_NOTES (insn), cse_change_cc_mode, &args);
+  subrtx_ptr_iterator::array_type array;
+  cse_change_cc_mode (array, &PATTERN (insn), insn, newreg);
+  cse_change_cc_mode (array, &REG_NOTES (insn), insn, newreg);
 
   /* If the following assertion was triggered, there is most probably
      something wrong with the cc_modes_compatible back end function.
@@ -7155,16 +7196,16 @@ cse_change_cc_mode_insns (rtx_insn *start, rtx_insn *end, rtx newreg)
    We may have more than one duplicate which we can eliminate, and we
    try to find a mode which will work for multiple duplicates.  */
 
-static enum machine_mode
+static machine_mode
 cse_cc_succs (basic_block bb, basic_block orig_bb, rtx cc_reg, rtx cc_src,
              bool can_change_mode)
 {
   bool found_equiv;
-  enum machine_mode mode;
+  machine_mode mode;
   unsigned int insn_count;
   edge e;
   rtx_insn *insns[2];
-  enum machine_mode modes[2];
+  machine_mode modes[2];
   rtx_insn *last_insns[2];
   unsigned int i;
   rtx newreg;
@@ -7213,8 +7254,8 @@ cse_cc_succs (basic_block bb, basic_block orig_bb, rtx cc_reg, rtx cc_src,
              && REGNO (SET_DEST (set)) == REGNO (cc_reg))
            {
              bool found;
-             enum machine_mode set_mode;
-             enum machine_mode comp_mode;
+             machine_mode set_mode;
+             machine_mode comp_mode;
 
              found = false;
              set_mode = GET_MODE (SET_SRC (set));
@@ -7293,7 +7334,7 @@ cse_cc_succs (basic_block bb, basic_block orig_bb, rtx cc_reg, rtx cc_src,
         further blocks and this block.  */
       if (insn == end)
        {
-         enum machine_mode submode;
+         machine_mode submode;
 
          submode = cse_cc_succs (e->dest, orig_bb, cc_reg, cc_src, false);
          if (submode != VOIDmode)
@@ -7364,8 +7405,8 @@ cse_condition_code_reg (void)
       rtx_insn *insn;
       rtx_insn *cc_src_insn;
       rtx cc_src;
-      enum machine_mode mode;
-      enum machine_mode orig_mode;
+      machine_mode mode;
+      machine_mode orig_mode;
 
       /* Look for blocks which end with a conditional jump based on a
         condition code register.  Then look for the instruction which