sem_aux.adb, [...] (Get_Low_Bound): Use Type_Low_Bound.
[gcc.git] / gcc / optabs.c
index 4f3cbb48916e3245f10fb6cb3b5a96e0587ef2fc..49e1c531c65dd95e0f0d040141952071d0d01a4f 100644 (file)
@@ -1,7 +1,5 @@
 /* Expand the basic unary and binary arithmetic operations, for GNU compiler.
-   Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
-   2011, 2012  Free Software Foundation, Inc.
+   Copyright (C) 1987-2015 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -30,22 +28,51 @@ along with GCC; see the file COPYING3.  If not see
    is properly defined.  */
 #include "insn-config.h"
 #include "rtl.h"
+#include "hash-set.h"
+#include "machmode.h"
+#include "vec.h"
+#include "double-int.h"
+#include "input.h"
+#include "alias.h"
+#include "symtab.h"
+#include "wide-int.h"
+#include "inchash.h"
 #include "tree.h"
+#include "tree-hasher.h"
+#include "stor-layout.h"
+#include "stringpool.h"
+#include "varasm.h"
 #include "tm_p.h"
 #include "flags.h"
+#include "hard-reg-set.h"
 #include "function.h"
 #include "except.h"
+#include "hashtab.h"
+#include "statistics.h"
+#include "real.h"
+#include "fixed-value.h"
+#include "expmed.h"
+#include "dojump.h"
+#include "explow.h"
+#include "calls.h"
+#include "emit-rtl.h"
+#include "stmt.h"
 #include "expr.h"
+#include "insn-codes.h"
 #include "optabs.h"
 #include "libfuncs.h"
 #include "recog.h"
 #include "reload.h"
 #include "ggc.h"
+#include "predict.h"
+#include "dominance.h"
+#include "cfg.h"
 #include "basic-block.h"
 #include "target.h"
 
 struct target_optabs default_target_optabs;
 struct target_libfuncs default_target_libfuncs;
+struct target_optabs *this_fn_optabs = &default_target_optabs;
 #if SWITCHABLE_TARGET
 struct target_optabs *this_target_optabs = &default_target_optabs;
 struct target_libfuncs *this_target_libfuncs = &default_target_libfuncs;
@@ -55,9 +82,9 @@ struct target_libfuncs *this_target_libfuncs = &default_target_libfuncs;
   (this_target_libfuncs->x_libfunc_hash)
 
 static void prepare_float_lib_cmp (rtx, rtx, enum rtx_code, rtx *,
-                                  enum machine_mode *);
-static rtx expand_unop_direct (enum machine_mode, optab, rtx, rtx, int);
-static void emit_libcall_block_1 (rtx, rtx, rtx, rtx, bool);
+                                  machine_mode *);
+static rtx expand_unop_direct (machine_mode, optab, rtx, rtx, int);
+static void emit_libcall_block_1 (rtx_insn *, rtx, rtx, rtx, bool);
 
 /* Debug facility for use in GDB.  */
 void debug_optab_libfuncs (void);
@@ -71,20 +98,17 @@ void debug_optab_libfuncs (void);
 \f
 /* Used for libfunc_hash.  */
 
-static hashval_t
-hash_libfunc (const void *p)
+hashval_t
+libfunc_hasher::hash (libfunc_entry *e)
 {
-  const struct libfunc_entry *const e = (const struct libfunc_entry *) p;
   return ((e->mode1 + e->mode2 * NUM_MACHINE_MODES) ^ e->op);
 }
 
 /* Used for libfunc_hash.  */
 
-static int
-eq_libfunc (const void *p, const void *q)
+bool
+libfunc_hasher::equal (libfunc_entry *e1, libfunc_entry *e2)
 {
-  const struct libfunc_entry *const e1 = (const struct libfunc_entry *) p;
-  const struct libfunc_entry *const e2 = (const struct libfunc_entry *) q;
   return e1->op == e2->op && e1->mode1 == e2->mode1 && e1->mode2 == e2->mode2;
 }
 
@@ -92,8 +116,8 @@ eq_libfunc (const void *p, const void *q)
    from MODE2 to MODE1.  Trigger lazy initialization if needed, return NULL
    if no libfunc is available.  */
 rtx
-convert_optab_libfunc (convert_optab optab, enum machine_mode mode1,
-                      enum machine_mode mode2)
+convert_optab_libfunc (convert_optab optab, machine_mode mode1,
+                      machine_mode mode2)
 {
   struct libfunc_entry e;
   struct libfunc_entry **slot;
@@ -107,8 +131,7 @@ convert_optab_libfunc (convert_optab optab, enum machine_mode mode1,
   e.op = optab;
   e.mode1 = mode1;
   e.mode2 = mode2;
-  slot = (struct libfunc_entry **)
-    htab_find_slot (libfunc_hash, &e, NO_INSERT);
+  slot = libfunc_hash->find_slot (&e, NO_INSERT);
   if (!slot)
     {
       const struct convert_optab_libcall_d *d
@@ -118,8 +141,7 @@ convert_optab_libfunc (convert_optab optab, enum machine_mode mode1,
        return NULL;
 
       d->libcall_gen (optab, d->libcall_basename, mode1, mode2);
-      slot = (struct libfunc_entry **)
-       htab_find_slot (libfunc_hash, &e, NO_INSERT);
+      slot = libfunc_hash->find_slot (&e, NO_INSERT);
       if (!slot)
        return NULL;
     }
@@ -130,7 +152,7 @@ convert_optab_libfunc (convert_optab optab, enum machine_mode mode1,
    Trigger lazy initialization if needed, return NULL if no libfunc is
    available.  */
 rtx
-optab_libfunc (optab optab, enum machine_mode mode)
+optab_libfunc (optab optab, machine_mode mode)
 {
   struct libfunc_entry e;
   struct libfunc_entry **slot;
@@ -144,8 +166,7 @@ optab_libfunc (optab optab, enum machine_mode mode)
   e.op = optab;
   e.mode1 = mode;
   e.mode2 = VOIDmode;
-  slot = (struct libfunc_entry **)
-    htab_find_slot (libfunc_hash, &e, NO_INSERT);
+  slot = libfunc_hash->find_slot (&e, NO_INSERT);
   if (!slot)
     {
       const struct optab_libcall_d *d
@@ -155,8 +176,7 @@ optab_libfunc (optab optab, enum machine_mode mode)
        return NULL;
 
       d->libcall_gen (optab, d->libcall_basename, d->libcall_suffix, mode);
-      slot = (struct libfunc_entry **)
-       htab_find_slot (libfunc_hash, &e, NO_INSERT);
+      slot = libfunc_hash->find_slot (&e, NO_INSERT);
       if (!slot)
        return NULL;
     }
@@ -175,9 +195,10 @@ optab_libfunc (optab optab, enum machine_mode mode)
    try again, ensuring that TARGET is not one of the operands.  */
 
 static int
-add_equal_note (rtx insns, rtx target, enum rtx_code code, rtx op0, rtx op1)
+add_equal_note (rtx_insn *insns, rtx target, enum rtx_code code, rtx op0, rtx op1)
 {
-  rtx last_insn, set;
+  rtx_insn *last_insn;
+  rtx set;
   rtx note;
 
   gcc_assert (insns && INSN_P (insns) && NEXT_INSN (insns));
@@ -192,18 +213,41 @@ add_equal_note (rtx insns, rtx target, enum rtx_code code, rtx op0, rtx op1)
   if (GET_CODE (target) == ZERO_EXTRACT)
     return 1;
 
-  /* If TARGET is in OP0 or OP1, punt.  We'd end up with a note referencing
-     a value changing in the insn, so the note would be invalid for CSE.  */
-  if (reg_overlap_mentioned_p (target, op0)
-      || (op1 && reg_overlap_mentioned_p (target, op1)))
-    return 0;
-
   for (last_insn = insns;
        NEXT_INSN (last_insn) != NULL_RTX;
        last_insn = NEXT_INSN (last_insn))
     ;
 
-  set = single_set (last_insn);
+  /* If TARGET is in OP0 or OP1, punt.  We'd end up with a note referencing
+     a value changing in the insn, so the note would be invalid for CSE.  */
+  if (reg_overlap_mentioned_p (target, op0)
+      || (op1 && reg_overlap_mentioned_p (target, op1)))
+    {
+      if (MEM_P (target)
+         && (rtx_equal_p (target, op0)
+             || (op1 && rtx_equal_p (target, op1))))
+       {
+         /* For MEM target, with MEM = MEM op X, prefer no REG_EQUAL note
+            over expanding it as temp = MEM op X, MEM = temp.  If the target
+            supports MEM = MEM op X instructions, it is sometimes too hard
+            to reconstruct that form later, especially if X is also a memory,
+            and due to multiple occurrences of addresses the address might
+            be forced into register unnecessarily.
+            Note that not emitting the REG_EQUIV note might inhibit
+            CSE in some cases.  */
+         set = single_set (last_insn);
+         if (set
+             && GET_CODE (SET_SRC (set)) == code
+             && MEM_P (SET_DEST (set))
+             && (rtx_equal_p (SET_DEST (set), XEXP (SET_SRC (set), 0))
+                 || (op1 && rtx_equal_p (SET_DEST (set),
+                                         XEXP (SET_SRC (set), 1)))))
+           return 1;
+       }
+      return 0;
+    }
+
+  set = set_for_reg_notes (last_insn);
   if (set == NULL_RTX)
     return 1;
 
@@ -252,12 +296,12 @@ add_equal_note (rtx insns, rtx target, enum rtx_code code, rtx op0, rtx op1)
    for a widening operation would be.  In most cases this would be OP0, but if
    that's a constant it'll be VOIDmode, which isn't useful.  */
 
-static enum machine_mode
-widened_mode (enum machine_mode to_mode, rtx op0, rtx op1)
+static machine_mode
+widened_mode (machine_mode to_mode, rtx op0, rtx op1)
 {
-  enum machine_mode m0 = GET_MODE (op0);
-  enum machine_mode m1 = GET_MODE (op1);
-  enum machine_mode result;
+  machine_mode m0 = GET_MODE (op0);
+  machine_mode m1 = GET_MODE (op1);
+  machine_mode result;
 
   if (m0 == VOIDmode && m1 == VOIDmode)
     return to_mode;
@@ -272,6 +316,25 @@ widened_mode (enum machine_mode to_mode, rtx op0, rtx op1)
   return result;
 }
 \f
+/* Like optab_handler, but for widening_operations that have a
+   TO_MODE and a FROM_MODE.  */
+
+enum insn_code
+widening_optab_handler (optab op, machine_mode to_mode,
+                       machine_mode from_mode)
+{
+  unsigned scode = (op << 16) | to_mode;
+  if (to_mode != from_mode && from_mode != VOIDmode)
+    {
+      /* ??? Why does find_widening_optab_handler_and_mode attempt to
+        widen things that can't be widened?  E.g. add_optab... */
+      if (op > LAST_CONV_OPTAB)
+       return CODE_FOR_nothing;
+      scode |= from_mode << 8;
+    }
+  return raw_optab_handler (scode);
+}
+
 /* Find a widening optab even if it doesn't widen as much as we want.
    E.g. if from_mode is HImode, and to_mode is DImode, and there is no
    direct HI->SI insn, then return SI->DI, if that exists.
@@ -279,10 +342,10 @@ widened_mode (enum machine_mode to_mode, rtx op0, rtx op1)
    non-widening optabs also.  */
 
 enum insn_code
-find_widening_optab_handler_and_mode (optab op, enum machine_mode to_mode,
-                                     enum machine_mode from_mode,
+find_widening_optab_handler_and_mode (optab op, machine_mode to_mode,
+                                     machine_mode from_mode,
                                      int permit_non_widening,
-                                     enum machine_mode *found_mode)
+                                     machine_mode *found_mode)
 {
   for (; (permit_non_widening || from_mode != to_mode)
         && GET_MODE_SIZE (from_mode) <= GET_MODE_SIZE (to_mode)
@@ -310,7 +373,7 @@ find_widening_optab_handler_and_mode (optab op, enum machine_mode to_mode,
    of logical operations, but not right shifts.  */
 
 static rtx
-widen_operand (rtx op, enum machine_mode mode, enum machine_mode oldmode,
+widen_operand (rtx op, machine_mode mode, machine_mode oldmode,
               int unsignedp, int no_extend)
 {
   rtx result;
@@ -324,13 +387,13 @@ widen_operand (rtx op, enum machine_mode mode, enum machine_mode oldmode,
      a promoted object differs from our extension.  */
   if (! no_extend
       || (GET_CODE (op) == SUBREG && SUBREG_PROMOTED_VAR_P (op)
-         && SUBREG_PROMOTED_UNSIGNED_P (op) == unsignedp))
+         && SUBREG_CHECK_PROMOTED_SIGN (op, unsignedp)))
     return convert_modes (mode, oldmode, op, unsignedp);
 
-  /* If MODE is no wider than a single word, we return a paradoxical
+  /* If MODE is no wider than a single word, we return a lowpart or paradoxical
      SUBREG.  */
   if (GET_MODE_SIZE (mode) <= UNITS_PER_WORD)
-    return gen_rtx_SUBREG (mode, force_reg (GET_MODE (op), op), 0);
+    return gen_lowpart (mode, force_reg (GET_MODE (op), op));
 
   /* Otherwise, get an object of MODE, clobber it, and set the low-order
      part to OP.  */
@@ -379,8 +442,8 @@ optab_for_tree_code (enum tree_code code, const_tree type,
     case FLOOR_DIV_EXPR:
     case ROUND_DIV_EXPR:
     case EXACT_DIV_EXPR:
-      if (TYPE_SATURATING(type))
-       return TYPE_UNSIGNED(type) ? usdiv_optab : ssdiv_optab;
+      if (TYPE_SATURATING (type))
+       return TYPE_UNSIGNED (type) ? usdiv_optab : ssdiv_optab;
       return TYPE_UNSIGNED (type) ? udiv_optab : sdiv_optab;
 
     case LSHIFT_EXPR:
@@ -391,8 +454,8 @@ optab_for_tree_code (enum tree_code code, const_tree type,
 
          gcc_assert (subtype == optab_scalar);
        }
-      if (TYPE_SATURATING(type))
-       return TYPE_UNSIGNED(type) ? usashl_optab : ssashl_optab;
+      if (TYPE_SATURATING (type))
+       return TYPE_UNSIGNED (type) ? usashl_optab : ssashl_optab;
       return ashl_optab;
 
     case RSHIFT_EXPR:
@@ -440,6 +503,9 @@ optab_for_tree_code (enum tree_code code, const_tree type,
     case DOT_PROD_EXPR:
       return TYPE_UNSIGNED (type) ? udot_prod_optab : sdot_prod_optab;
 
+    case SAD_EXPR:
+      return TYPE_UNSIGNED (type) ? usad_optab : ssad_optab;
+
     case WIDEN_MULT_PLUS_EXPR:
       return (TYPE_UNSIGNED (type)
              ? (TYPE_SATURATING (type)
@@ -458,19 +524,15 @@ optab_for_tree_code (enum tree_code code, const_tree type,
       return fma_optab;
 
     case REDUC_MAX_EXPR:
-      return TYPE_UNSIGNED (type) ? reduc_umax_optab : reduc_smax_optab;
+      return TYPE_UNSIGNED (type)
+            ? reduc_umax_scal_optab : reduc_smax_scal_optab;
 
     case REDUC_MIN_EXPR:
-      return TYPE_UNSIGNED (type) ? reduc_umin_optab : reduc_smin_optab;
+      return TYPE_UNSIGNED (type)
+            ? reduc_umin_scal_optab : reduc_smin_scal_optab;
 
     case REDUC_PLUS_EXPR:
-      return TYPE_UNSIGNED (type) ? reduc_uplus_optab : reduc_splus_optab;
-
-    case VEC_LSHIFT_EXPR:
-      return vec_shl_optab;
-
-    case VEC_RSHIFT_EXPR:
-      return vec_shr_optab;
+      return reduc_plus_scal_optab;
 
     case VEC_WIDEN_MULT_HI_EXPR:
       return TYPE_UNSIGNED (type) ?
@@ -534,23 +596,23 @@ optab_for_tree_code (enum tree_code code, const_tree type,
     {
     case POINTER_PLUS_EXPR:
     case PLUS_EXPR:
-      if (TYPE_SATURATING(type))
-       return TYPE_UNSIGNED(type) ? usadd_optab : ssadd_optab;
+      if (TYPE_SATURATING (type))
+       return TYPE_UNSIGNED (type) ? usadd_optab : ssadd_optab;
       return trapv ? addv_optab : add_optab;
 
     case MINUS_EXPR:
-      if (TYPE_SATURATING(type))
-       return TYPE_UNSIGNED(type) ? ussub_optab : sssub_optab;
+      if (TYPE_SATURATING (type))
+       return TYPE_UNSIGNED (type) ? ussub_optab : sssub_optab;
       return trapv ? subv_optab : sub_optab;
 
     case MULT_EXPR:
-      if (TYPE_SATURATING(type))
-       return TYPE_UNSIGNED(type) ? usmul_optab : ssmul_optab;
+      if (TYPE_SATURATING (type))
+       return TYPE_UNSIGNED (type) ? usmul_optab : ssmul_optab;
       return trapv ? smulv_optab : smul_optab;
 
     case NEGATE_EXPR:
-      if (TYPE_SATURATING(type))
-       return TYPE_UNSIGNED(type) ? usneg_optab : ssneg_optab;
+      if (TYPE_SATURATING (type))
+       return TYPE_UNSIGNED (type) ? usneg_optab : ssneg_optab;
       return trapv ? negv_optab : neg_optab;
 
     case ABS_EXPR:
@@ -560,7 +622,26 @@ optab_for_tree_code (enum tree_code code, const_tree type,
       return unknown_optab;
     }
 }
-\f
+
+/* Given optab UNOPTAB that reduces a vector to a scalar, find instead the old
+   optab that produces a vector with the reduction result in one element,
+   for a tree with type TYPE.  */
+
+optab
+scalar_reduc_to_vector (optab unoptab, const_tree type)
+{
+  switch (unoptab)
+    {
+    case reduc_plus_scal_optab:
+      return TYPE_UNSIGNED (type) ? reduc_uplus_optab : reduc_splus_optab;
+
+    case reduc_smin_scal_optab: return reduc_smin_optab;
+    case reduc_umin_scal_optab: return reduc_umin_optab;
+    case reduc_smax_scal_optab: return reduc_smax_optab;
+    case reduc_umax_scal_optab: return reduc_umax_optab;
+    default: return unknown_optab;
+    }
+}
 
 /* Expand vector widening operations.
 
@@ -588,7 +669,7 @@ expand_widen_pattern_expr (sepops ops, rtx op0, rtx op1, rtx wide_op,
 {
   struct expand_operand eops[4];
   tree oprnd0, oprnd1, oprnd2;
-  enum machine_mode wmode = VOIDmode, tmode0, tmode1 = VOIDmode;
+  machine_mode wmode = VOIDmode, tmode0, tmode1 = VOIDmode;
   optab widen_pattern_optab;
   enum insn_code icode;
   int nops = TREE_CODE_LENGTH (ops->code);
@@ -647,7 +728,7 @@ expand_widen_pattern_expr (sepops ops, rtx op0, rtx op1, rtx wide_op,
    this may or may not be TARGET.  */
 
 rtx
-expand_ternary_op (enum machine_mode mode, optab ternary_optab, rtx op0,
+expand_ternary_op (machine_mode mode, optab ternary_optab, rtx op0,
                   rtx op1, rtx op2, rtx target, int unsignedp)
 {
   struct expand_operand ops[4];
@@ -669,7 +750,7 @@ expand_ternary_op (enum machine_mode mode, optab ternary_optab, rtx op0,
    otherwise the same as for expand_binop.  */
 
 rtx
-simplify_expand_binop (enum machine_mode mode, optab binoptab,
+simplify_expand_binop (machine_mode mode, optab binoptab,
                       rtx op0, rtx op1, rtx target, int unsignedp,
                       enum optab_methods methods)
 {
@@ -688,7 +769,7 @@ simplify_expand_binop (enum machine_mode mode, optab binoptab,
    Return true if the expansion succeeded.  */
 
 bool
-force_expand_binop (enum machine_mode mode, optab binoptab,
+force_expand_binop (machine_mode mode, optab binoptab,
                    rtx op0, rtx op1, rtx target, int unsignedp,
                    enum optab_methods methods)
 {
@@ -701,51 +782,12 @@ force_expand_binop (enum machine_mode mode, optab binoptab,
   return true;
 }
 
-/* Generate insns for VEC_LSHIFT_EXPR, VEC_RSHIFT_EXPR.  */
-
-rtx
-expand_vec_shift_expr (sepops ops, rtx target)
-{
-  struct expand_operand eops[3];
-  enum insn_code icode;
-  rtx rtx_op1, rtx_op2;
-  enum machine_mode mode = TYPE_MODE (ops->type);
-  tree vec_oprnd = ops->op0;
-  tree shift_oprnd = ops->op1;
-  optab shift_optab;
-
-  switch (ops->code)
-    {
-      case VEC_RSHIFT_EXPR:
-       shift_optab = vec_shr_optab;
-       break;
-      case VEC_LSHIFT_EXPR:
-       shift_optab = vec_shl_optab;
-       break;
-      default:
-       gcc_unreachable ();
-    }
-
-  icode = optab_handler (shift_optab, mode);
-  gcc_assert (icode != CODE_FOR_nothing);
-
-  rtx_op1 = expand_normal (vec_oprnd);
-  rtx_op2 = expand_normal (shift_oprnd);
-
-  create_output_operand (&eops[0], target, mode);
-  create_input_operand (&eops[1], rtx_op1, GET_MODE (rtx_op1));
-  create_convert_operand_from_type (&eops[2], rtx_op2, TREE_TYPE (shift_oprnd));
-  expand_insn (icode, 3, eops);
-
-  return eops[0].value;
-}
-
 /* Create a new vector value in VMODE with all elements set to OP.  The
    mode of OP must be the element mode of VMODE.  If OP is a constant,
    then the return value will be a constant.  */
 
 static rtx
-expand_vector_broadcast (enum machine_mode vmode, rtx op)
+expand_vector_broadcast (machine_mode vmode, rtx op)
 {
   enum insn_code icode;
   rtvec vec;
@@ -811,7 +853,7 @@ expand_superword_shift (optab binoptab, rtx outof_input, rtx superword_op1,
    value are the same as for the parent routine.  */
 
 static bool
-expand_subword_shift (enum machine_mode op1_mode, optab binoptab,
+expand_subword_shift (machine_mode op1_mode, optab binoptab,
                      rtx outof_input, rtx into_input, rtx op1,
                      rtx outof_target, rtx into_target,
                      int unsignedp, enum optab_methods methods,
@@ -829,7 +871,8 @@ expand_subword_shift (enum machine_mode op1_mode, optab binoptab,
   if (CONSTANT_P (op1) || shift_mask >= BITS_PER_WORD)
     {
       carries = outof_input;
-      tmp = immed_double_const (BITS_PER_WORD, 0, op1_mode);
+      tmp = immed_wide_int_const (wi::shwi (BITS_PER_WORD,
+                                           op1_mode), op1_mode);
       tmp = simplify_expand_binop (op1_mode, sub_optab, tmp, op1,
                                   0, true, methods);
     }
@@ -844,13 +887,15 @@ expand_subword_shift (enum machine_mode op1_mode, optab binoptab,
                              outof_input, const1_rtx, 0, unsignedp, methods);
       if (shift_mask == BITS_PER_WORD - 1)
        {
-         tmp = immed_double_const (-1, -1, op1_mode);
+         tmp = immed_wide_int_const
+           (wi::minus_one (GET_MODE_PRECISION (op1_mode)), op1_mode);
          tmp = simplify_expand_binop (op1_mode, xor_optab, op1, tmp,
                                       0, true, methods);
        }
       else
        {
-         tmp = immed_double_const (BITS_PER_WORD - 1, 0, op1_mode);
+         tmp = immed_wide_int_const (wi::shwi (BITS_PER_WORD - 1,
+                                               op1_mode), op1_mode);
          tmp = simplify_expand_binop (op1_mode, sub_optab, tmp, op1,
                                       0, true, methods);
        }
@@ -884,7 +929,6 @@ expand_subword_shift (enum machine_mode op1_mode, optab binoptab,
 }
 
 
-#ifdef HAVE_conditional_move
 /* Try implementing expand_doubleword_shift using conditional moves.
    The shift is by < BITS_PER_WORD if (CMP_CODE CMP1 CMP2) is true,
    otherwise it is by >= BITS_PER_WORD.  SUBWORD_OP1 and SUPERWORD_OP1
@@ -892,7 +936,7 @@ expand_subword_shift (enum machine_mode op1_mode, optab binoptab,
    arguments are the same as the parent routine.  */
 
 static bool
-expand_doubleword_shift_condmove (enum machine_mode op1_mode, optab binoptab,
+expand_doubleword_shift_condmove (machine_mode op1_mode, optab binoptab,
                                  enum rtx_code cmp_code, rtx cmp1, rtx cmp2,
                                  rtx outof_input, rtx into_input,
                                  rtx subword_op1, rtx superword_op1,
@@ -944,7 +988,6 @@ expand_doubleword_shift_condmove (enum machine_mode op1_mode, optab binoptab,
 
   return true;
 }
-#endif
 
 /* Expand a doubleword shift (ashl, ashr or lshr) using word-mode shifts.
    OUTOF_INPUT and INTO_INPUT are the two word-sized halves of the first
@@ -976,14 +1019,13 @@ expand_doubleword_shift_condmove (enum machine_mode op1_mode, optab binoptab,
    Return true if the shift could be successfully synthesized.  */
 
 static bool
-expand_doubleword_shift (enum machine_mode op1_mode, optab binoptab,
+expand_doubleword_shift (machine_mode op1_mode, optab binoptab,
                         rtx outof_input, rtx into_input, rtx op1,
                         rtx outof_target, rtx into_target,
                         int unsignedp, enum optab_methods methods,
                         unsigned HOST_WIDE_INT shift_mask)
 {
   rtx superword_op1, tmp, cmp1, cmp2;
-  rtx subword_label, done_label;
   enum rtx_code cmp_code;
 
   /* See if word-mode shifts by BITS_PER_WORD...BITS_PER_WORD * 2 - 1 will
@@ -1013,7 +1055,7 @@ expand_doubleword_shift (enum machine_mode op1_mode, optab binoptab,
      is true when the effective shift value is less than BITS_PER_WORD.
      Set SUPERWORD_OP1 to the shift count that should be used to shift
      OUTOF_INPUT into INTO_TARGET when the condition is false.  */
-  tmp = immed_double_const (BITS_PER_WORD, 0, op1_mode);
+  tmp = immed_wide_int_const (wi::shwi (BITS_PER_WORD, op1_mode), op1_mode);
   if (!CONSTANT_P (op1) && shift_mask == BITS_PER_WORD - 1)
     {
       /* Set CMP1 to OP1 & BITS_PER_WORD.  The result is zero iff OP1
@@ -1052,24 +1094,23 @@ expand_doubleword_shift (enum machine_mode op1_mode, optab binoptab,
                                     unsignedp, methods, shift_mask);
     }
 
-#ifdef HAVE_conditional_move
   /* Try using conditional moves to generate straight-line code.  */
-  {
-    rtx start = get_last_insn ();
-    if (expand_doubleword_shift_condmove (op1_mode, binoptab,
-                                         cmp_code, cmp1, cmp2,
-                                         outof_input, into_input,
-                                         op1, superword_op1,
-                                         outof_target, into_target,
-                                         unsignedp, methods, shift_mask))
-      return true;
-    delete_insns_since (start);
-  }
-#endif
+  if (HAVE_conditional_move)
+    {
+      rtx_insn *start = get_last_insn ();
+      if (expand_doubleword_shift_condmove (op1_mode, binoptab,
+                                           cmp_code, cmp1, cmp2,
+                                           outof_input, into_input,
+                                           op1, superword_op1,
+                                           outof_target, into_target,
+                                           unsignedp, methods, shift_mask))
+       return true;
+      delete_insns_since (start);
+    }
 
   /* As a last resort, use branches to select the correct alternative.  */
-  subword_label = gen_label_rtx ();
-  done_label = gen_label_rtx ();
+  rtx_code_label *subword_label = gen_label_rtx ();
+  rtx_code_label *done_label = gen_label_rtx ();
 
   NO_DEFER_POP;
   do_compare_rtx_and_jump (cmp1, cmp2, cmp_code, false, op1_mode,
@@ -1151,7 +1192,7 @@ expand_doubleword_shift (enum machine_mode op1_mode, optab binoptab,
       the 0 or -1.  */
 
 static rtx
-expand_doubleword_mult (enum machine_mode mode, rtx op0, rtx op1, rtx target,
+expand_doubleword_mult (machine_mode mode, rtx op0, rtx op1, rtx target,
                       bool umulp, enum optab_methods methods)
 {
   int low = (WORDS_BIG_ENDIAN ? 1 : 0);
@@ -1259,7 +1300,7 @@ expand_doubleword_mult (enum machine_mode mode, rtx op0, rtx op1, rtx target,
    the operation to perform, not an optab pointer.  All other
    arguments are the same.  */
 rtx
-expand_simple_binop (enum machine_mode mode, enum rtx_code code, rtx op0,
+expand_simple_binop (machine_mode mode, enum rtx_code code, rtx op0,
                     rtx op1, rtx target, int unsignedp,
                     enum optab_methods methods)
 {
@@ -1331,7 +1372,7 @@ commutative_optab_p (optab binoptab)
    register.  Return X otherwise.  UNSIGNEDP says whether X is unsigned.  */
 
 static rtx
-avoid_expensive_constant (enum machine_mode mode, optab binoptab,
+avoid_expensive_constant (machine_mode mode, optab binoptab,
                          int opn, rtx x, bool unsignedp)
 {
   bool speed = optimize_insn_for_speed_p ();
@@ -1359,22 +1400,21 @@ avoid_expensive_constant (enum machine_mode mode, optab binoptab,
    is an insn that directly implements the indicated operation.
    Returns null if this is not possible.  */
 static rtx
-expand_binop_directly (enum machine_mode mode, optab binoptab,
+expand_binop_directly (machine_mode mode, optab binoptab,
                       rtx op0, rtx op1,
                       rtx target, int unsignedp, enum optab_methods methods,
-                      rtx last)
+                      rtx_insn *last)
 {
-  enum machine_mode from_mode = widened_mode (mode, op0, op1);
+  machine_mode from_mode = widened_mode (mode, op0, op1);
   enum insn_code icode = find_widening_optab_handler (binoptab, mode,
                                                      from_mode, 1);
-  enum machine_mode xmode0 = insn_data[(int) icode].operand[1].mode;
-  enum machine_mode xmode1 = insn_data[(int) icode].operand[2].mode;
-  enum machine_mode mode0, mode1, tmp_mode;
+  machine_mode xmode0 = insn_data[(int) icode].operand[1].mode;
+  machine_mode xmode1 = insn_data[(int) icode].operand[2].mode;
+  machine_mode mode0, mode1, tmp_mode;
   struct expand_operand ops[3];
   bool commutative_p;
-  rtx pat;
+  rtx_insn *pat;
   rtx xop0 = op0, xop1 = op1;
-  rtx swap;
 
   /* If it is a commutative operator and the modes would match
      if we would swap the operands, we can save the conversions.  */
@@ -1382,11 +1422,7 @@ expand_binop_directly (enum machine_mode mode, optab binoptab,
   if (commutative_p
       && GET_MODE (xop0) != xmode0 && GET_MODE (xop1) != xmode1
       && GET_MODE (xop0) == xmode1 && GET_MODE (xop1) == xmode1)
-    {
-      swap = xop0;
-      xop0 = xop1;
-      xop1 = swap;
-    }
+    std::swap (xop0, xop1);
 
   /* If we are optimizing, force expensive constants into a register.  */
   xop0 = avoid_expensive_constant (xmode0, binoptab, 0, xop0, unsignedp);
@@ -1419,11 +1455,7 @@ expand_binop_directly (enum machine_mode mode, optab binoptab,
      Also try to make the last operand a constant.  */
   if (commutative_p
       && swap_commutative_operands_with_target (target, xop0, xop1))
-    {
-      swap = xop1;
-      xop1 = xop0;
-      xop0 = swap;
-    }
+    std::swap (xop0, xop1);
 
   /* Now, if insn's predicates don't allow our operands, put them into
      pseudo regs.  */
@@ -1456,7 +1488,8 @@ expand_binop_directly (enum machine_mode mode, optab binoptab,
         REG_EQUAL note to it.  If we can't because TEMP conflicts with an
         operand, call expand_binop again, this time without a target.  */
       if (INSN_P (pat) && NEXT_INSN (pat) != NULL_RTX
-         && ! add_equal_note (pat, ops[0].value, optab_to_code (binoptab),
+         && ! add_equal_note (pat, ops[0].value,
+                              optab_to_code (binoptab),
                               ops[1].value, ops[2].value))
        {
          delete_insns_since (last);
@@ -1483,18 +1516,18 @@ expand_binop_directly (enum machine_mode mode, optab binoptab,
    this may or may not be TARGET.  */
 
 rtx
-expand_binop (enum machine_mode mode, optab binoptab, rtx op0, rtx op1,
+expand_binop (machine_mode mode, optab binoptab, rtx op0, rtx op1,
              rtx target, int unsignedp, enum optab_methods methods)
 {
   enum optab_methods next_methods
     = (methods == OPTAB_LIB || methods == OPTAB_LIB_WIDEN
        ? OPTAB_WIDEN : methods);
   enum mode_class mclass;
-  enum machine_mode wider_mode;
+  machine_mode wider_mode;
   rtx libfunc;
   rtx temp;
-  rtx entry_last = get_last_insn ();
-  rtx last;
+  rtx_insn *entry_last = get_last_insn ();
+  rtx_insn *last;
 
   mclass = GET_MODE_CLASS (mode);
 
@@ -1541,7 +1574,7 @@ expand_binop (enum machine_mode mode, optab binoptab, rtx op0, rtx op1,
         newop1 = negate_rtx (GET_MODE (op1), op1);
       else
         newop1 = expand_binop (GET_MODE (op1), sub_optab,
-                              GEN_INT (bits), op1,
+                              gen_int_mode (bits, GET_MODE (op1)), op1,
                               NULL_RTX, unsignedp, OPTAB_DIRECT);
 
       temp = expand_binop_directly (mode, otheroptab, op0, newop1,
@@ -1677,11 +1710,7 @@ expand_binop (enum machine_mode mode, optab binoptab, rtx op0, rtx op1,
      Also try to make the last operand a constant.  */
   if (commutative_optab_p (binoptab)
       && swap_commutative_operands_with_target (target, op0, op1))
-    {
-      temp = op1;
-      op1 = op0;
-      op0 = temp;
-    }
+    std::swap (op0, op1);
 
   /* These can be done a word at a time.  */
   if ((binoptab == and_optab || binoptab == ior_optab || binoptab == xor_optab)
@@ -1690,7 +1719,7 @@ expand_binop (enum machine_mode mode, optab binoptab, rtx op0, rtx op1,
       && optab_handler (binoptab, word_mode) != CODE_FOR_nothing)
     {
       int i;
-      rtx insns;
+      rtx_insn *insns;
 
       /* If TARGET is the same as one of the operands, the REG_EQUAL note
         won't be accurate, so use a new target.  */
@@ -1740,7 +1769,7 @@ expand_binop (enum machine_mode mode, optab binoptab, rtx op0, rtx op1,
       && optab_handler (lshr_optab, word_mode) != CODE_FOR_nothing)
     {
       unsigned HOST_WIDE_INT shift_mask, double_shift_mask;
-      enum machine_mode op1_mode;
+      machine_mode op1_mode;
 
       double_shift_mask = targetm.shift_truncation_mask (mode);
       shift_mask = targetm.shift_truncation_mask (word_mode);
@@ -1759,7 +1788,7 @@ expand_binop (enum machine_mode mode, optab binoptab, rtx op0, rtx op1,
          || (shift_mask == BITS_PER_WORD - 1
              && double_shift_mask == BITS_PER_WORD * 2 - 1))
        {
-         rtx insns;
+         rtx_insn *insns;
          rtx into_target, outof_target;
          rtx into_input, outof_input;
          int left_shift, outof_word;
@@ -1811,7 +1840,7 @@ expand_binop (enum machine_mode mode, optab binoptab, rtx op0, rtx op1,
       && optab_handler (ashl_optab, word_mode) != CODE_FOR_nothing
       && optab_handler (lshr_optab, word_mode) != CODE_FOR_nothing)
     {
-      rtx insns;
+      rtx_insn *insns;
       rtx into_target, outof_target;
       rtx into_input, outof_input;
       rtx inter;
@@ -2096,9 +2125,9 @@ expand_binop (enum machine_mode mode, optab binoptab, rtx op0, rtx op1,
   if (libfunc
       && (methods == OPTAB_LIB || methods == OPTAB_LIB_WIDEN))
     {
-      rtx insns;
+      rtx_insn *insns;
       rtx op1x = op1;
-      enum machine_mode op1_mode = mode;
+      machine_mode op1_mode = mode;
       rtx value;
 
       start_sequence ();
@@ -2218,7 +2247,7 @@ expand_binop (enum machine_mode mode, optab binoptab, rtx op0, rtx op1,
    of an unsigned wider operation, since the result would be the same.  */
 
 rtx
-sign_expand_binop (enum machine_mode mode, optab uoptab, optab soptab,
+sign_expand_binop (machine_mode mode, optab uoptab, optab soptab,
                   rtx op0, rtx op1, rtx target, int unsignedp,
                   enum optab_methods methods)
 {
@@ -2281,11 +2310,11 @@ int
 expand_twoval_unop (optab unoptab, rtx op0, rtx targ0, rtx targ1,
                    int unsignedp)
 {
-  enum machine_mode mode = GET_MODE (targ0 ? targ0 : targ1);
+  machine_mode mode = GET_MODE (targ0 ? targ0 : targ1);
   enum mode_class mclass;
-  enum machine_mode wider_mode;
-  rtx entry_last = get_last_insn ();
-  rtx last;
+  machine_mode wider_mode;
+  rtx_insn *entry_last = get_last_insn ();
+  rtx_insn *last;
 
   mclass = GET_MODE_CLASS (mode);
 
@@ -2355,11 +2384,11 @@ int
 expand_twoval_binop (optab binoptab, rtx op0, rtx op1, rtx targ0, rtx targ1,
                     int unsignedp)
 {
-  enum machine_mode mode = GET_MODE (targ0 ? targ0 : targ1);
+  machine_mode mode = GET_MODE (targ0 ? targ0 : targ1);
   enum mode_class mclass;
-  enum machine_mode wider_mode;
-  rtx entry_last = get_last_insn ();
-  rtx last;
+  machine_mode wider_mode;
+  rtx_insn *entry_last = get_last_insn ();
+  rtx_insn *last;
 
   mclass = GET_MODE_CLASS (mode);
 
@@ -2375,8 +2404,8 @@ expand_twoval_binop (optab binoptab, rtx op0, rtx op1, rtx targ0, rtx targ1,
     {
       struct expand_operand ops[4];
       enum insn_code icode = optab_handler (binoptab, mode);
-      enum machine_mode mode0 = insn_data[icode].operand[1].mode;
-      enum machine_mode mode1 = insn_data[icode].operand[2].mode;
+      machine_mode mode0 = insn_data[icode].operand[1].mode;
+      machine_mode mode1 = insn_data[icode].operand[2].mode;
       rtx xop0 = op0, xop1 = op1;
 
       /* If we are optimizing, force expensive constants into a register.  */
@@ -2437,10 +2466,10 @@ bool
 expand_twoval_binop_libfunc (optab binoptab, rtx op0, rtx op1,
                             rtx targ0, rtx targ1, enum rtx_code code)
 {
-  enum machine_mode mode;
-  enum machine_mode libval_mode;
+  machine_mode mode;
+  machine_mode libval_mode;
   rtx libval;
-  rtx insns;
+  rtx_insn *insns;
   rtx libfunc;
 
   /* Exactly one of TARG0 or TARG1 should be non-NULL.  */
@@ -2477,7 +2506,7 @@ expand_twoval_binop_libfunc (optab binoptab, rtx op0, rtx op1,
    the operation to perform, not an optab pointer.  All other
    arguments are the same.  */
 rtx
-expand_simple_unop (enum machine_mode mode, enum rtx_code code, rtx op0,
+expand_simple_unop (machine_mode mode, enum rtx_code code, rtx op0,
                    rtx target, int unsignedp)
 {
   optab unop = code_to_optab (code);
@@ -2494,19 +2523,20 @@ expand_simple_unop (enum machine_mode mode, enum rtx_code code, rtx op0,
    A similar operation can be used for clrsb.  UNOPTAB says which operation
    we are trying to expand.  */
 static rtx
-widen_leading (enum machine_mode mode, rtx op0, rtx target, optab unoptab)
+widen_leading (machine_mode mode, rtx op0, rtx target, optab unoptab)
 {
   enum mode_class mclass = GET_MODE_CLASS (mode);
   if (CLASS_HAS_WIDER_MODES_P (mclass))
     {
-      enum machine_mode wider_mode;
+      machine_mode wider_mode;
       for (wider_mode = GET_MODE_WIDER_MODE (mode);
           wider_mode != VOIDmode;
           wider_mode = GET_MODE_WIDER_MODE (wider_mode))
        {
          if (optab_handler (unoptab, wider_mode) != CODE_FOR_nothing)
            {
-             rtx xop0, temp, last;
+             rtx xop0, temp;
+             rtx_insn *last;
 
              last = get_last_insn ();
 
@@ -2517,10 +2547,12 @@ widen_leading (enum machine_mode mode, rtx op0, rtx target, optab unoptab)
              temp = expand_unop (wider_mode, unoptab, xop0, NULL_RTX,
                                  unoptab != clrsb_optab);
              if (temp != 0)
-               temp = expand_binop (wider_mode, sub_optab, temp,
-                                    GEN_INT (GET_MODE_PRECISION (wider_mode)
-                                             - GET_MODE_PRECISION (mode)),
-                                    target, true, OPTAB_DIRECT);
+               temp = expand_binop
+                 (wider_mode, sub_optab, temp,
+                  gen_int_mode (GET_MODE_PRECISION (wider_mode)
+                                - GET_MODE_PRECISION (mode),
+                                wider_mode),
+                  target, true, OPTAB_DIRECT);
              if (temp == 0)
                delete_insns_since (last);
 
@@ -2534,14 +2566,15 @@ widen_leading (enum machine_mode mode, rtx op0, rtx target, optab unoptab)
 /* Try calculating clz of a double-word quantity as two clz's of word-sized
    quantities, choosing which based on whether the high word is nonzero.  */
 static rtx
-expand_doubleword_clz (enum machine_mode mode, rtx op0, rtx target)
+expand_doubleword_clz (machine_mode mode, rtx op0, rtx target)
 {
   rtx xop0 = force_reg (mode, op0);
   rtx subhi = gen_highpart (word_mode, xop0);
   rtx sublo = gen_lowpart (word_mode, xop0);
-  rtx hi0_label = gen_label_rtx ();
-  rtx after_label = gen_label_rtx ();
-  rtx seq, temp, result;
+  rtx_code_label *hi0_label = gen_label_rtx ();
+  rtx_code_label *after_label = gen_label_rtx ();
+  rtx_insn *seq;
+  rtx temp, result;
 
   /* If we were not given a target, use a word_mode register, not a
      'mode' register.  The result will fit, and nobody is expecting
@@ -2579,7 +2612,7 @@ expand_doubleword_clz (enum machine_mode mode, rtx op0, rtx target)
   if (!temp)
     goto fail;
   temp = expand_binop (word_mode, add_optab, temp,
-                      GEN_INT (GET_MODE_BITSIZE (word_mode)),
+                      gen_int_mode (GET_MODE_BITSIZE (word_mode), word_mode),
                       result, true, OPTAB_DIRECT);
   if (!temp)
     goto fail;
@@ -2606,11 +2639,12 @@ expand_doubleword_clz (enum machine_mode mode, rtx op0, rtx target)
    as
        (lshiftrt:wide (bswap:wide x) ((width wide) - (width narrow))).  */
 static rtx
-widen_bswap (enum machine_mode mode, rtx op0, rtx target)
+widen_bswap (machine_mode mode, rtx op0, rtx target)
 {
   enum mode_class mclass = GET_MODE_CLASS (mode);
-  enum machine_mode wider_mode;
-  rtx x, last;
+  machine_mode wider_mode;
+  rtx x;
+  rtx_insn *last;
 
   if (!CLASS_HAS_WIDER_MODES_P (mclass))
     return NULL_RTX;
@@ -2651,7 +2685,7 @@ widen_bswap (enum machine_mode mode, rtx op0, rtx target)
 /* Try calculating bswap as two bswaps of two word-sized operands.  */
 
 static rtx
-expand_doubleword_bswap (enum machine_mode mode, rtx op, rtx target)
+expand_doubleword_bswap (machine_mode mode, rtx op, rtx target)
 {
   rtx t0, t1;
 
@@ -2673,18 +2707,19 @@ expand_doubleword_bswap (enum machine_mode mode, rtx op, rtx target)
 /* Try calculating (parity x) as (and (popcount x) 1), where
    popcount can also be done in a wider mode.  */
 static rtx
-expand_parity (enum machine_mode mode, rtx op0, rtx target)
+expand_parity (machine_mode mode, rtx op0, rtx target)
 {
   enum mode_class mclass = GET_MODE_CLASS (mode);
   if (CLASS_HAS_WIDER_MODES_P (mclass))
     {
-      enum machine_mode wider_mode;
+      machine_mode wider_mode;
       for (wider_mode = mode; wider_mode != VOIDmode;
           wider_mode = GET_MODE_WIDER_MODE (wider_mode))
        {
          if (optab_handler (popcount_optab, wider_mode) != CODE_FOR_nothing)
            {
-             rtx xop0, temp, last;
+             rtx xop0, temp;
+             rtx_insn *last;
 
              last = get_last_insn ();
 
@@ -2719,9 +2754,10 @@ expand_parity (enum machine_mode mode, rtx op0, rtx target)
    less convenient for expand_ffs anyway.  */
 
 static rtx
-expand_ctz (enum machine_mode mode, rtx op0, rtx target)
+expand_ctz (machine_mode mode, rtx op0, rtx target)
 {
-  rtx seq, temp;
+  rtx_insn *seq;
+  rtx temp;
 
   if (optab_handler (clz_optab, mode) == CODE_FOR_nothing)
     return 0;
@@ -2735,7 +2771,8 @@ expand_ctz (enum machine_mode mode, rtx op0, rtx target)
   if (temp)
     temp = expand_unop_direct (mode, clz_optab, temp, NULL_RTX, true);
   if (temp)
-    temp = expand_binop (mode, sub_optab, GEN_INT (GET_MODE_PRECISION (mode) - 1),
+    temp = expand_binop (mode, sub_optab,
+                        gen_int_mode (GET_MODE_PRECISION (mode) - 1, mode),
                         temp, target,
                         true, OPTAB_DIRECT);
   if (temp == 0)
@@ -2760,11 +2797,12 @@ expand_ctz (enum machine_mode mode, rtx op0, rtx target)
    may have an undefined value in that case.  If they do not give us a
    convenient value, we have to generate a test and branch.  */
 static rtx
-expand_ffs (enum machine_mode mode, rtx op0, rtx target)
+expand_ffs (machine_mode mode, rtx op0, rtx target)
 {
   HOST_WIDE_INT val = 0;
   bool defined_at_zero = false;
-  rtx temp, seq;
+  rtx temp;
+  rtx_insn *seq;
 
   if (optab_handler (ctz_optab, mode) != CODE_FOR_nothing)
     {
@@ -2806,7 +2844,7 @@ expand_ffs (enum machine_mode mode, rtx op0, rtx target)
         the operation sets condition codes that can be recycled for this.
         (This is true on i386, for instance.)  */
 
-      rtx nonzero_label = gen_label_rtx ();
+      rtx_code_label *nonzero_label = gen_label_rtx ();
       emit_cmp_and_jump_insns (op0, CONST0_RTX (mode), NE, 0,
                               mode, true, nonzero_label);
 
@@ -2816,7 +2854,7 @@ expand_ffs (enum machine_mode mode, rtx op0, rtx target)
 
   /* temp now has a value in the range -1..bitsize-1.  ffs is supposed
      to produce a value in the range 0..bitsize.  */
-  temp = expand_binop (mode, add_optab, temp, GEN_INT (1),
+  temp = expand_binop (mode, add_optab, temp, gen_int_mode (1, mode),
                       target, false, OPTAB_DIRECT);
   if (!temp)
     goto fail;
@@ -2839,8 +2877,8 @@ expand_ffs (enum machine_mode mode, rtx op0, rtx target)
    register will work around the situation.  */
 
 static rtx
-lowpart_subreg_maybe_copy (enum machine_mode omode, rtx val,
-                          enum machine_mode imode)
+lowpart_subreg_maybe_copy (machine_mode omode, rtx val,
+                          machine_mode imode)
 {
   rtx ret;
   ret = lowpart_subreg (omode, val, imode);
@@ -2857,14 +2895,14 @@ lowpart_subreg_maybe_copy (enum machine_mode omode, rtx val,
    logical operation on the sign bit.  */
 
 static rtx
-expand_absneg_bit (enum rtx_code code, enum machine_mode mode,
+expand_absneg_bit (enum rtx_code code, machine_mode mode,
                   rtx op0, rtx target)
 {
   const struct real_format *fmt;
   int bitpos, word, nwords, i;
-  enum machine_mode imode;
-  double_int mask;
-  rtx temp, insns;
+  machine_mode imode;
+  rtx temp;
+  rtx_insn *insns;
 
   /* The format has to have a simple sign bit.  */
   fmt = REAL_MODE_FORMAT (mode);
@@ -2899,7 +2937,7 @@ expand_absneg_bit (enum rtx_code code, enum machine_mode mode,
       nwords = (GET_MODE_BITSIZE (mode) + BITS_PER_WORD - 1) / BITS_PER_WORD;
     }
 
-  mask = double_int_zero.set_bit (bitpos);
+  wide_int mask = wi::set_bit_in_zero (bitpos, GET_MODE_PRECISION (imode));
   if (code == ABS)
     mask = ~mask;
 
@@ -2921,7 +2959,7 @@ expand_absneg_bit (enum rtx_code code, enum machine_mode mode,
            {
              temp = expand_binop (imode, code == ABS ? and_optab : xor_optab,
                                   op0_piece,
-                                  immed_double_int_const (mask, imode),
+                                  immed_wide_int_const (mask, imode),
                                   targ_piece, 1, OPTAB_LIB_WIDEN);
              if (temp != targ_piece)
                emit_move_insn (targ_piece, temp);
@@ -2939,7 +2977,7 @@ expand_absneg_bit (enum rtx_code code, enum machine_mode mode,
     {
       temp = expand_binop (imode, code == ABS ? and_optab : xor_optab,
                           gen_lowpart (imode, op0),
-                          immed_double_int_const (mask, imode),
+                          immed_wide_int_const (mask, imode),
                           gen_lowpart (imode, target), 1, OPTAB_LIB_WIDEN);
       target = lowpart_subreg_maybe_copy (mode, temp, imode);
 
@@ -2954,15 +2992,15 @@ expand_absneg_bit (enum rtx_code code, enum machine_mode mode,
 /* As expand_unop, but will fail rather than attempt the operation in a
    different mode or with a libcall.  */
 static rtx
-expand_unop_direct (enum machine_mode mode, optab unoptab, rtx op0, rtx target,
+expand_unop_direct (machine_mode mode, optab unoptab, rtx op0, rtx target,
             int unsignedp)
 {
   if (optab_handler (unoptab, mode) != CODE_FOR_nothing)
     {
       struct expand_operand ops[2];
       enum insn_code icode = optab_handler (unoptab, mode);
-      rtx last = get_last_insn ();
-      rtx pat;
+      rtx_insn *last = get_last_insn ();
+      rtx_insn *pat;
 
       create_output_operand (&ops[0], target, mode);
       create_convert_operand_from (&ops[1], op0, mode, unsignedp);
@@ -2970,7 +3008,8 @@ expand_unop_direct (enum machine_mode mode, optab unoptab, rtx op0, rtx target,
       if (pat)
        {
          if (INSN_P (pat) && NEXT_INSN (pat) != NULL_RTX
-             && ! add_equal_note (pat, ops[0].value, optab_to_code (unoptab),
+             && ! add_equal_note (pat, ops[0].value,
+                                  optab_to_code (unoptab),
                                   ops[1].value, NULL_RTX))
            {
              delete_insns_since (last);
@@ -2997,11 +3036,11 @@ expand_unop_direct (enum machine_mode mode, optab unoptab, rtx op0, rtx target,
    this may or may not be TARGET.  */
 
 rtx
-expand_unop (enum machine_mode mode, optab unoptab, rtx op0, rtx target,
+expand_unop (machine_mode mode, optab unoptab, rtx op0, rtx target,
             int unsignedp)
 {
   enum mode_class mclass = GET_MODE_CLASS (mode);
-  enum machine_mode wider_mode;
+  machine_mode wider_mode;
   rtx temp;
   rtx libfunc;
 
@@ -3046,7 +3085,8 @@ expand_unop (enum machine_mode mode, optab unoptab, rtx op0, rtx target,
         be always more efficient than the other fallback methods.  */
       if (mode == HImode)
        {
-         rtx last, temp1, temp2;
+         rtx_insn *last;
+         rtx temp1, temp2;
 
          if (optab_handler (rotl_optab, mode) != CODE_FOR_nothing)
            {
@@ -3104,7 +3144,7 @@ expand_unop (enum machine_mode mode, optab unoptab, rtx op0, rtx target,
        if (optab_handler (unoptab, wider_mode) != CODE_FOR_nothing)
          {
            rtx xop0 = op0;
-           rtx last = get_last_insn ();
+           rtx_insn *last = get_last_insn ();
 
            /* For certain operations, we need not actually extend
               the narrow operand, as long as we will truncate the
@@ -3143,7 +3183,7 @@ expand_unop (enum machine_mode mode, optab unoptab, rtx op0, rtx target,
       && optab_handler (unoptab, word_mode) != CODE_FOR_nothing)
     {
       int i;
-      rtx insns;
+      rtx_insn *insns;
 
       if (target == 0 || target == op0 || !valid_multiword_target_p (target))
        target = gen_reg_rtx (mode);
@@ -3221,10 +3261,10 @@ expand_unop (enum machine_mode mode, optab unoptab, rtx op0, rtx target,
   libfunc = optab_libfunc (unoptab, mode);
   if (libfunc)
     {
-      rtx insns;
+      rtx_insn *insns;
       rtx value;
       rtx eq_value;
-      enum machine_mode outmode = mode;
+      machine_mode outmode = mode;
 
       /* All of these functions return small values.  Thus we choose to
         have them return something that isn't a double-word.  */
@@ -3268,7 +3308,7 @@ expand_unop (enum machine_mode mode, optab unoptab, rtx op0, rtx target,
              || optab_libfunc (unoptab, wider_mode))
            {
              rtx xop0 = op0;
-             rtx last = get_last_insn ();
+             rtx_insn *last = get_last_insn ();
 
              /* For certain operations, we need not actually extend
                 the narrow operand, as long as we will truncate the
@@ -3286,10 +3326,12 @@ expand_unop (enum machine_mode mode, optab unoptab, rtx op0, rtx target,
                 result.  Similarly for clrsb.  */
              if ((unoptab == clz_optab || unoptab == clrsb_optab)
                  && temp != 0)
-               temp = expand_binop (wider_mode, sub_optab, temp,
-                                    GEN_INT (GET_MODE_PRECISION (wider_mode)
-                                             - GET_MODE_PRECISION (mode)),
-                                    target, true, OPTAB_DIRECT);
+               temp = expand_binop
+                 (wider_mode, sub_optab, temp,
+                  gen_int_mode (GET_MODE_PRECISION (wider_mode)
+                                - GET_MODE_PRECISION (mode),
+                                wider_mode),
+                  target, true, OPTAB_DIRECT);
 
              /* Likewise for bswap.  */
              if (unoptab == bswap_optab && temp != 0)
@@ -3349,12 +3391,13 @@ expand_unop (enum machine_mode mode, optab unoptab, rtx op0, rtx target,
  */
 
 rtx
-expand_abs_nojump (enum machine_mode mode, rtx op0, rtx target,
+expand_abs_nojump (machine_mode mode, rtx op0, rtx target,
                   int result_unsignedp)
 {
   rtx temp;
 
-  if (! flag_trapv)
+  if (GET_MODE_CLASS (mode) != MODE_INT
+      || ! flag_trapv)
     result_unsignedp = 1;
 
   /* First try to do it with a special abs instruction.  */
@@ -3375,9 +3418,10 @@ expand_abs_nojump (enum machine_mode mode, rtx op0, rtx target,
   if (optab_handler (smax_optab, mode) != CODE_FOR_nothing
       && !HONOR_SIGNED_ZEROS (mode))
     {
-      rtx last = get_last_insn ();
+      rtx_insn *last = get_last_insn ();
 
-      temp = expand_unop (mode, neg_optab, op0, NULL_RTX, 0);
+      temp = expand_unop (mode, result_unsignedp ? neg_optab : negv_optab,
+                         op0, NULL_RTX, 0);
       if (temp != 0)
        temp = expand_binop (mode, smax_optab, op0, temp, target, 0,
                             OPTAB_WIDEN);
@@ -3414,12 +3458,14 @@ expand_abs_nojump (enum machine_mode mode, rtx op0, rtx target,
 }
 
 rtx
-expand_abs (enum machine_mode mode, rtx op0, rtx target,
+expand_abs (machine_mode mode, rtx op0, rtx target,
            int result_unsignedp, int safe)
 {
-  rtx temp, op1;
+  rtx temp;
+  rtx_code_label *op1;
 
-  if (! flag_trapv)
+  if (GET_MODE_CLASS (mode) != MODE_INT
+      || ! flag_trapv)
     result_unsignedp = 1;
 
   temp = expand_abs_nojump (mode, op0, target, result_unsignedp);
@@ -3446,7 +3492,7 @@ expand_abs (enum machine_mode mode, rtx op0, rtx target,
   NO_DEFER_POP;
 
   do_compare_rtx_and_jump (target, CONST0_RTX (mode), GE, 0, mode,
-                          NULL_RTX, NULL_RTX, op1, -1);
+                          NULL_RTX, NULL, op1, -1);
 
   op0 = expand_unop (mode, result_unsignedp ? neg_optab : negv_optab,
                      target, target, 0);
@@ -3466,7 +3512,7 @@ expand_abs (enum machine_mode mode, rtx op0, rtx target,
    different but can be deduced from MODE.  */
 
 rtx
-expand_one_cmpl_abs_nojump (enum machine_mode mode, rtx op0, rtx target)
+expand_one_cmpl_abs_nojump (machine_mode mode, rtx op0, rtx target)
 {
   rtx temp;
 
@@ -3477,7 +3523,7 @@ expand_one_cmpl_abs_nojump (enum machine_mode mode, rtx op0, rtx target)
   /* If we have a MAX insn, we can do this as MAX (x, ~x).  */
   if (optab_handler (smax_optab, mode) != CODE_FOR_nothing)
     {
-      rtx last = get_last_insn ();
+      rtx_insn *last = get_last_insn ();
 
       temp = expand_unop (mode, one_cmpl_optab, op0, NULL_RTX, 0);
       if (temp != 0)
@@ -3517,12 +3563,13 @@ expand_one_cmpl_abs_nojump (enum machine_mode mode, rtx op0, rtx target)
    and not playing with subregs so much, will help the register allocator.  */
 
 static rtx
-expand_copysign_absneg (enum machine_mode mode, rtx op0, rtx op1, rtx target,
+expand_copysign_absneg (machine_mode mode, rtx op0, rtx op1, rtx target,
                        int bitpos, bool op0_is_abs)
 {
-  enum machine_mode imode;
+  machine_mode imode;
   enum insn_code icode;
-  rtx sign, label;
+  rtx sign;
+  rtx_code_label *label;
 
   if (target == op1)
     target = NULL_RTX;
@@ -3538,8 +3585,6 @@ expand_copysign_absneg (enum machine_mode mode, rtx op0, rtx op1, rtx target,
     }
   else
     {
-      double_int mask;
-
       if (GET_MODE_SIZE (mode) <= UNITS_PER_WORD)
        {
          imode = int_mode_for_mode (mode);
@@ -3560,10 +3605,9 @@ expand_copysign_absneg (enum machine_mode mode, rtx op0, rtx op1, rtx target,
          op1 = operand_subword_force (op1, word, mode);
        }
 
-      mask = double_int_zero.set_bit (bitpos);
-
+      wide_int mask = wi::set_bit_in_zero (bitpos, GET_MODE_PRECISION (imode));
       sign = expand_binop (imode, and_optab, op1,
-                          immed_double_int_const (mask, imode),
+                          immed_wide_int_const (mask, imode),
                           NULL_RTX, 1, OPTAB_LIB_WIDEN);
     }
 
@@ -3603,13 +3647,13 @@ expand_copysign_absneg (enum machine_mode mode, rtx op0, rtx op1, rtx target,
    is true if op0 is known to have its sign bit clear.  */
 
 static rtx
-expand_copysign_bit (enum machine_mode mode, rtx op0, rtx op1, rtx target,
+expand_copysign_bit (machine_mode mode, rtx op0, rtx op1, rtx target,
                     int bitpos, bool op0_is_abs)
 {
-  enum machine_mode imode;
-  double_int mask;
+  machine_mode imode;
   int word, nwords, i;
-  rtx temp, insns;
+  rtx temp;
+  rtx_insn *insns;
 
   if (GET_MODE_SIZE (mode) <= UNITS_PER_WORD)
     {
@@ -3631,7 +3675,7 @@ expand_copysign_bit (enum machine_mode mode, rtx op0, rtx op1, rtx target,
       nwords = (GET_MODE_BITSIZE (mode) + BITS_PER_WORD - 1) / BITS_PER_WORD;
     }
 
-  mask = double_int_zero.set_bit (bitpos);
+  wide_int mask = wi::set_bit_in_zero (bitpos, GET_MODE_PRECISION (imode));
 
   if (target == 0
       || target == op0
@@ -3653,12 +3697,11 @@ expand_copysign_bit (enum machine_mode mode, rtx op0, rtx op1, rtx target,
              if (!op0_is_abs)
                op0_piece
                  = expand_binop (imode, and_optab, op0_piece,
-                                 immed_double_int_const (~mask, imode),
+                                 immed_wide_int_const (~mask, imode),
                                  NULL_RTX, 1, OPTAB_LIB_WIDEN);
-
              op1 = expand_binop (imode, and_optab,
                                  operand_subword_force (op1, i, mode),
-                                 immed_double_int_const (mask, imode),
+                                 immed_wide_int_const (mask, imode),
                                  NULL_RTX, 1, OPTAB_LIB_WIDEN);
 
              temp = expand_binop (imode, ior_optab, op0_piece, op1,
@@ -3678,13 +3721,13 @@ expand_copysign_bit (enum machine_mode mode, rtx op0, rtx op1, rtx target,
   else
     {
       op1 = expand_binop (imode, and_optab, gen_lowpart (imode, op1),
-                         immed_double_int_const (mask, imode),
+                         immed_wide_int_const (mask, imode),
                          NULL_RTX, 1, OPTAB_LIB_WIDEN);
 
       op0 = gen_lowpart (imode, op0);
       if (!op0_is_abs)
        op0 = expand_binop (imode, and_optab, op0,
-                           immed_double_int_const (~mask, imode),
+                           immed_wide_int_const (~mask, imode),
                            NULL_RTX, 1, OPTAB_LIB_WIDEN);
 
       temp = expand_binop (imode, ior_optab, op0, op1,
@@ -3702,7 +3745,7 @@ expand_copysign_bit (enum machine_mode mode, rtx op0, rtx op1, rtx target,
 rtx
 expand_copysign (rtx op0, rtx op1, rtx target)
 {
-  enum machine_mode mode = GET_MODE (op0);
+  machine_mode mode = GET_MODE (op0);
   const struct real_format *fmt;
   bool op0_is_abs;
   rtx temp;
@@ -3758,7 +3801,7 @@ maybe_emit_unop_insn (enum insn_code icode, rtx target, rtx op0,
                      enum rtx_code code)
 {
   struct expand_operand ops[2];
-  rtx pat;
+  rtx_insn *pat;
 
   create_output_operand (&ops[0], target, GET_MODE (target));
   create_input_operand (&ops[1], op0, GET_MODE (op0));
@@ -3766,7 +3809,8 @@ maybe_emit_unop_insn (enum insn_code icode, rtx target, rtx op0,
   if (!pat)
     return false;
 
-  if (INSN_P (pat) && NEXT_INSN (pat) != NULL_RTX && code != UNKNOWN)
+  if (INSN_P (pat) && NEXT_INSN (pat) != NULL_RTX
+      && code != UNKNOWN)
     add_equal_note (pat, ops[0].value, code, ops[1].value, NULL_RTX);
 
   emit_insn (pat);
@@ -3790,7 +3834,8 @@ emit_unop_insn (enum insn_code icode, rtx target, rtx op0, enum rtx_code code)
 \f
 struct no_conflict_data
 {
-  rtx target, first, insn;
+  rtx target;
+  rtx_insn *first, *insn;
   bool must_stay;
 };
 
@@ -3842,11 +3887,11 @@ no_conflict_move_test (rtx dest, const_rtx set, void *p0)
    note with an operand of EQUIV.  */
 
 static void
-emit_libcall_block_1 (rtx insns, rtx target, rtx result, rtx equiv,
+emit_libcall_block_1 (rtx_insn *insns, rtx target, rtx result, rtx equiv,
                      bool equiv_may_trap)
 {
   rtx final_dest = target;
-  rtx next, last, insn;
+  rtx_insn *next, *last, *insn;
 
   /* If this is a reg with REG_USERVAR_P set, then it could possibly turn
      into a MEM later.  Protect the libcall block from this change.  */
@@ -3907,12 +3952,12 @@ emit_libcall_block_1 (rtx insns, rtx target, rtx result, rtx equiv,
          if (! data.must_stay)
            {
              if (PREV_INSN (insn))
-               NEXT_INSN (PREV_INSN (insn)) = next;
+               SET_NEXT_INSN (PREV_INSN (insn)) = next;
              else
                insns = next;
 
              if (next)
-               PREV_INSN (next) = PREV_INSN (insn);
+               SET_PREV_INSN (next) = PREV_INSN (insn);
 
              add_insn (insn);
            }
@@ -3942,7 +3987,8 @@ emit_libcall_block_1 (rtx insns, rtx target, rtx result, rtx equiv,
 void
 emit_libcall_block (rtx insns, rtx target, rtx result, rtx equiv)
 {
-  emit_libcall_block_1 (insns, target, result, equiv, false);
+  emit_libcall_block_1 (safe_as_a <rtx_insn *> (insns),
+                       target, result, equiv, false);
 }
 \f
 /* Nonzero if we can perform a comparison of mode MODE straightforwardly.
@@ -3954,7 +4000,7 @@ emit_libcall_block (rtx insns, rtx target, rtx result, rtx equiv)
    required to implement all (or any) of the unordered bcc operations.  */
 
 int
-can_compare_p (enum rtx_code code, enum machine_mode mode,
+can_compare_p (enum rtx_code code, machine_mode mode,
               enum can_compare_purpose purpose)
 {
   rtx test;
@@ -4003,11 +4049,11 @@ can_compare_p (enum rtx_code code, enum machine_mode mode,
 static void
 prepare_cmp_insn (rtx x, rtx y, enum rtx_code comparison, rtx size,
                  int unsignedp, enum optab_methods methods,
-                 rtx *ptest, enum machine_mode *pmode)
+                 rtx *ptest, machine_mode *pmode)
 {
-  enum machine_mode mode = *pmode;
+  machine_mode mode = *pmode;
   rtx libfunc, test;
-  enum machine_mode cmp_mode;
+  machine_mode cmp_mode;
   enum mode_class mclass;
 
   /* The other methods are not needed.  */
@@ -4025,7 +4071,7 @@ prepare_cmp_insn (rtx x, rtx y, enum rtx_code comparison, rtx size,
           > COSTS_N_INSNS (1)))
     y = force_reg (mode, y);
 
-#ifdef HAVE_cc0
+#if HAVE_cc0
   /* Make sure if we have a canonical comparison.  The RTL
      documentation states that canonical comparisons are required only
      for targets which have cc0.  */
@@ -4042,7 +4088,7 @@ prepare_cmp_insn (rtx x, rtx y, enum rtx_code comparison, rtx size,
 
   if (mode == BLKmode)
     {
-      enum machine_mode result_mode;
+      machine_mode result_mode;
       enum insn_code cmp_code;
       tree length_type;
       rtx libfunc;
@@ -4118,8 +4164,11 @@ prepare_cmp_insn (rtx x, rtx y, enum rtx_code comparison, rtx size,
 
   if (GET_MODE_CLASS (mode) == MODE_CC)
     {
-      gcc_assert (can_compare_p (comparison, CCmode, ccp_jump));
-      *ptest = gen_rtx_fmt_ee (comparison, VOIDmode, x, y);
+      enum insn_code icode = optab_handler (cbranch_optab, CCmode);
+      test = gen_rtx_fmt_ee (comparison, VOIDmode, x, y);
+      gcc_assert (icode != CODE_FOR_nothing
+                  && insn_operand_matches (icode, 0, test));
+      *ptest = test;
       return;
     }
 
@@ -4133,7 +4182,7 @@ prepare_cmp_insn (rtx x, rtx y, enum rtx_code comparison, rtx size,
       if (icode != CODE_FOR_nothing
          && insn_operand_matches (icode, 0, test))
        {
-         rtx last = get_last_insn ();
+         rtx_insn *last = get_last_insn ();
          rtx op0 = prepare_operand (icode, x, 1, mode, cmp_mode, unsignedp);
          rtx op1 = prepare_operand (icode, y, 2, mode, cmp_mode, unsignedp);
          if (op0 && op1
@@ -4161,7 +4210,7 @@ prepare_cmp_insn (rtx x, rtx y, enum rtx_code comparison, rtx size,
   if (!SCALAR_FLOAT_MODE_P (mode))
     {
       rtx result;
-      enum machine_mode ret_mode;
+      machine_mode ret_mode;
 
       /* Handle a libcall just for the mode we are using.  */
       libfunc = optab_libfunc (cmp_optab, mode);
@@ -4201,7 +4250,7 @@ prepare_cmp_insn (rtx x, rtx y, enum rtx_code comparison, rtx size,
            y = const0_rtx;
        }
 
-      *pmode = word_mode;
+      *pmode = ret_mode;
       prepare_cmp_insn (x, y, comparison, NULL_RTX, unsignedp, methods,
                        ptest, pmode);
     }
@@ -4220,17 +4269,20 @@ prepare_cmp_insn (rtx x, rtx y, enum rtx_code comparison, rtx size,
    that it is accepted by the operand predicate.  Return the new value.  */
 
 rtx
-prepare_operand (enum insn_code icode, rtx x, int opnum, enum machine_mode mode,
-                enum machine_mode wider_mode, int unsignedp)
+prepare_operand (enum insn_code icode, rtx x, int opnum, machine_mode mode,
+                machine_mode wider_mode, int unsignedp)
 {
   if (mode != wider_mode)
     x = convert_modes (wider_mode, mode, x, unsignedp);
 
   if (!insn_operand_matches (icode, opnum, x))
     {
+      machine_mode op_mode = insn_data[(int) icode].operand[opnum].mode;
       if (reload_completed)
        return NULL_RTX;
-      x = copy_to_mode_reg (insn_data[(int) icode].operand[opnum].mode, x);
+      if (GET_MODE (x) != op_mode && GET_MODE (x) != VOIDmode)
+       return NULL_RTX;
+      x = copy_to_mode_reg (op_mode, x);
     }
 
   return x;
@@ -4240,12 +4292,12 @@ prepare_operand (enum insn_code icode, rtx x, int opnum, enum machine_mode mode,
    we can do the branch.  */
 
 static void
-emit_cmp_and_jump_insn_1 (rtx test, enum machine_mode mode, rtx label, int prob)
+emit_cmp_and_jump_insn_1 (rtx test, machine_mode mode, rtx label, int prob)
 {
-  enum machine_mode optab_mode;
+  machine_mode optab_mode;
   enum mode_class mclass;
   enum insn_code icode;
-  rtx insn;
+  rtx_insn *insn;
 
   mclass = GET_MODE_CLASS (mode);
   optab_mode = (mclass == MODE_CC) ? CCmode : mode;
@@ -4256,12 +4308,12 @@ emit_cmp_and_jump_insn_1 (rtx test, enum machine_mode mode, rtx label, int prob)
   insn = emit_jump_insn (GEN_FCN (icode) (test, XEXP (test, 0),
                                           XEXP (test, 1), label));
   if (prob != -1
-      && profile_status != PROFILE_ABSENT
+      && profile_status_for_fn (cfun) != PROFILE_ABSENT
       && insn
       && JUMP_P (insn)
       && any_condjump_p (insn)
       && !find_reg_note (insn, REG_BR_PROB, 0))
-    add_reg_note (insn, REG_BR_PROB, GEN_INT (prob));
+    add_int_reg_note (insn, REG_BR_PROB, prob);
 }
 
 /* Generate code to compare X with Y so that the condition codes are
@@ -4285,7 +4337,7 @@ emit_cmp_and_jump_insn_1 (rtx test, enum machine_mode mode, rtx label, int prob)
 
 void
 emit_cmp_and_jump_insns (rtx x, rtx y, enum rtx_code comparison, rtx size,
-                        enum machine_mode mode, int unsignedp, rtx label,
+                        machine_mode mode, int unsignedp, rtx label,
                          int prob)
 {
   rtx op0 = x, op1 = y;
@@ -4319,14 +4371,15 @@ emit_cmp_and_jump_insns (rtx x, rtx y, enum rtx_code comparison, rtx size,
 
 static void
 prepare_float_lib_cmp (rtx x, rtx y, enum rtx_code comparison,
-                      rtx *ptest, enum machine_mode *pmode)
+                      rtx *ptest, machine_mode *pmode)
 {
   enum rtx_code swapped = swap_condition (comparison);
   enum rtx_code reversed = reverse_condition_maybe_unordered (comparison);
-  enum machine_mode orig_mode = GET_MODE (x);
-  enum machine_mode mode, cmp_mode;
+  machine_mode orig_mode = GET_MODE (x);
+  machine_mode mode, cmp_mode;
   rtx true_rtx, false_rtx;
-  rtx value, target, insns, equiv;
+  rtx value, target, equiv;
+  rtx_insn *insns;
   rtx libfunc = 0;
   bool reversed_p = false;
   cmp_mode = targetm.libgcc_cmp_return_mode ();
@@ -4450,16 +4503,18 @@ prepare_float_lib_cmp (rtx x, rtx y, enum rtx_code comparison,
 /* Generate code to indirectly jump to a location given in the rtx LOC.  */
 
 void
-emit_indirect_jump (rtx loc)
+emit_indirect_jump (rtx loc ATTRIBUTE_UNUSED)
 {
+#ifndef HAVE_indirect_jump
+  sorry ("indirect jumps are not available on this target");
+#else
   struct expand_operand ops[1];
-
   create_address_operand (&ops[0], loc);
   expand_jump_insn (CODE_FOR_indirect_jump, 1, ops);
   emit_barrier ();
+#endif
 }
 \f
-#ifdef HAVE_conditional_move
 
 /* Emit a conditional move instruction if the machine supports one for that
    condition and machine mode.
@@ -4477,10 +4532,11 @@ emit_indirect_jump (rtx loc)
 
 rtx
 emit_conditional_move (rtx target, enum rtx_code code, rtx op0, rtx op1,
-                      enum machine_mode cmode, rtx op2, rtx op3,
-                      enum machine_mode mode, int unsignedp)
+                      machine_mode cmode, rtx op2, rtx op3,
+                      machine_mode mode, int unsignedp)
 {
-  rtx tem, comparison, last;
+  rtx comparison;
+  rtx_insn *last;
   enum insn_code icode;
   enum rtx_code reversed;
 
@@ -4489,9 +4545,7 @@ emit_conditional_move (rtx target, enum rtx_code code, rtx op0, rtx op1,
 
   if (swap_commutative_operands_p (op0, op1))
     {
-      tem = op0;
-      op0 = op1;
-      op1 = tem;
+      std::swap (op0, op1);
       code = swap_condition (code);
     }
 
@@ -4510,9 +4564,7 @@ emit_conditional_move (rtx target, enum rtx_code code, rtx op0, rtx op1,
       && ((reversed = reversed_comparison_code_parts (code, op0, op1, NULL))
           != UNKNOWN))
     {
-      tem = op2;
-      op2 = op3;
-      op3 = tem;
+      std::swap (op2, op3);
       code = reversed;
     }
 
@@ -4536,8 +4588,10 @@ emit_conditional_move (rtx target, enum rtx_code code, rtx op0, rtx op1,
   if (!COMPARISON_P (comparison))
     return NULL_RTX;
 
-  do_pending_stack_adjust ();
+  saved_pending_stack_adjust save;
+  save_pending_stack_adjust (&save);
   last = get_last_insn ();
+  do_pending_stack_adjust ();
   prepare_cmp_insn (XEXP (comparison, 0), XEXP (comparison, 1),
                    GET_CODE (comparison), NULL_RTX, unsignedp, OPTAB_WIDEN,
                    &comparison, &cmode);
@@ -4557,6 +4611,7 @@ emit_conditional_move (rtx target, enum rtx_code code, rtx op0, rtx op1,
        }
     }
   delete_insns_since (last);
+  restore_pending_stack_adjust (&save);
   return NULL_RTX;
 }
 
@@ -4569,7 +4624,7 @@ emit_conditional_move (rtx target, enum rtx_code code, rtx op0, rtx op1,
    comparisons, and vice versa.  How do we handle them?  */
 
 int
-can_conditionally_move_p (enum machine_mode mode)
+can_conditionally_move_p (machine_mode mode)
 {
   if (direct_optab_handler (movcc_optab, mode) != CODE_FOR_nothing)
     return 1;
@@ -4577,8 +4632,6 @@ can_conditionally_move_p (enum machine_mode mode)
   return 0;
 }
 
-#endif /* HAVE_conditional_move */
-
 /* Emit a conditional addition instruction if the machine supports one for that
    condition and machine mode.
 
@@ -4595,10 +4648,11 @@ can_conditionally_move_p (enum machine_mode mode)
 
 rtx
 emit_conditional_add (rtx target, enum rtx_code code, rtx op0, rtx op1,
-                     enum machine_mode cmode, rtx op2, rtx op3,
-                     enum machine_mode mode, int unsignedp)
+                     machine_mode cmode, rtx op2, rtx op3,
+                     machine_mode mode, int unsignedp)
 {
-  rtx tem, comparison, last;
+  rtx comparison;
+  rtx_insn *last;
   enum insn_code icode;
 
   /* If one operand is constant, make it the second one.  Only do this
@@ -4606,9 +4660,7 @@ emit_conditional_add (rtx target, enum rtx_code code, rtx op0, rtx op1,
 
   if (swap_commutative_operands_p (op0, op1))
     {
-      tem = op0;
-      op0 = op1;
-      op1 = tem;
+      std::swap (op0, op1);
       code = swap_condition (code);
     }
 
@@ -4722,6 +4774,43 @@ have_add2_insn (rtx x, rtx y)
   return 1;
 }
 
+/* Generate and return an insn body to add Y to X.  */
+
+rtx
+gen_addptr3_insn (rtx x, rtx y, rtx z)
+{
+  enum insn_code icode = optab_handler (addptr3_optab, GET_MODE (x));
+
+  gcc_assert (insn_operand_matches (icode, 0, x));
+  gcc_assert (insn_operand_matches (icode, 1, y));
+  gcc_assert (insn_operand_matches (icode, 2, z));
+
+  return GEN_FCN (icode) (x, y, z);
+}
+
+/* Return true if the target implements an addptr pattern and X, Y,
+   and Z are valid for the pattern predicates.  */
+
+int
+have_addptr3_insn (rtx x, rtx y, rtx z)
+{
+  enum insn_code icode;
+
+  gcc_assert (GET_MODE (x) != VOIDmode);
+
+  icode = optab_handler (addptr3_optab, GET_MODE (x));
+
+  if (icode == CODE_FOR_nothing)
+    return 0;
+
+  if (!insn_operand_matches (icode, 0, x)
+      || !insn_operand_matches (icode, 1, y)
+      || !insn_operand_matches (icode, 2, z))
+    return 0;
+
+  return 1;
+}
+
 /* Generate and return an insn body to subtract Y from X.  */
 
 rtx
@@ -4772,28 +4861,13 @@ have_sub2_insn (rtx x, rtx y)
 
   return 1;
 }
-
-/* Generate the body of an instruction to copy Y into X.
-   It may be a list of insns, if one insn isn't enough.  */
-
-rtx
-gen_move_insn (rtx x, rtx y)
-{
-  rtx seq;
-
-  start_sequence ();
-  emit_move_insn_1 (x, y);
-  seq = get_insns ();
-  end_sequence ();
-  return seq;
-}
 \f
 /* Return the insn code used to extend FROM_MODE to TO_MODE.
    UNSIGNEDP specifies zero-extension instead of sign-extension.  If
    no such operation exists, CODE_FOR_nothing will be returned.  */
 
 enum insn_code
-can_extend_p (enum machine_mode to_mode, enum machine_mode from_mode,
+can_extend_p (machine_mode to_mode, machine_mode from_mode,
              int unsignedp)
 {
   convert_optab tab;
@@ -4810,8 +4884,8 @@ can_extend_p (enum machine_mode to_mode, enum machine_mode from_mode,
    into X (with mode MTO).  Do zero-extension if UNSIGNEDP is nonzero.  */
 
 rtx
-gen_extend_insn (rtx x, rtx y, enum machine_mode mto,
-                enum machine_mode mfrom, int unsignedp)
+gen_extend_insn (rtx x, rtx y, machine_mode mto,
+                machine_mode mfrom, int unsignedp)
 {
   enum insn_code icode = can_extend_p (mto, mfrom, unsignedp);
   return GEN_FCN (icode) (x, y);
@@ -4827,7 +4901,7 @@ gen_extend_insn (rtx x, rtx y, enum machine_mode mto,
    an explicit FTRUNC insn before the fix insn; otherwise 0.  */
 
 static enum insn_code
-can_fix_p (enum machine_mode fixmode, enum machine_mode fltmode,
+can_fix_p (machine_mode fixmode, machine_mode fltmode,
           int unsignedp, int *truncp_ptr)
 {
   convert_optab tab;
@@ -4858,7 +4932,7 @@ can_fix_p (enum machine_mode fixmode, enum machine_mode fltmode,
 }
 
 enum insn_code
-can_float_p (enum machine_mode fltmode, enum machine_mode fixmode,
+can_float_p (machine_mode fltmode, machine_mode fixmode,
             int unsignedp)
 {
   convert_optab tab;
@@ -4891,7 +4965,7 @@ supportable_convert_operation (enum tree_code code,
                                     tree vectype_out, tree vectype_in,
                                     tree *decl, enum tree_code *code1)
 {
-  enum machine_mode m1,m2;
+  machine_mode m1,m2;
   int truncp;
 
   m1 = TYPE_MODE (vectype_out);
@@ -4932,7 +5006,7 @@ expand_float (rtx to, rtx from, int unsignedp)
 {
   enum insn_code icode;
   rtx target = to;
-  enum machine_mode fmode, imode;
+  machine_mode fmode, imode;
   bool can_do_signed = false;
 
   /* Crash now, because we won't be able to decide which mode to use.  */
@@ -4985,7 +5059,7 @@ expand_float (rtx to, rtx from, int unsignedp)
      then unconditionally adjust the result.  */
   if (unsignedp && can_do_signed)
     {
-      rtx label = gen_label_rtx ();
+      rtx_code_label *label = gen_label_rtx ();
       rtx temp;
       REAL_VALUE_TYPE offset;
 
@@ -5009,7 +5083,7 @@ expand_float (rtx to, rtx from, int unsignedp)
              < GET_MODE_PRECISION (GET_MODE (from)))
            {
              rtx temp1;
-             rtx neglabel = gen_label_rtx ();
+             rtx_code_label *neglabel = gen_label_rtx ();
 
              /* Don't use TARGET if it isn't a register, is a hard register,
                 or is the wrong mode.  */
@@ -5088,11 +5162,11 @@ expand_float (rtx to, rtx from, int unsignedp)
   /* No hardware instruction available; call a library routine.  */
     {
       rtx libfunc;
-      rtx insns;
+      rtx_insn *insns;
       rtx value;
       convert_optab tab = unsignedp ? ufloat_optab : sfloat_optab;
 
-      if (GET_MODE_SIZE (GET_MODE (from)) < GET_MODE_SIZE (SImode))
+      if (GET_MODE_PRECISION (GET_MODE (from)) < GET_MODE_PRECISION (SImode))
        from = convert_to_mode (SImode, from, unsignedp);
 
       libfunc = convert_optab_libfunc (tab, GET_MODE (to), GET_MODE (from));
@@ -5133,7 +5207,7 @@ expand_fix (rtx to, rtx from, int unsignedp)
 {
   enum insn_code icode;
   rtx target = to;
-  enum machine_mode fmode, imode;
+  machine_mode fmode, imode;
   int must_trunc = 0;
 
   /* We first try to find a pair of modes, one real and one integer, at
@@ -5154,7 +5228,7 @@ expand_fix (rtx to, rtx from, int unsignedp)
 
        if (icode != CODE_FOR_nothing)
          {
-           rtx last = get_last_insn ();
+           rtx_insn *last = get_last_insn ();
            if (fmode != GET_MODE (from))
              from = convert_to_mode (fmode, from, 0);
 
@@ -5212,7 +5286,9 @@ expand_fix (rtx to, rtx from, int unsignedp)
        {
          int bitsize;
          REAL_VALUE_TYPE offset;
-         rtx limit, lab1, lab2, insn;
+         rtx limit;
+         rtx_code_label *lab1, *lab2;
+         rtx_insn *insn;
 
          bitsize = GET_MODE_PRECISION (GET_MODE (to));
          real_2expN (&offset, bitsize - 1, fmode);
@@ -5268,7 +5344,7 @@ expand_fix (rtx to, rtx from, int unsignedp)
      that the mode of TO is at least as wide as SImode, since those are the
      only library calls we know about.  */
 
-  if (GET_MODE_SIZE (GET_MODE (to)) < GET_MODE_SIZE (SImode))
+  if (GET_MODE_PRECISION (GET_MODE (to)) < GET_MODE_PRECISION (SImode))
     {
       target = gen_reg_rtx (SImode);
 
@@ -5276,7 +5352,7 @@ expand_fix (rtx to, rtx from, int unsignedp)
     }
   else
     {
-      rtx insns;
+      rtx_insn *insns;
       rtx value;
       rtx libfunc;
 
@@ -5313,12 +5389,13 @@ expand_fix (rtx to, rtx from, int unsignedp)
 void
 expand_fixed_convert (rtx to, rtx from, int uintp, int satp)
 {
-  enum machine_mode to_mode = GET_MODE (to);
-  enum machine_mode from_mode = GET_MODE (from);
+  machine_mode to_mode = GET_MODE (to);
+  machine_mode from_mode = GET_MODE (from);
   convert_optab tab;
   enum rtx_code this_code;
   enum insn_code code;
-  rtx insns, value;
+  rtx_insn *insns;
+  rtx value;
   rtx libfunc;
 
   if (to_mode == from_mode)
@@ -5366,7 +5443,7 @@ expand_sfix_optab (rtx to, rtx from, convert_optab tab)
 {
   enum insn_code icode;
   rtx target = to;
-  enum machine_mode fmode, imode;
+  machine_mode fmode, imode;
 
   /* We first try to find a pair of modes, one real and one integer, at
      least as wide as FROM and TO, respectively, in which we can open-code
@@ -5381,7 +5458,7 @@ expand_sfix_optab (rtx to, rtx from, convert_optab tab)
        icode = convert_optab_handler (tab, imode, fmode);
        if (icode != CODE_FOR_nothing)
          {
-           rtx last = get_last_insn ();
+           rtx_insn *last = get_last_insn ();
            if (fmode != GET_MODE (from))
              from = convert_to_mode (fmode, from, 0);
 
@@ -5405,7 +5482,7 @@ expand_sfix_optab (rtx to, rtx from, convert_optab tab)
 /* Report whether we have an instruction to perform the operation
    specified by CODE on operands of mode MODE.  */
 int
-have_insn_for (enum rtx_code code, enum machine_mode mode)
+have_insn_for (enum rtx_code code, machine_mode mode)
 {
   return (code_to_optab (code)
          && (optab_handler (code_to_optab (code), mode)
@@ -5428,7 +5505,7 @@ have_insn_for (enum rtx_code code, enum machine_mode mode)
 
 static void
 gen_libfunc (optab optable, const char *opname, int suffix,
-            enum machine_mode mode)
+            machine_mode mode)
 {
   unsigned opname_len = strlen (opname);
   const char *mname = GET_MODE_NAME (mode);
@@ -5464,16 +5541,21 @@ gen_libfunc (optab optable, const char *opname, int suffix,
 
 void
 gen_int_libfunc (optab optable, const char *opname, char suffix,
-                enum machine_mode mode)
+                machine_mode mode)
 {
   int maxsize = 2 * BITS_PER_WORD;
+  int minsize = BITS_PER_WORD;
 
   if (GET_MODE_CLASS (mode) != MODE_INT)
     return;
   if (maxsize < LONG_LONG_TYPE_SIZE)
     maxsize = LONG_LONG_TYPE_SIZE;
-  if (GET_MODE_CLASS (mode) != MODE_INT
-      || mode < word_mode || GET_MODE_BITSIZE (mode) > maxsize)
+  if (minsize > INT_TYPE_SIZE
+      && (trapv_binoptab_p (optable)
+         || trapv_unoptab_p (optable)))
+    minsize = INT_TYPE_SIZE;
+  if (GET_MODE_BITSIZE (mode) < minsize
+      || GET_MODE_BITSIZE (mode) > maxsize)
     return;
   gen_libfunc (optable, opname, suffix, mode);
 }
@@ -5482,7 +5564,7 @@ gen_int_libfunc (optab optable, const char *opname, char suffix,
 
 void
 gen_fp_libfunc (optab optable, const char *opname, char suffix,
-               enum machine_mode mode)
+               machine_mode mode)
 {
   char *dec_opname;
 
@@ -5503,7 +5585,7 @@ gen_fp_libfunc (optab optable, const char *opname, char suffix,
 
 void
 gen_fixed_libfunc (optab optable, const char *opname, char suffix,
-                  enum machine_mode mode)
+                  machine_mode mode)
 {
   if (!ALL_FIXED_POINT_MODE_P (mode))
     return;
@@ -5515,7 +5597,7 @@ gen_fixed_libfunc (optab optable, const char *opname, char suffix,
 
 void
 gen_signed_fixed_libfunc (optab optable, const char *opname, char suffix,
-                         enum machine_mode mode)
+                         machine_mode mode)
 {
   if (!SIGNED_FIXED_POINT_MODE_P (mode))
     return;
@@ -5527,7 +5609,7 @@ gen_signed_fixed_libfunc (optab optable, const char *opname, char suffix,
 
 void
 gen_unsigned_fixed_libfunc (optab optable, const char *opname, char suffix,
-                           enum machine_mode mode)
+                           machine_mode mode)
 {
   if (!UNSIGNED_FIXED_POINT_MODE_P (mode))
     return;
@@ -5538,7 +5620,7 @@ gen_unsigned_fixed_libfunc (optab optable, const char *opname, char suffix,
 
 void
 gen_int_fp_libfunc (optab optable, const char *name, char suffix,
-                   enum machine_mode mode)
+                   machine_mode mode)
 {
   if (DECIMAL_FLOAT_MODE_P (mode) || GET_MODE_CLASS (mode) == MODE_FLOAT)
     gen_fp_libfunc (optable, name, suffix, mode);
@@ -5551,7 +5633,7 @@ gen_int_fp_libfunc (optab optable, const char *name, char suffix,
 
 void
 gen_intv_fp_libfunc (optab optable, const char *name, char suffix,
-                    enum machine_mode mode)
+                    machine_mode mode)
 {
   if (DECIMAL_FLOAT_MODE_P (mode) || GET_MODE_CLASS (mode) == MODE_FLOAT)
     gen_fp_libfunc (optable, name, suffix, mode);
@@ -5571,7 +5653,7 @@ gen_intv_fp_libfunc (optab optable, const char *name, char suffix,
 
 void
 gen_int_fp_fixed_libfunc (optab optable, const char *name, char suffix,
-                         enum machine_mode mode)
+                         machine_mode mode)
 {
   if (DECIMAL_FLOAT_MODE_P (mode) || GET_MODE_CLASS (mode) == MODE_FLOAT)
     gen_fp_libfunc (optable, name, suffix, mode);
@@ -5586,7 +5668,7 @@ gen_int_fp_fixed_libfunc (optab optable, const char *name, char suffix,
 
 void
 gen_int_fp_signed_fixed_libfunc (optab optable, const char *name, char suffix,
-                                enum machine_mode mode)
+                                machine_mode mode)
 {
   if (DECIMAL_FLOAT_MODE_P (mode) || GET_MODE_CLASS (mode) == MODE_FLOAT)
     gen_fp_libfunc (optable, name, suffix, mode);
@@ -5601,7 +5683,7 @@ gen_int_fp_signed_fixed_libfunc (optab optable, const char *name, char suffix,
 
 void
 gen_int_fixed_libfunc (optab optable, const char *name, char suffix,
-                      enum machine_mode mode)
+                      machine_mode mode)
 {
   if (INTEGRAL_MODE_P (mode))
     gen_int_libfunc (optable, name, suffix, mode);
@@ -5614,7 +5696,7 @@ gen_int_fixed_libfunc (optab optable, const char *name, char suffix,
 
 void
 gen_int_signed_fixed_libfunc (optab optable, const char *name, char suffix,
-                             enum machine_mode mode)
+                             machine_mode mode)
 {
   if (INTEGRAL_MODE_P (mode))
     gen_int_libfunc (optable, name, suffix, mode);
@@ -5627,7 +5709,7 @@ gen_int_signed_fixed_libfunc (optab optable, const char *name, char suffix,
 
 void
 gen_int_unsigned_fixed_libfunc (optab optable, const char *name, char suffix,
-                               enum machine_mode mode)
+                               machine_mode mode)
 {
   if (INTEGRAL_MODE_P (mode))
     gen_int_libfunc (optable, name, suffix, mode);
@@ -5644,8 +5726,8 @@ gen_int_unsigned_fixed_libfunc (optab optable, const char *name, char suffix,
 void
 gen_interclass_conv_libfunc (convert_optab tab,
                             const char *opname,
-                            enum machine_mode tmode,
-                            enum machine_mode fmode)
+                            machine_mode tmode,
+                            machine_mode fmode)
 {
   size_t opname_len = strlen (opname);
   size_t mname_len = 0;
@@ -5687,7 +5769,7 @@ gen_interclass_conv_libfunc (convert_optab tab,
   fname = GET_MODE_NAME (fmode);
   tname = GET_MODE_NAME (tmode);
 
-  if (DECIMAL_FLOAT_MODE_P(fmode) || DECIMAL_FLOAT_MODE_P(tmode))
+  if (DECIMAL_FLOAT_MODE_P (fmode) || DECIMAL_FLOAT_MODE_P (tmode))
     {
       libfunc_name = dec_name;
       suffix = dec_suffix;
@@ -5716,8 +5798,8 @@ gen_interclass_conv_libfunc (convert_optab tab,
 void
 gen_int_to_fp_conv_libfunc (convert_optab tab,
                            const char *opname,
-                           enum machine_mode tmode,
-                           enum machine_mode fmode)
+                           machine_mode tmode,
+                           machine_mode fmode)
 {
   if (GET_MODE_CLASS (fmode) != MODE_INT)
     return;
@@ -5732,8 +5814,8 @@ gen_int_to_fp_conv_libfunc (convert_optab tab,
 void
 gen_ufloat_conv_libfunc (convert_optab tab,
                         const char *opname ATTRIBUTE_UNUSED,
-                        enum machine_mode tmode,
-                        enum machine_mode fmode)
+                        machine_mode tmode,
+                        machine_mode fmode)
 {
   if (DECIMAL_FLOAT_MODE_P (tmode))
     gen_int_to_fp_conv_libfunc (tab, "floatuns", tmode, fmode);
@@ -5747,8 +5829,8 @@ gen_ufloat_conv_libfunc (convert_optab tab,
 void
 gen_int_to_fp_nondecimal_conv_libfunc (convert_optab tab,
                                       const char *opname,
-                                      enum machine_mode tmode,
-                                      enum machine_mode fmode)
+                                      machine_mode tmode,
+                                      machine_mode fmode)
 {
   if (GET_MODE_CLASS (fmode) != MODE_INT)
     return;
@@ -5763,8 +5845,8 @@ gen_int_to_fp_nondecimal_conv_libfunc (convert_optab tab,
 void
 gen_fp_to_int_conv_libfunc (convert_optab tab,
                            const char *opname,
-                           enum machine_mode tmode,
-                           enum machine_mode fmode)
+                           machine_mode tmode,
+                           machine_mode fmode)
 {
   if (GET_MODE_CLASS (fmode) != MODE_FLOAT && !DECIMAL_FLOAT_MODE_P (fmode))
     return;
@@ -5779,7 +5861,7 @@ gen_fp_to_int_conv_libfunc (convert_optab tab,
 
 void
 gen_intraclass_conv_libfunc (convert_optab tab, const char *opname,
-                            enum machine_mode tmode, enum machine_mode fmode)
+                            machine_mode tmode, machine_mode fmode)
 {
   size_t opname_len = strlen (opname);
   size_t mname_len = 0;
@@ -5820,7 +5902,7 @@ gen_intraclass_conv_libfunc (convert_optab tab, const char *opname,
   fname = GET_MODE_NAME (fmode);
   tname = GET_MODE_NAME (tmode);
 
-  if (DECIMAL_FLOAT_MODE_P(fmode) || DECIMAL_FLOAT_MODE_P(tmode))
+  if (DECIMAL_FLOAT_MODE_P (fmode) || DECIMAL_FLOAT_MODE_P (tmode))
     {
       libfunc_name = dec_name;
       suffix = dec_suffix;
@@ -5850,8 +5932,8 @@ gen_intraclass_conv_libfunc (convert_optab tab, const char *opname,
 void
 gen_trunc_conv_libfunc (convert_optab tab,
                         const char *opname,
-                        enum machine_mode tmode,
-                        enum machine_mode fmode)
+                        machine_mode tmode,
+                        machine_mode fmode)
 {
   if (GET_MODE_CLASS (tmode) != MODE_FLOAT && !DECIMAL_FLOAT_MODE_P (tmode))
     return;
@@ -5879,8 +5961,8 @@ gen_trunc_conv_libfunc (convert_optab tab,
 void
 gen_extend_conv_libfunc (convert_optab tab,
                         const char *opname ATTRIBUTE_UNUSED,
-                        enum machine_mode tmode,
-                        enum machine_mode fmode)
+                        machine_mode tmode,
+                        machine_mode fmode)
 {
   if (GET_MODE_CLASS (tmode) != MODE_FLOAT && !DECIMAL_FLOAT_MODE_P (tmode))
     return;
@@ -5908,8 +5990,8 @@ gen_extend_conv_libfunc (convert_optab tab,
 void
 gen_fract_conv_libfunc (convert_optab tab,
                        const char *opname,
-                       enum machine_mode tmode,
-                       enum machine_mode fmode)
+                       machine_mode tmode,
+                       machine_mode fmode)
 {
   if (tmode == fmode)
     return;
@@ -5927,8 +6009,8 @@ gen_fract_conv_libfunc (convert_optab tab,
 void
 gen_fractuns_conv_libfunc (convert_optab tab,
                           const char *opname,
-                          enum machine_mode tmode,
-                          enum machine_mode fmode)
+                          machine_mode tmode,
+                          machine_mode fmode)
 {
   if (tmode == fmode)
     return;
@@ -5948,8 +6030,8 @@ gen_fractuns_conv_libfunc (convert_optab tab,
 void
 gen_satfract_conv_libfunc (convert_optab tab,
                           const char *opname,
-                          enum machine_mode tmode,
-                          enum machine_mode fmode)
+                          machine_mode tmode,
+                          machine_mode fmode)
 {
   if (tmode == fmode)
     return;
@@ -5968,8 +6050,8 @@ gen_satfract_conv_libfunc (convert_optab tab,
 void
 gen_satfractuns_conv_libfunc (convert_optab tab,
                              const char *opname,
-                             enum machine_mode tmode,
-                             enum machine_mode fmode)
+                             machine_mode tmode,
+                             machine_mode fmode)
 {
   if (tmode == fmode)
     return;
@@ -5980,22 +6062,25 @@ gen_satfractuns_conv_libfunc (convert_optab tab,
   gen_interclass_conv_libfunc (tab, opname, tmode, fmode);
 }
 
-/* A table of previously-created libfuncs, hashed by name.  */
-static GTY ((param_is (union tree_node))) htab_t libfunc_decls;
-
 /* Hashtable callbacks for libfunc_decls.  */
 
-static hashval_t
-libfunc_decl_hash (const void *entry)
+struct libfunc_decl_hasher : ggc_hasher<tree>
 {
-  return IDENTIFIER_HASH_VALUE (DECL_NAME ((const_tree) entry));
-}
+  static hashval_t
+  hash (tree entry)
+  {
+    return IDENTIFIER_HASH_VALUE (DECL_NAME (entry));
+  }
 
-static int
-libfunc_decl_eq (const void *entry1, const void *entry2)
-{
-  return DECL_NAME ((const_tree) entry1) == (const_tree) entry2;
-}
+  static bool
+  equal (tree decl, tree name)
+  {
+    return DECL_NAME (decl) == name;
+  }
+};
+
+/* A table of previously-created libfuncs, hashed by name.  */
+static GTY (()) hash_table<libfunc_decl_hasher> *libfunc_decls;
 
 /* Build a decl for a libfunc named NAME. */
 
@@ -6023,18 +6108,16 @@ rtx
 init_one_libfunc (const char *name)
 {
   tree id, decl;
-  void **slot;
   hashval_t hash;
 
   if (libfunc_decls == NULL)
-    libfunc_decls = htab_create_ggc (37, libfunc_decl_hash,
-                                    libfunc_decl_eq, NULL);
+    libfunc_decls = hash_table<libfunc_decl_hasher>::create_ggc (37);
 
   /* See if we have already created a libfunc decl for this function.  */
   id = get_identifier (name);
   hash = IDENTIFIER_HASH_VALUE (id);
-  slot = htab_find_slot_with_hash (libfunc_decls, id, hash, INSERT);
-  decl = (tree) *slot;
+  tree *slot = libfunc_decls->find_slot_with_hash (id, hash, INSERT);
+  decl = *slot;
   if (decl == NULL)
     {
       /* Create a new decl, so that it can be passed to
@@ -6051,12 +6134,11 @@ rtx
 set_user_assembler_libfunc (const char *name, const char *asmspec)
 {
   tree id, decl;
-  void **slot;
   hashval_t hash;
 
   id = get_identifier (name);
   hash = IDENTIFIER_HASH_VALUE (id);
-  slot = htab_find_slot_with_hash (libfunc_decls, id, hash, NO_INSERT);
+  tree *slot = libfunc_decls->find_slot_with_hash (id, hash, NO_INSERT);
   gcc_assert (slot);
   decl = (tree) *slot;
   set_user_assembler_name (decl, asmspec);
@@ -6066,7 +6148,7 @@ set_user_assembler_libfunc (const char *name, const char *asmspec)
 /* Call this to reset the function entry for one optab (OPTABLE) in mode
    MODE to NAME, which should be either 0 or a string constant.  */
 void
-set_optab_libfunc (optab op, enum machine_mode mode, const char *name)
+set_optab_libfunc (optab op, machine_mode mode, const char *name)
 {
   rtx val;
   struct libfunc_entry e;
@@ -6080,9 +6162,9 @@ set_optab_libfunc (optab op, enum machine_mode mode, const char *name)
     val = init_one_libfunc (name);
   else
     val = 0;
-  slot = (struct libfunc_entry **) htab_find_slot (libfunc_hash, &e, INSERT);
+  slot = libfunc_hash->find_slot (&e, INSERT);
   if (*slot == NULL)
-    *slot = ggc_alloc_libfunc_entry ();
+    *slot = ggc_alloc<libfunc_entry> ();
   (*slot)->op = op;
   (*slot)->mode1 = mode;
   (*slot)->mode2 = VOIDmode;
@@ -6093,8 +6175,8 @@ set_optab_libfunc (optab op, enum machine_mode mode, const char *name)
    (OPTABLE) from mode FMODE to mode TMODE to NAME, which should be
    either 0 or a string constant.  */
 void
-set_conv_libfunc (convert_optab optab, enum machine_mode tmode,
-                 enum machine_mode fmode, const char *name)
+set_conv_libfunc (convert_optab optab, machine_mode tmode,
+                 machine_mode fmode, const char *name)
 {
   rtx val;
   struct libfunc_entry e;
@@ -6108,9 +6190,9 @@ set_conv_libfunc (convert_optab optab, enum machine_mode tmode,
     val = init_one_libfunc (name);
   else
     val = 0;
-  slot = (struct libfunc_entry **) htab_find_slot (libfunc_hash, &e, INSERT);
+  slot = libfunc_hash->find_slot (&e, INSERT);
   if (*slot == NULL)
-    *slot = ggc_alloc_libfunc_entry ();
+    *slot = ggc_alloc<libfunc_entry> ();
   (*slot)->op = optab;
   (*slot)->mode1 = tmode;
   (*slot)->mode2 = fmode;
@@ -6124,12 +6206,12 @@ void
 init_optabs (void)
 {
   if (libfunc_hash)
-    htab_empty (libfunc_hash);
+    libfunc_hash->empty ();
   else
-    libfunc_hash = htab_create_ggc (10, hash_libfunc, eq_libfunc, NULL);
+    libfunc_hash = hash_table<libfunc_hasher>::create_ggc (10);
 
   /* Fill in the optabs with the insns we support.  */
-  init_all_optabs ();
+  init_all_optabs (this_fn_optabs);
 
   /* The ffs function operates on `int'.  Fall back on it if we do not
      have a libgcc2 function for that width.  */
@@ -6186,13 +6268,45 @@ init_optabs (void)
   targetm.init_libfuncs ();
 }
 
+/* Use the current target and options to initialize
+   TREE_OPTIMIZATION_OPTABS (OPTNODE).  */
+
+void
+init_tree_optimization_optabs (tree optnode)
+{
+  /* Quick exit if we have already computed optabs for this target.  */
+  if (TREE_OPTIMIZATION_BASE_OPTABS (optnode) == this_target_optabs)
+    return;
+
+  /* Forget any previous information and set up for the current target.  */
+  TREE_OPTIMIZATION_BASE_OPTABS (optnode) = this_target_optabs;
+  struct target_optabs *tmp_optabs = (struct target_optabs *)
+    TREE_OPTIMIZATION_OPTABS (optnode);
+  if (tmp_optabs)
+    memset (tmp_optabs, 0, sizeof (struct target_optabs));
+  else
+    tmp_optabs = ggc_alloc<target_optabs> ();
+
+  /* Generate a new set of optabs into tmp_optabs.  */
+  init_all_optabs (tmp_optabs);
+
+  /* If the optabs changed, record it.  */
+  if (memcmp (tmp_optabs, this_target_optabs, sizeof (struct target_optabs)))
+    TREE_OPTIMIZATION_OPTABS (optnode) = tmp_optabs;
+  else
+    {
+      TREE_OPTIMIZATION_OPTABS (optnode) = NULL;
+      ggc_free (tmp_optabs);
+    }
+}
+
 /* A helper function for init_sync_libfuncs.  Using the basename BASE,
    install libfuncs into TAB for BASE_N for 1 <= N <= MAX.  */
 
 static void
 init_sync_libfuncs_1 (optab tab, const char *base, int max)
 {
-  enum machine_mode mode;
+  machine_mode mode;
   char buf[64];
   size_t len = strlen (base);
   int i;
@@ -6252,7 +6366,7 @@ debug_optab_libfuncs (void)
   for (i = FIRST_NORM_OPTAB; i <= LAST_NORMLIB_OPTAB; ++i)
     for (j = 0; j < NUM_MACHINE_MODES; ++j)
       {
-       rtx l = optab_libfunc ((optab) i, (enum machine_mode) j);
+       rtx l = optab_libfunc ((optab) i, (machine_mode) j);
        if (l)
          {
            gcc_assert (GET_CODE (l) == SYMBOL_REF);
@@ -6268,8 +6382,8 @@ debug_optab_libfuncs (void)
     for (j = 0; j < NUM_MACHINE_MODES; ++j)
       for (k = 0; k < NUM_MACHINE_MODES; ++k)
        {
-         rtx l = convert_optab_libfunc ((optab) i, (enum machine_mode) j,
-                                        (enum machine_mode) k);
+         rtx l = convert_optab_libfunc ((optab) i, (machine_mode) j,
+                                        (machine_mode) k);
          if (l)
            {
              gcc_assert (GET_CODE (l) == SYMBOL_REF);
@@ -6289,7 +6403,7 @@ debug_optab_libfuncs (void)
 rtx
 gen_cond_trap (enum rtx_code code, rtx op1, rtx op2, rtx tcode)
 {
-  enum machine_mode mode = GET_MODE (op1);
+  machine_mode mode = GET_MODE (op1);
   enum insn_code icode;
   rtx insn;
   rtx trap_rtx;
@@ -6331,7 +6445,7 @@ gen_cond_trap (enum rtx_code code, rtx op1, rtx op2, rtx tcode)
 /* Return rtx code for TCODE. Use UNSIGNEDP to select signed
    or unsigned operation code.  */
 
-static enum rtx_code
+enum rtx_code
 get_rtx_code (enum tree_code tcode, bool unsignedp)
 {
   enum rtx_code code;
@@ -6381,6 +6495,14 @@ get_rtx_code (enum tree_code tcode, bool unsignedp)
       code = LTGT;
       break;
 
+    case BIT_AND_EXPR:
+      code = AND;
+      break;
+
+    case BIT_IOR_EXPR:
+      code = IOR;
+      break;
+
     default:
       gcc_unreachable ();
     }
@@ -6396,31 +6518,44 @@ vector_compare_rtx (enum tree_code tcode, tree t_op0, tree t_op1,
 {
   struct expand_operand ops[2];
   rtx rtx_op0, rtx_op1;
+  machine_mode m0, m1;
   enum rtx_code rcode = get_rtx_code (tcode, unsignedp);
 
   gcc_assert (TREE_CODE_CLASS (tcode) == tcc_comparison);
 
-  /* Expand operands.  */
+  /* Expand operands.  For vector types with scalar modes, e.g. where int64x1_t
+     has mode DImode, this can produce a constant RTX of mode VOIDmode; in such
+     cases, use the original mode.  */
   rtx_op0 = expand_expr (t_op0, NULL_RTX, TYPE_MODE (TREE_TYPE (t_op0)),
                         EXPAND_STACK_PARM);
+  m0 = GET_MODE (rtx_op0);
+  if (m0 == VOIDmode)
+    m0 = TYPE_MODE (TREE_TYPE (t_op0));
+
   rtx_op1 = expand_expr (t_op1, NULL_RTX, TYPE_MODE (TREE_TYPE (t_op1)),
                         EXPAND_STACK_PARM);
+  m1 = GET_MODE (rtx_op1);
+  if (m1 == VOIDmode)
+    m1 = TYPE_MODE (TREE_TYPE (t_op1));
 
-  create_input_operand (&ops[0], rtx_op0, GET_MODE (rtx_op0));
-  create_input_operand (&ops[1], rtx_op1, GET_MODE (rtx_op1));
+  create_input_operand (&ops[0], rtx_op0, m0);
+  create_input_operand (&ops[1], rtx_op1, m1);
   if (!maybe_legitimize_operands (icode, 4, 2, ops))
     gcc_unreachable ();
   return gen_rtx_fmt_ee (rcode, VOIDmode, ops[0].value, ops[1].value);
 }
 
-/* Return true if VEC_PERM_EXPR can be expanded using SIMD extensions
-   of the CPU.  SEL may be NULL, which stands for an unknown constant.  */
+/* Return true if VEC_PERM_EXPR of arbitrary input vectors can be expanded using
+   SIMD extensions of the CPU.  SEL may be NULL, which stands for an unknown
+   constant.  Note that additional permutations representing whole-vector shifts
+   may also be handled via the vec_shr optab, but only where the second input
+   vector is entirely constant zeroes; this case is not dealt with here.  */
 
 bool
-can_vec_perm_p (enum machine_mode mode, bool variable,
+can_vec_perm_p (machine_mode mode, bool variable,
                const unsigned char *sel)
 {
-  enum machine_mode qimode;
+  machine_mode qimode;
 
   /* If the target doesn't implement a vector mode for the vector type,
      then no operations are supported.  */
@@ -6467,14 +6602,42 @@ can_vec_perm_p (enum machine_mode mode, bool variable,
   return true;
 }
 
+/* Checks if vec_perm mask SEL is a constant equivalent to a shift of the first
+   vec_perm operand, assuming the second operand is a constant vector of zeroes.
+   Return the shift distance in bits if so, or NULL_RTX if the vec_perm is not a
+   shift.  */
+static rtx
+shift_amt_for_vec_perm_mask (rtx sel)
+{
+  unsigned int i, first, nelt = GET_MODE_NUNITS (GET_MODE (sel));
+  unsigned int bitsize = GET_MODE_BITSIZE (GET_MODE_INNER (GET_MODE (sel)));
+
+  if (GET_CODE (sel) != CONST_VECTOR)
+    return NULL_RTX;
+
+  first = INTVAL (CONST_VECTOR_ELT (sel, 0));
+  if (first >= 2*nelt)
+    return NULL_RTX;
+  for (i = 1; i < nelt; i++)
+    {
+      int idx = INTVAL (CONST_VECTOR_ELT (sel, i));
+      unsigned int expected = (i + first) & (2 * nelt - 1);
+      /* Indices into the second vector are all equivalent.  */
+      if (idx < 0 || (MIN (nelt, (unsigned) idx) != MIN (nelt, expected)))
+       return NULL_RTX;
+    }
+
+  return GEN_INT (first * bitsize);
+}
+
 /* A subroutine of expand_vec_perm for expanding one vec_perm insn.  */
 
 static rtx
 expand_vec_perm_1 (enum insn_code icode, rtx target,
                   rtx v0, rtx v1, rtx sel)
 {
-  enum machine_mode tmode = GET_MODE (target);
-  enum machine_mode smode = GET_MODE (sel);
+  machine_mode tmode = GET_MODE (target);
+  machine_mode smode = GET_MODE (sel);
   struct expand_operand ops[4];
 
   create_output_operand (&ops[0], target, tmode);
@@ -6495,6 +6658,17 @@ expand_vec_perm_1 (enum insn_code icode, rtx target,
   else
     {
       create_input_operand (&ops[1], v0, tmode);
+      /* See if this can be handled with a vec_shr.  We only do this if the
+         second vector is all zeroes.  */
+      enum insn_code shift_code = optab_handler (vec_shr_optab, GET_MODE (v0));
+      if (v1 == CONST0_RTX (GET_MODE (v1)) && shift_code)
+       if (rtx shift_amt = shift_amt_for_vec_perm_mask (sel))
+         {
+           create_convert_operand_from_type (&ops[2], shift_amt,
+                                             sizetype_tab[(int) stk_sizetype]);
+           if (maybe_expand_insn (shift_code, 3, ops))
+             return ops[0].value;
+         }
       create_input_operand (&ops[2], v1, tmode);
     }
 
@@ -6507,10 +6681,10 @@ expand_vec_perm_1 (enum insn_code icode, rtx target,
    and three operands.  */
 
 rtx
-expand_vec_perm (enum machine_mode mode, rtx v0, rtx v1, rtx sel, rtx target)
+expand_vec_perm (machine_mode mode, rtx v0, rtx v1, rtx sel, rtx target)
 {
   enum insn_code icode;
-  enum machine_mode qimode;
+  machine_mode qimode;
   unsigned int i, w, e, u;
   rtx tmp, sel_qi = NULL;
   rtvec vec;
@@ -6564,8 +6738,8 @@ expand_vec_perm (enum machine_mode mode, rtx v0, rtx v1, rtx sel, rtx target)
          icode = direct_optab_handler (vec_perm_const_optab, qimode);
          if (icode != CODE_FOR_nothing)
            {
-             tmp = expand_vec_perm_1 (icode, gen_lowpart (qimode, target),
-                                      gen_lowpart (qimode, v0),
+             tmp = mode != qimode ? gen_reg_rtx (qimode) : target;
+             tmp = expand_vec_perm_1 (icode, tmp, gen_lowpart (qimode, v0),
                                       gen_lowpart (qimode, v1), sel_qi);
              if (tmp)
                return gen_lowpart (mode, tmp);
@@ -6593,14 +6767,14 @@ expand_vec_perm (enum machine_mode mode, rtx v0, rtx v1, rtx sel, rtx target)
   if (sel_qi == NULL)
     {
       /* Multiply each element by its byte size.  */
-      enum machine_mode selmode = GET_MODE (sel);
+      machine_mode selmode = GET_MODE (sel);
       if (u == 2)
        sel = expand_simple_binop (selmode, PLUS, sel, sel,
-                                  sel, 0, OPTAB_DIRECT);
+                                  NULL, 0, OPTAB_DIRECT);
       else
        sel = expand_simple_binop (selmode, ASHIFT, sel,
                                   GEN_INT (exact_log2 (u)),
-                                  sel, 0, OPTAB_DIRECT);
+                                  NULL, 0, OPTAB_DIRECT);
       gcc_assert (sel != NULL);
 
       /* Broadcast the low byte each element into each of its bytes.  */
@@ -6629,8 +6803,8 @@ expand_vec_perm (enum machine_mode mode, rtx v0, rtx v1, rtx sel, rtx target)
       gcc_assert (sel_qi != NULL);
     }
 
-  tmp = expand_vec_perm_1 (icode, gen_lowpart (qimode, target),
-                          gen_lowpart (qimode, v0),
+  tmp = mode != qimode ? gen_reg_rtx (qimode) : target;
+  tmp = expand_vec_perm_1 (icode, tmp, gen_lowpart (qimode, v0),
                           gen_lowpart (qimode, v1), sel_qi);
   if (tmp)
     tmp = gen_lowpart (mode, tmp);
@@ -6641,7 +6815,7 @@ expand_vec_perm (enum machine_mode mode, rtx v0, rtx v1, rtx sel, rtx target)
    mode CMODE, unsigned if UNS is true, resulting in a value of mode VMODE.  */
 
 static inline enum insn_code
-get_vcond_icode (enum machine_mode vmode, enum machine_mode cmode, bool uns)
+get_vcond_icode (machine_mode vmode, machine_mode cmode, bool uns)
 {
   enum insn_code icode = CODE_FOR_nothing;
   if (uns)
@@ -6658,8 +6832,8 @@ get_vcond_icode (enum machine_mode vmode, enum machine_mode cmode, bool uns)
 bool
 expand_vec_cond_expr_p (tree value_type, tree cmp_op_type)
 {
-  enum machine_mode value_mode = TYPE_MODE (value_type);
-  enum machine_mode cmp_op_mode = TYPE_MODE (cmp_op_type);
+  machine_mode value_mode = TYPE_MODE (value_type);
+  machine_mode cmp_op_mode = TYPE_MODE (cmp_op_type);
   if (GET_MODE_SIZE (value_mode) != GET_MODE_SIZE (cmp_op_mode)
       || GET_MODE_NUNITS (value_mode) != GET_MODE_NUNITS (cmp_op_mode)
       || get_vcond_icode (TYPE_MODE (value_type), TYPE_MODE (cmp_op_type),
@@ -6678,8 +6852,8 @@ expand_vec_cond_expr (tree vec_cond_type, tree op0, tree op1, tree op2,
   struct expand_operand ops[6];
   enum insn_code icode;
   rtx comparison, rtx_op1, rtx_op2;
-  enum machine_mode mode = TYPE_MODE (vec_cond_type);
-  enum machine_mode cmp_op_mode;
+  machine_mode mode = TYPE_MODE (vec_cond_type);
+  machine_mode cmp_op_mode;
   bool unsignedp;
   tree op0a, op0b;
   enum tree_code tcode;
@@ -6728,7 +6902,7 @@ expand_vec_cond_expr (tree vec_cond_type, tree op0, tree op1, tree op2,
    2 for even/odd widening, and 3 for hi/lo widening.  */
 
 int
-can_mult_highpart_p (enum machine_mode mode, bool uns_p)
+can_mult_highpart_p (machine_mode mode, bool uns_p)
 {
   optab op;
   unsigned char *sel;
@@ -6777,13 +6951,13 @@ can_mult_highpart_p (enum machine_mode mode, bool uns_p)
 /* Expand a highpart multiply.  */
 
 rtx
-expand_mult_highpart (enum machine_mode mode, rtx op0, rtx op1,
+expand_mult_highpart (machine_mode mode, rtx op0, rtx op1,
                      rtx target, bool uns_p)
 {
   struct expand_operand eops[3];
   enum insn_code icode;
   int method, i, nunits;
-  enum machine_mode wmode;
+  machine_mode wmode;
   rtx m1, m2, perm;
   optab tab1, tab2;
   rtvec v;
@@ -6849,11 +7023,50 @@ expand_mult_highpart (enum machine_mode mode, rtx op0, rtx op1,
 
   return expand_vec_perm (mode, m1, m2, perm, target);
 }
+
+/* Return true if target supports vector masked load/store for mode.  */
+bool
+can_vec_mask_load_store_p (machine_mode mode, bool is_load)
+{
+  optab op = is_load ? maskload_optab : maskstore_optab;
+  machine_mode vmode;
+  unsigned int vector_sizes;
+
+  /* If mode is vector mode, check it directly.  */
+  if (VECTOR_MODE_P (mode))
+    return optab_handler (op, mode) != CODE_FOR_nothing;
+
+  /* Otherwise, return true if there is some vector mode with
+     the mask load/store supported.  */
+
+  /* See if there is any chance the mask load or store might be
+     vectorized.  If not, punt.  */
+  vmode = targetm.vectorize.preferred_simd_mode (mode);
+  if (!VECTOR_MODE_P (vmode))
+    return false;
+
+  if (optab_handler (op, vmode) != CODE_FOR_nothing)
+    return true;
+
+  vector_sizes = targetm.vectorize.autovectorize_vector_sizes ();
+  while (vector_sizes != 0)
+    {
+      unsigned int cur = 1 << floor_log2 (vector_sizes);
+      vector_sizes &= ~cur;
+      if (cur <= GET_MODE_SIZE (mode))
+       continue;
+      vmode = mode_for_vector (mode, cur / GET_MODE_SIZE (mode));
+      if (VECTOR_MODE_P (vmode)
+         && optab_handler (op, vmode) != CODE_FOR_nothing)
+       return true;
+    }
+  return false;
+}
 \f
 /* Return true if there is a compare_and_swap pattern.  */
 
 bool
-can_compare_and_swap_p (enum machine_mode mode, bool allow_libcall)
+can_compare_and_swap_p (machine_mode mode, bool allow_libcall)
 {
   enum insn_code icode;
 
@@ -6876,7 +7089,7 @@ can_compare_and_swap_p (enum machine_mode mode, bool allow_libcall)
 /* Return true if an atomic exchange can be performed.  */
 
 bool
-can_atomic_exchange_p (enum machine_mode mode, bool allow_libcall)
+can_atomic_exchange_p (machine_mode mode, bool allow_libcall)
 {
   enum insn_code icode;
 
@@ -6920,8 +7133,9 @@ find_cc_set (rtx x, const_rtx pat, void *data)
 static bool
 expand_compare_and_swap_loop (rtx mem, rtx old_reg, rtx new_reg, rtx seq)
 {
-  enum machine_mode mode = GET_MODE (mem);
-  rtx label, cmp_reg, success, oldval;
+  machine_mode mode = GET_MODE (mem);
+  rtx_code_label *label;
+  rtx cmp_reg, success, oldval;
 
   /* The loop we want to generate looks like
 
@@ -6948,7 +7162,7 @@ expand_compare_and_swap_loop (rtx mem, rtx old_reg, rtx new_reg, rtx seq)
   success = NULL_RTX;
   oldval = cmp_reg;
   if (!expand_atomic_compare_and_swap (&success, &oldval, mem, old_reg,
-                                      new_reg, false, MEMMODEL_SEQ_CST,
+                                      new_reg, false, MEMMODEL_SYNC_SEQ_CST,
                                       MEMMODEL_RELAXED))
     return false;
 
@@ -6969,7 +7183,7 @@ expand_compare_and_swap_loop (rtx mem, rtx old_reg, rtx new_reg, rtx seq)
 static rtx
 maybe_emit_atomic_exchange (rtx target, rtx mem, rtx val, enum memmodel model)
 {
-  enum machine_mode mode = GET_MODE (mem);
+  machine_mode mode = GET_MODE (mem);
   enum insn_code icode;
 
   /* If the target supports the exchange directly, great.  */
@@ -6980,8 +7194,7 @@ maybe_emit_atomic_exchange (rtx target, rtx mem, rtx val, enum memmodel model)
 
       create_output_operand (&ops[0], target, mode);
       create_fixed_operand (&ops[1], mem);
-      /* VAL may have been promoted to a wider mode.  Shrink it if so.  */
-      create_convert_operand_to (&ops[2], val, mode, true);
+      create_input_operand (&ops[2], val, mode);
       create_integer_operand (&ops[3], model);
       if (maybe_expand_insn (icode, 4, ops))
        return ops[0].value;
@@ -7000,9 +7213,9 @@ static rtx
 maybe_emit_sync_lock_test_and_set (rtx target, rtx mem, rtx val,
                                   enum memmodel model)
 {
-  enum machine_mode mode = GET_MODE (mem);
+  machine_mode mode = GET_MODE (mem);
   enum insn_code icode;
-  rtx last_insn = get_last_insn ();
+  rtx_insn *last_insn = get_last_insn ();
 
   icode = optab_handler (sync_lock_test_and_set_optab, mode);
 
@@ -7010,9 +7223,7 @@ maybe_emit_sync_lock_test_and_set (rtx target, rtx mem, rtx val,
      exists, and the memory model is stronger than acquire, add a release 
      barrier before the instruction.  */
 
-  if (model == MEMMODEL_SEQ_CST
-      || model == MEMMODEL_RELEASE
-      || model == MEMMODEL_ACQ_REL)
+  if (is_mm_seq_cst (model) || is_mm_release (model) || is_mm_acq_rel (model))
     expand_mem_thread_fence (model);
 
   if (icode != CODE_FOR_nothing)
@@ -7020,8 +7231,7 @@ maybe_emit_sync_lock_test_and_set (rtx target, rtx mem, rtx val,
       struct expand_operand ops[3];
       create_output_operand (&ops[0], target, mode);
       create_fixed_operand (&ops[1], mem);
-      /* VAL may have been promoted to a wider mode.  Shrink it if so.  */
-      create_convert_operand_to (&ops[2], val, mode, true);
+      create_input_operand (&ops[2], val, mode);
       if (maybe_expand_insn (icode, 3, ops))
        return ops[0].value;
     }
@@ -7057,14 +7267,12 @@ maybe_emit_sync_lock_test_and_set (rtx target, rtx mem, rtx val,
 static rtx 
 maybe_emit_compare_and_swap_exchange_loop (rtx target, rtx mem, rtx val)
 {
-  enum machine_mode mode = GET_MODE (mem);
+  machine_mode mode = GET_MODE (mem);
 
   if (can_compare_and_swap_p (mode, true))
     {
       if (!target || !register_operand (target, mode))
        target = gen_reg_rtx (mode);
-      if (GET_MODE (val) != VOIDmode && GET_MODE (val) != mode)
-       val = convert_modes (mode, GET_MODE (val), val, 1);
       if (expand_compare_and_swap_loop (mem, target, val, NULL_RTX))
        return target;
     }
@@ -7084,7 +7292,7 @@ maybe_emit_compare_and_swap_exchange_loop (rtx target, rtx mem, rtx val)
 static rtx
 maybe_emit_atomic_test_and_set (rtx target, rtx mem, enum memmodel model)
 {
-  enum machine_mode pat_bool_mode;
+  machine_mode pat_bool_mode;
   struct expand_operand ops[3];
 
   if (!HAVE_atomic_test_and_set)
@@ -7122,11 +7330,12 @@ expand_sync_lock_test_and_set (rtx target, rtx mem, rtx val)
   rtx ret;
 
   /* Try an atomic_exchange first.  */
-  ret = maybe_emit_atomic_exchange (target, mem, val, MEMMODEL_ACQUIRE);
+  ret = maybe_emit_atomic_exchange (target, mem, val, MEMMODEL_SYNC_ACQUIRE);
   if (ret)
     return ret;
 
-  ret = maybe_emit_sync_lock_test_and_set (target, mem, val, MEMMODEL_ACQUIRE);
+  ret = maybe_emit_sync_lock_test_and_set (target, mem, val,
+                                          MEMMODEL_SYNC_ACQUIRE);
   if (ret)
     return ret;
 
@@ -7137,7 +7346,7 @@ expand_sync_lock_test_and_set (rtx target, rtx mem, rtx val)
   /* If there are no other options, try atomic_test_and_set if the value
      being stored is 1.  */
   if (val == const1_rtx)
-    ret = maybe_emit_atomic_test_and_set (target, mem, MEMMODEL_ACQUIRE);
+    ret = maybe_emit_atomic_test_and_set (target, mem, MEMMODEL_SYNC_ACQUIRE);
 
   return ret;
 }
@@ -7151,7 +7360,7 @@ expand_sync_lock_test_and_set (rtx target, rtx mem, rtx val)
 rtx
 expand_atomic_test_and_set (rtx target, rtx mem, enum memmodel model)
 {
-  enum machine_mode mode = GET_MODE (mem);
+  machine_mode mode = GET_MODE (mem);
   rtx ret, trueval, subtarget;
 
   ret = maybe_emit_atomic_test_and_set (target, mem, model);
@@ -7192,7 +7401,10 @@ expand_atomic_test_and_set (rtx target, rtx mem, enum memmodel model)
      perform the operation.  */
   if (!ret)
     {
-      emit_move_insn (subtarget, mem);
+      /* If the result is ignored skip the move to target.  */
+      if (subtarget != const0_rtx)
+        emit_move_insn (subtarget, mem);
+
       emit_move_insn (mem, trueval);
       ret = subtarget;
     }
@@ -7243,7 +7455,7 @@ expand_atomic_compare_and_swap (rtx *ptarget_bool, rtx *ptarget_oval,
                                bool is_weak, enum memmodel succ_model,
                                enum memmodel fail_model)
 {
-  enum machine_mode mode = GET_MODE (mem);
+  machine_mode mode = GET_MODE (mem);
   struct expand_operand ops[8];
   enum insn_code icode;
   rtx target_oval, target_bool = NULL_RTX;
@@ -7264,7 +7476,7 @@ expand_atomic_compare_and_swap (rtx *ptarget_bool, rtx *ptarget_oval,
   icode = direct_optab_handler (atomic_compare_and_swap_optab, mode);
   if (icode != CODE_FOR_nothing)
     {
-      enum machine_mode bool_mode = insn_data[icode].operand[0].mode;
+      machine_mode bool_mode = insn_data[icode].operand[0].mode;
 
       /* Make sure we always have a place for the bool operand.  */
       if (ptarget_bool == NULL
@@ -7276,17 +7488,18 @@ expand_atomic_compare_and_swap (rtx *ptarget_bool, rtx *ptarget_oval,
       create_output_operand (&ops[0], target_bool, bool_mode);
       create_output_operand (&ops[1], target_oval, mode);
       create_fixed_operand (&ops[2], mem);
-      create_convert_operand_to (&ops[3], expected, mode, true);
-      create_convert_operand_to (&ops[4], desired, mode, true);
+      create_input_operand (&ops[3], expected, mode);
+      create_input_operand (&ops[4], desired, mode);
       create_integer_operand (&ops[5], is_weak);
       create_integer_operand (&ops[6], succ_model);
       create_integer_operand (&ops[7], fail_model);
-      expand_insn (icode, 8, ops);
-
-      /* Return success/failure.  */
-      target_bool = ops[0].value;
-      target_oval = ops[1].value;
-      goto success;
+      if (maybe_expand_insn (icode, 8, ops))
+       {
+         /* Return success/failure.  */
+         target_bool = ops[0].value;
+         target_oval = ops[1].value;
+         goto success;
+       }
     }
 
   /* Otherwise fall back to the original __sync_val_compare_and_swap
@@ -7298,8 +7511,8 @@ expand_atomic_compare_and_swap (rtx *ptarget_bool, rtx *ptarget_oval,
 
       create_output_operand (&ops[0], target_oval, mode);
       create_fixed_operand (&ops[1], mem);
-      create_convert_operand_to (&ops[2], expected, mode, true);
-      create_convert_operand_to (&ops[3], desired, mode, true);
+      create_input_operand (&ops[2], expected, mode);
+      create_input_operand (&ops[3], desired, mode);
       if (!maybe_expand_insn (icode, 4, ops))
        return false;
 
@@ -7376,21 +7589,12 @@ expand_asm_memory_barrier (void)
 /* This routine will either emit the mem_thread_fence pattern or issue a 
    sync_synchronize to generate a fence for memory model MEMMODEL.  */
 
-#ifndef HAVE_mem_thread_fence
-# define HAVE_mem_thread_fence 0
-# define gen_mem_thread_fence(x) (gcc_unreachable (), NULL_RTX)
-#endif
-#ifndef HAVE_memory_barrier
-# define HAVE_memory_barrier 0
-# define gen_memory_barrier()  (gcc_unreachable (), NULL_RTX)
-#endif
-
 void
 expand_mem_thread_fence (enum memmodel model)
 {
   if (HAVE_mem_thread_fence)
     emit_insn (gen_mem_thread_fence (GEN_INT (model)));
-  else if (model != MEMMODEL_RELAXED)
+  else if (!is_mm_relaxed (model))
     {
       if (HAVE_memory_barrier)
        emit_insn (gen_memory_barrier ());
@@ -7404,17 +7608,12 @@ expand_mem_thread_fence (enum memmodel model)
 /* This routine will either emit the mem_signal_fence pattern or issue a 
    sync_synchronize to generate a fence for memory model MEMMODEL.  */
 
-#ifndef HAVE_mem_signal_fence
-# define HAVE_mem_signal_fence 0
-# define gen_mem_signal_fence(x) (gcc_unreachable (), NULL_RTX)
-#endif
-
 void
 expand_mem_signal_fence (enum memmodel model)
 {
   if (HAVE_mem_signal_fence)
     emit_insn (gen_mem_signal_fence (GEN_INT (model)));
-  else if (model != MEMMODEL_RELAXED)
+  else if (!is_mm_relaxed (model))
     {
       /* By default targets are coherent between a thread and the signal
         handler running on the same thread.  Thus this really becomes a
@@ -7433,7 +7632,7 @@ expand_mem_signal_fence (enum memmodel model)
 rtx
 expand_atomic_load (rtx target, rtx mem, enum memmodel model)
 {
-  enum machine_mode mode = GET_MODE (mem);
+  machine_mode mode = GET_MODE (mem);
   enum insn_code icode;
 
   /* If the target supports the load directly, great.  */
@@ -7469,7 +7668,7 @@ expand_atomic_load (rtx target, rtx mem, enum memmodel model)
     target = gen_reg_rtx (mode);
 
   /* For SEQ_CST, emit a barrier before the load.  */
-  if (model == MEMMODEL_SEQ_CST)
+  if (is_mm_seq_cst (model))
     expand_mem_thread_fence (model);
 
   emit_move_insn (target, mem);
@@ -7489,7 +7688,7 @@ expand_atomic_load (rtx target, rtx mem, enum memmodel model)
 rtx
 expand_atomic_store (rtx mem, rtx val, enum memmodel model, bool use_release)
 {
-  enum machine_mode mode = GET_MODE (mem);
+  machine_mode mode = GET_MODE (mem);
   enum insn_code icode;
   struct expand_operand ops[3];
 
@@ -7515,7 +7714,7 @@ expand_atomic_store (rtx mem, rtx val, enum memmodel model, bool use_release)
          if (maybe_expand_insn (icode, 2, ops))
            {
              /* lock_release is only a release barrier.  */
-             if (model == MEMMODEL_SEQ_CST)
+             if (is_mm_seq_cst (model))
                expand_mem_thread_fence (model);
              return const0_rtx;
            }
@@ -7525,7 +7724,7 @@ expand_atomic_store (rtx mem, rtx val, enum memmodel model, bool use_release)
   /* If the size of the object is greater than word size on this target,
      a default store will not be atomic, Try a mem_exchange and throw away
      the result.  If that doesn't work, don't do anything.  */
-  if (GET_MODE_PRECISION(mode) > BITS_PER_WORD)
+  if (GET_MODE_PRECISION (mode) > BITS_PER_WORD)
     {
       rtx target = maybe_emit_atomic_exchange (NULL_RTX, mem, val, model);
       if (!target)
@@ -7542,7 +7741,7 @@ expand_atomic_store (rtx mem, rtx val, enum memmodel model, bool use_release)
   emit_move_insn (mem, val);
 
   /* For SEQ_CST, also emit a barrier after the store.  */
-  if (model == MEMMODEL_SEQ_CST)
+  if (is_mm_seq_cst (model))
     expand_mem_thread_fence (model);
 
   return const0_rtx;
@@ -7684,7 +7883,7 @@ static rtx
 maybe_emit_op (const struct atomic_op_functions *optab, rtx target, rtx mem,
               rtx val, bool use_memmodel, enum memmodel model, bool after)
 {
-  enum machine_mode mode = GET_MODE (mem);
+  machine_mode mode = GET_MODE (mem);
   struct expand_operand ops[4];
   enum insn_code icode;
   int op_counter = 0;
@@ -7754,7 +7953,7 @@ expand_atomic_fetch_op_no_fallback (rtx target, rtx mem, rtx val,
                                    enum rtx_code code, enum memmodel model,
                                    bool after)
 {
-  enum machine_mode mode = GET_MODE (mem);
+  machine_mode mode = GET_MODE (mem);
   struct atomic_op_functions optab;
   rtx result;
   bool unused_result = (target == const0_rtx);
@@ -7843,7 +8042,7 @@ rtx
 expand_atomic_fetch_op (rtx target, rtx mem, rtx val, enum rtx_code code,
                        enum memmodel model, bool after)
 {
-  enum machine_mode mode = GET_MODE (mem);
+  machine_mode mode = GET_MODE (mem);
   rtx result;
   bool unused_result = (target == const0_rtx);
 
@@ -7915,7 +8114,7 @@ expand_atomic_fetch_op (rtx target, rtx mem, rtx val, enum rtx_code code,
   /* If nothing else has succeeded, default to a compare and swap loop.  */
   if (can_compare_and_swap_p (mode, true))
     {
-      rtx insn;
+      rtx_insn *insn;
       rtx t0 = gen_reg_rtx (mode), t1;
 
       start_sequence ();
@@ -7974,7 +8173,7 @@ insn_operand_matches (enum insn_code icode, unsigned int opno, rtx operand)
 bool
 valid_multiword_target_p (rtx target)
 {
-  enum machine_mode mode;
+  machine_mode mode;
   int i;
 
   mode = GET_MODE (target);
@@ -8008,8 +8207,8 @@ maybe_legitimize_operand_same_code (enum insn_code icode, unsigned int opno,
       if (!(REG_P (addr) && REGNO (addr) > LAST_VIRTUAL_REGISTER)
          && !side_effects_p (addr))
        {
-         rtx last;
-         enum machine_mode mode;
+         rtx_insn *last;
+         machine_mode mode;
 
          last = get_last_insn ();
          mode = get_address_mode (mem);
@@ -8033,7 +8232,7 @@ static bool
 maybe_legitimize_operand (enum insn_code icode, unsigned int opno,
                          struct expand_operand *op)
 {
-  enum machine_mode mode, imode;
+  machine_mode mode, imode;
   bool old_volatile_ok, result;
 
   mode = op->mode;
@@ -8122,7 +8321,7 @@ bool
 maybe_legitimize_operands (enum insn_code icode, unsigned int opno,
                           unsigned int nops, struct expand_operand *ops)
 {
-  rtx last;
+  rtx_insn *last;
   unsigned int i;
 
   last = get_last_insn ();
@@ -8140,13 +8339,13 @@ maybe_legitimize_operands (enum insn_code icode, unsigned int opno,
    and emit any necessary set-up code.  Return null and emit no
    code on failure.  */
 
-rtx
+rtx_insn *
 maybe_gen_insn (enum insn_code icode, unsigned int nops,
                struct expand_operand *ops)
 {
   gcc_assert (nops == (unsigned int) insn_data[(int) icode].n_generator_args);
   if (!maybe_legitimize_operands (icode, 0, nops, ops))
-    return NULL_RTX;
+    return NULL;
 
   switch (nops)
     {
@@ -8173,6 +8372,10 @@ maybe_gen_insn (enum insn_code icode, unsigned int nops,
       return GEN_FCN (icode) (ops[0].value, ops[1].value, ops[2].value,
                              ops[3].value, ops[4].value, ops[5].value,
                              ops[6].value, ops[7].value);
+    case 9:
+      return GEN_FCN (icode) (ops[0].value, ops[1].value, ops[2].value,
+                             ops[3].value, ops[4].value, ops[5].value,
+                             ops[6].value, ops[7].value, ops[8].value);
     }
   gcc_unreachable ();
 }
@@ -8257,23 +8460,23 @@ enum extraction_type { ET_unaligned_mem, ET_reg };
 static bool
 get_traditional_extraction_insn (extraction_insn *insn,
                                 enum extraction_type type,
-                                enum machine_mode mode,
+                                machine_mode mode,
                                 enum insn_code icode,
                                 int struct_op, int field_op)
 {
   const struct insn_data_d *data = &insn_data[icode];
 
-  enum machine_mode struct_mode = data->operand[struct_op].mode;
+  machine_mode struct_mode = data->operand[struct_op].mode;
   if (struct_mode == VOIDmode)
     struct_mode = word_mode;
   if (mode != struct_mode)
     return false;
 
-  enum machine_mode field_mode = data->operand[field_op].mode;
+  machine_mode field_mode = data->operand[field_op].mode;
   if (field_mode == VOIDmode)
     field_mode = word_mode;
 
-  enum machine_mode pos_mode = data->operand[struct_op + 2].mode;
+  machine_mode pos_mode = data->operand[struct_op + 2].mode;
   if (pos_mode == VOIDmode)
     pos_mode = word_mode;
 
@@ -8294,7 +8497,7 @@ get_traditional_extraction_insn (extraction_insn *insn,
 static bool
 get_optab_extraction_insn (struct extraction_insn *insn,
                           enum extraction_type type,
-                          enum machine_mode mode, direct_optab reg_optab,
+                          machine_mode mode, direct_optab reg_optab,
                           direct_optab misalign_optab, int pos_op)
 {
   direct_optab optab = (type == ET_unaligned_mem ? misalign_optab : reg_optab);
@@ -8321,7 +8524,7 @@ static bool
 get_extraction_insn (extraction_insn *insn,
                     enum extraction_pattern pattern,
                     enum extraction_type type,
-                    enum machine_mode mode)
+                    machine_mode mode)
 {
   switch (pattern)
     {
@@ -8369,9 +8572,9 @@ get_best_extraction_insn (extraction_insn *insn,
                          enum extraction_pattern pattern,
                          enum extraction_type type,
                          unsigned HOST_WIDE_INT struct_bits,
-                         enum machine_mode field_mode)
+                         machine_mode field_mode)
 {
-  enum machine_mode mode = smallest_mode_for_size (struct_bits, MODE_INT);
+  machine_mode mode = smallest_mode_for_size (struct_bits, MODE_INT);
   while (mode != VOIDmode)
     {
       if (get_extraction_insn (insn, pattern, type, mode))
@@ -8405,7 +8608,7 @@ bool
 get_best_reg_extraction_insn (extraction_insn *insn,
                              enum extraction_pattern pattern,
                              unsigned HOST_WIDE_INT struct_bits,
-                             enum machine_mode field_mode)
+                             machine_mode field_mode)
 {
   return get_best_extraction_insn (insn, pattern, ET_reg, struct_bits,
                                   field_mode);
@@ -8424,7 +8627,7 @@ bool
 get_best_mem_extraction_insn (extraction_insn *insn,
                              enum extraction_pattern pattern,
                              HOST_WIDE_INT bitsize, HOST_WIDE_INT bitnum,
-                             enum machine_mode field_mode)
+                             machine_mode field_mode)
 {
   unsigned HOST_WIDE_INT struct_bits = (bitnum % BITS_PER_UNIT
                                        + bitsize
@@ -8434,4 +8637,31 @@ get_best_mem_extraction_insn (extraction_insn *insn,
                                   struct_bits, field_mode);
 }
 
+/* Determine whether "1 << x" is relatively cheap in word_mode.  */
+
+bool
+lshift_cheap_p (bool speed_p)
+{
+  /* FIXME: This should be made target dependent via this "this_target"
+     mechanism, similar to e.g. can_copy_init_p in gcse.c.  */
+  static bool init[2] = { false, false };
+  static bool cheap[2] = { true, true };
+
+  /* If the targer has no lshift in word_mode, the operation will most
+     probably not be cheap.  ??? Does GCC even work for such targets?  */
+  if (optab_handler (ashl_optab, word_mode) == CODE_FOR_nothing)
+    return false;
+
+  if (!init[speed_p])
+    {
+      rtx reg = gen_raw_REG (word_mode, 10000);
+      int cost = set_src_cost (gen_rtx_ASHIFT (word_mode, const1_rtx, reg),
+                              speed_p);
+      cheap[speed_p] = cost < COSTS_N_INSNS (3);
+      init[speed_p] = true;
+    }
+
+  return cheap[speed_p];
+}
+
 #include "gt-optabs.h"