IA MCU psABI support: changes to libraries
[gcc.git] / gcc / recog.c
index ee68e305256dc3a37158d201679457bd70b1cdba..3fbfe076ed8b1f3c682cf07c987a53886eccea65 100644 (file)
@@ -1,7 +1,5 @@
 /* Subroutines used by or related to instruction recognition.
-   Copyright (C) 1987, 1988, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998
-   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
-   Free Software Foundation, Inc.
+   Copyright (C) 1987-2015 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -24,6 +22,9 @@ along with GCC; see the file COPYING3.  If not see
 #include "system.h"
 #include "coretypes.h"
 #include "tm.h"
+#include "alias.h"
+#include "symtab.h"
+#include "tree.h"
 #include "rtl-error.h"
 #include "tm_p.h"
 #include "insn-config.h"
@@ -32,34 +33,46 @@ along with GCC; see the file COPYING3.  If not see
 #include "recog.h"
 #include "regs.h"
 #include "addresses.h"
-#include "expr.h"
 #include "function.h"
+#include "rtl.h"
 #include "flags.h"
+#include "expmed.h"
+#include "dojump.h"
+#include "explow.h"
+#include "calls.h"
+#include "emit-rtl.h"
+#include "varasm.h"
+#include "stmt.h"
+#include "expr.h"
+#include "predict.h"
+#include "dominance.h"
+#include "cfg.h"
+#include "cfgrtl.h"
+#include "cfgbuild.h"
+#include "cfgcleanup.h"
 #include "basic-block.h"
 #include "reload.h"
 #include "target.h"
 #include "tree-pass.h"
 #include "df.h"
-
-#ifndef STACK_PUSH_CODE
-#ifdef STACK_GROWS_DOWNWARD
-#define STACK_PUSH_CODE PRE_DEC
-#else
-#define STACK_PUSH_CODE PRE_INC
-#endif
-#endif
+#include "insn-codes.h"
 
 #ifndef STACK_POP_CODE
-#ifdef STACK_GROWS_DOWNWARD
+#if STACK_GROWS_DOWNWARD
 #define STACK_POP_CODE POST_INC
 #else
 #define STACK_POP_CODE POST_DEC
 #endif
 #endif
 
-static void validate_replace_rtx_1 (rtx *, rtx, rtx, rtx, bool);
+static void validate_replace_rtx_1 (rtx *, rtx, rtx, rtx_insn *, bool);
 static void validate_replace_src_1 (rtx *, void *);
-static rtx split_insn (rtx);
+static rtx_insn *split_insn (rtx_insn *);
+
+struct target_recog default_target_recog;
+#if SWITCHABLE_TARGET
+struct target_recog *this_target_recog = &default_target_recog;
+#endif
 
 /* Nonzero means allow operands to be volatile.
    This should be 0 if you are generating rtl, such as if you are calling
@@ -71,11 +84,16 @@ static rtx split_insn (rtx);
 
 int volatile_ok;
 
-struct recog_data recog_data;
+struct recog_data_d recog_data;
 
-/* Contains a vector of operand_alternative structures for every operand.
+/* Contains a vector of operand_alternative structures, such that
+   operand OP of alternative A is at index A * n_operands + OP.
    Set up by preprocess_constraints.  */
-struct operand_alternative recog_op_alt[MAX_RECOG_OPERANDS][MAX_RECOG_ALTERNATIVES];
+const operand_alternative *recog_op_alt;
+
+/* Used to provide recog_op_alt for asms.  */
+static operand_alternative asm_op_alt[MAX_RECOG_OPERANDS
+                                     * MAX_RECOG_ALTERNATIVES];
 
 /* On return from `constrain_operands', indicate which alternative
    was satisfied.  */
@@ -145,8 +163,9 @@ check_asm_operands (rtx x)
   if (reload_completed)
     {
       /* ??? Doh!  We've not got the wrapping insn.  Cook one up.  */
-      extract_insn (make_insn_raw (x));
-      constrain_operands (1);
+      rtx_insn *insn = make_insn_raw (x);
+      extract_insn (insn);
+      constrain_operands (1, get_enabled_alternatives (insn));
       return which_alternative >= 0;
     }
 
@@ -281,7 +300,7 @@ validate_unshare_change (rtx object, rtx *loc, rtx new_rtx, bool in_group)
 
    Return true if anything was changed.  */
 bool
-canonicalize_change_group (rtx insn, rtx x)
+canonicalize_change_group (rtx_insn *insn, rtx x)
 {
   if (COMMUTATIVE_P (x)
       && swap_commutative_operands_p (XEXP (x, 0), XEXP (x, 1)))
@@ -306,7 +325,7 @@ canonicalize_change_group (rtx insn, rtx x)
    Otherwise the changes will take effect immediately.  */
 
 int
-insn_invalid_p (rtx insn, bool in_group)
+insn_invalid_p (rtx_insn *insn, bool in_group)
 {
   rtx pat = PATTERN (insn);
   int num_clobbers = 0;
@@ -314,7 +333,8 @@ insn_invalid_p (rtx insn, bool in_group)
      clobbers.  */
   int icode = recog (pat, insn,
                     (GET_CODE (pat) == SET
-                     && ! reload_completed && ! reload_in_progress)
+                     && ! reload_completed 
+                      && ! reload_in_progress)
                     ? &num_clobbers : 0);
   int is_asm = icode < 0 && asm_noperands (PATTERN (insn)) >= 0;
 
@@ -349,7 +369,7 @@ insn_invalid_p (rtx insn, bool in_group)
     {
       extract_insn (insn);
 
-      if (! constrain_operands (1))
+      if (! constrain_operands (1, get_preferred_alternatives (insn)))
        return 1;
     }
 
@@ -398,7 +418,10 @@ verify_changes (int num)
                                             MEM_ADDR_SPACE (object)))
            break;
        }
-      else if (REG_P (changes[i].old)
+      else if (/* changes[i].old might be zero, e.g. when putting a
+              REG_FRAME_RELATED_EXPR into a previously empty list.  */
+              changes[i].old
+              && REG_P (changes[i].old)
               && asm_noperands (PATTERN (object)) > 0
               && REG_EXPR (changes[i].old) != NULL_TREE
               && DECL_ASSEMBLER_NAME_SET_P (REG_EXPR (changes[i].old))
@@ -410,7 +433,7 @@ verify_changes (int num)
        }
       else if (DEBUG_INSN_P (object))
        continue;
-      else if (insn_invalid_p (object, true))
+      else if (insn_invalid_p (as_a <rtx_insn *> (object), true))
        {
          rtx pat = PATTERN (object);
 
@@ -486,13 +509,13 @@ confirm_change_group (void)
       if (object)
        {
          if (object != last_object && last_object && INSN_P (last_object))
-           df_insn_rescan (last_object);
+           df_insn_rescan (as_a <rtx_insn *> (last_object));
          last_object = object;
        }
     }
 
   if (last_object && INSN_P (last_object))
-    df_insn_rescan (last_object);
+    df_insn_rescan (as_a <rtx_insn *> (last_object));
   num_changes = 0;
 }
 
@@ -542,16 +565,26 @@ cancel_changes (int num)
   num_changes = num;
 }
 
+/* Reduce conditional compilation elsewhere.  */
+#ifndef HAVE_extv
+#define HAVE_extv      0
+#define CODE_FOR_extv  CODE_FOR_nothing
+#endif
+#ifndef HAVE_extzv
+#define HAVE_extzv     0
+#define CODE_FOR_extzv CODE_FOR_nothing
+#endif
+
 /* A subroutine of validate_replace_rtx_1 that tries to simplify the resulting
    rtx.  */
 
 static void
-simplify_while_replacing (rtx *loc, rtx to, rtx object,
-                          enum machine_mode op0_mode)
+simplify_while_replacing (rtx *loc, rtx to, rtx_insn *object,
+                          machine_mode op0_mode)
 {
   rtx x = *loc;
   enum rtx_code code = GET_CODE (x);
-  rtx new_rtx;
+  rtx new_rtx = NULL_RTX;
 
   if (SWAPPABLE_OPERANDS_P (x)
       && swap_commutative_operands_p (XEXP (x, 0), XEXP (x, 1)))
@@ -565,6 +598,35 @@ simplify_while_replacing (rtx *loc, rtx to, rtx object,
       code = GET_CODE (x);
     }
 
+  /* Canonicalize arithmetics with all constant operands.  */
+  switch (GET_RTX_CLASS (code))
+    {
+    case RTX_UNARY:
+      if (CONSTANT_P (XEXP (x, 0)))
+       new_rtx = simplify_unary_operation (code, GET_MODE (x), XEXP (x, 0),
+                                           op0_mode);
+      break;
+    case RTX_COMM_ARITH:
+    case RTX_BIN_ARITH:
+      if (CONSTANT_P (XEXP (x, 0)) && CONSTANT_P (XEXP (x, 1)))
+       new_rtx = simplify_binary_operation (code, GET_MODE (x), XEXP (x, 0),
+                                            XEXP (x, 1));
+      break;
+    case RTX_COMPARE:
+    case RTX_COMM_COMPARE:
+      if (CONSTANT_P (XEXP (x, 0)) && CONSTANT_P (XEXP (x, 1)))
+       new_rtx = simplify_relational_operation (code, GET_MODE (x), op0_mode,
+                                                XEXP (x, 0), XEXP (x, 1));
+      break;
+    default:
+      break;
+    }
+  if (new_rtx)
+    {
+      validate_change (object, loc, new_rtx, 1);
+      return;
+    }
+
   switch (code)
     {
     case PLUS:
@@ -624,23 +686,21 @@ simplify_while_replacing (rtx *loc, rtx to, rtx object,
                                        MEM_ADDR_SPACE (XEXP (x, 0)))
          && !MEM_VOLATILE_P (XEXP (x, 0)))
        {
-         enum machine_mode wanted_mode = VOIDmode;
-         enum machine_mode is_mode = GET_MODE (XEXP (x, 0));
+         machine_mode wanted_mode = VOIDmode;
+         machine_mode is_mode = GET_MODE (XEXP (x, 0));
          int pos = INTVAL (XEXP (x, 2));
 
-         if (GET_CODE (x) == ZERO_EXTRACT)
+         if (GET_CODE (x) == ZERO_EXTRACT && HAVE_extzv)
            {
-             enum machine_mode new_mode
-               = mode_for_extraction (EP_extzv, 1);
-             if (new_mode != MAX_MACHINE_MODE)
-               wanted_mode = new_mode;
+             wanted_mode = insn_data[CODE_FOR_extzv].operand[1].mode;
+             if (wanted_mode == VOIDmode)
+               wanted_mode = word_mode;
            }
-         else if (GET_CODE (x) == SIGN_EXTRACT)
+         else if (GET_CODE (x) == SIGN_EXTRACT && HAVE_extv)
            {
-             enum machine_mode new_mode
-               = mode_for_extraction (EP_extv, 1);
-             if (new_mode != MAX_MACHINE_MODE)
-               wanted_mode = new_mode;
+             wanted_mode = insn_data[CODE_FOR_extv].operand[1].mode;
+             if (wanted_mode == VOIDmode)
+               wanted_mode = word_mode;
            }
 
          /* If we have a narrower mode, we can do something.  */
@@ -679,14 +739,14 @@ simplify_while_replacing (rtx *loc, rtx to, rtx object,
    validate_change passing OBJECT.  */
 
 static void
-validate_replace_rtx_1 (rtx *loc, rtx from, rtx to, rtx object,
+validate_replace_rtx_1 (rtx *loc, rtx from, rtx to, rtx_insn *object,
                         bool simplify)
 {
   int i, j;
   const char *fmt;
   rtx x = *loc;
   enum rtx_code code;
-  enum machine_mode op0_mode = VOIDmode;
+  machine_mode op0_mode = VOIDmode;
   int prev_changes = num_changes;
 
   if (!x)
@@ -715,7 +775,7 @@ validate_replace_rtx_1 (rtx *loc, rtx from, rtx to, rtx object,
   /* Call ourself recursively to perform the replacements.
      We must not replace inside already replaced expression, otherwise we
      get infinite recursion for replacements like (reg X)->(subreg (reg X))
-     done by regmove, so we must special case shared ASM_OPERANDS.  */
+     so we must special case shared ASM_OPERANDS.  */
 
   if (GET_CODE (x) == PARALLEL)
     {
@@ -751,6 +811,7 @@ validate_replace_rtx_1 (rtx *loc, rtx from, rtx to, rtx object,
   if (num_changes == prev_changes)
     return;
 
+  /* ??? The regmove is no more, so is this aberration still necessary?  */
   /* Allow substituted expression to have different mode.  This is used by
      regmove to change mode of pseudo register.  */
   if (fmt[0] == 'e' && GET_MODE (XEXP (x, 0)) != VOIDmode)
@@ -767,7 +828,7 @@ validate_replace_rtx_1 (rtx *loc, rtx from, rtx to, rtx object,
    if INSN is still valid.  */
 
 int
-validate_replace_rtx_subexp (rtx from, rtx to, rtx insn, rtx *loc)
+validate_replace_rtx_subexp (rtx from, rtx to, rtx_insn *insn, rtx *loc)
 {
   validate_replace_rtx_1 (loc, from, to, insn, true);
   return apply_change_group ();
@@ -777,7 +838,7 @@ validate_replace_rtx_subexp (rtx from, rtx to, rtx insn, rtx *loc)
    changes have been made, validate by seeing if INSN is still valid.  */
 
 int
-validate_replace_rtx (rtx from, rtx to, rtx insn)
+validate_replace_rtx (rtx from, rtx to, rtx_insn *insn)
 {
   validate_replace_rtx_1 (&PATTERN (insn), from, to, insn, true);
   return apply_change_group ();
@@ -790,7 +851,7 @@ validate_replace_rtx (rtx from, rtx to, rtx insn)
    validate_replace_rtx_part (from, to, &PATTERN (insn), insn).  */
 
 int
-validate_replace_rtx_part (rtx from, rtx to, rtx *where, rtx insn)
+validate_replace_rtx_part (rtx from, rtx to, rtx *where, rtx_insn *insn)
 {
   validate_replace_rtx_1 (where, from, to, insn, true);
   return apply_change_group ();
@@ -799,7 +860,7 @@ validate_replace_rtx_part (rtx from, rtx to, rtx *where, rtx insn)
 /* Same as above, but do not simplify rtx afterwards.  */
 int
 validate_replace_rtx_part_nosimplify (rtx from, rtx to, rtx *where,
-                                      rtx insn)
+                                     rtx_insn *insn)
 {
   validate_replace_rtx_1 (where, from, to, insn, false);
   return apply_change_group ();
@@ -810,7 +871,7 @@ validate_replace_rtx_part_nosimplify (rtx from, rtx to, rtx *where,
    will replace in REG_EQUAL and REG_EQUIV notes.  */
 
 void
-validate_replace_rtx_group (rtx from, rtx to, rtx insn)
+validate_replace_rtx_group (rtx from, rtx to, rtx_insn *insn)
 {
   rtx note;
   validate_replace_rtx_1 (&PATTERN (insn), from, to, insn, true);
@@ -825,7 +886,7 @@ struct validate_replace_src_data
 {
   rtx from;                    /* Old RTX */
   rtx to;                      /* New RTX */
-  rtx insn;                    /* Insn in which substitution is occurring.  */
+  rtx_insn *insn;                      /* Insn in which substitution is occurring.  */
 };
 
 static void
@@ -841,7 +902,7 @@ validate_replace_src_1 (rtx *x, void *data)
    SET_DESTs.  */
 
 void
-validate_replace_src_group (rtx from, rtx to, rtx insn)
+validate_replace_src_group (rtx from, rtx to, rtx_insn *insn)
 {
   struct validate_replace_src_data d;
 
@@ -856,7 +917,7 @@ validate_replace_src_group (rtx from, rtx to, rtx insn)
    pattern and return true if something was simplified.  */
 
 bool
-validate_simplify_insn (rtx insn)
+validate_simplify_insn (rtx_insn *insn)
 {
   int i;
   rtx pat = NULL;
@@ -891,15 +952,14 @@ validate_simplify_insn (rtx insn)
   return ((num_changes_pending () > 0) && (apply_change_group () > 0));
 }
 \f
-#ifdef HAVE_cc0
 /* Return 1 if the insn using CC0 set by INSN does not contain
    any ordered tests applied to the condition codes.
    EQ and NE tests do not count.  */
 
 int
-next_insn_tests_no_inequality (rtx insn)
+next_insn_tests_no_inequality (rtx_insn *insn)
 {
-  rtx next = next_cc0_user (insn);
+  rtx_insn *next = next_cc0_user (insn);
 
   /* If there is no next insn, we have to take the conservative choice.  */
   if (next == 0)
@@ -908,7 +968,6 @@ next_insn_tests_no_inequality (rtx insn)
   return (INSN_P (next)
          && ! inequality_comparisons_p (PATTERN (next)));
 }
-#endif
 \f
 /* Return 1 if OP is a valid general operand for machine mode MODE.
    This is either a register reference, a memory reference,
@@ -925,7 +984,7 @@ next_insn_tests_no_inequality (rtx insn)
    expressions in the machine description.  */
 
 int
-general_operand (rtx op, enum machine_mode mode)
+general_operand (rtx op, machine_mode mode)
 {
   enum rtx_code code = GET_CODE (op);
 
@@ -981,6 +1040,19 @@ general_operand (rtx op, enum machine_mode mode)
          && MEM_P (sub))
        return 0;
 
+#ifdef CANNOT_CHANGE_MODE_CLASS
+      if (REG_P (sub)
+         && REGNO (sub) < FIRST_PSEUDO_REGISTER
+         && REG_CANNOT_CHANGE_MODE_P (REGNO (sub), GET_MODE (sub), mode)
+         && GET_MODE_CLASS (GET_MODE (sub)) != MODE_COMPLEX_INT
+         && GET_MODE_CLASS (GET_MODE (sub)) != MODE_COMPLEX_FLOAT
+         /* LRA can generate some invalid SUBREGS just for matched
+            operand reload presentation.  LRA needs to treat them as
+            valid.  */
+         && ! LRA_SUBREG_P (op))
+       return 0;
+#endif
+
       /* FLOAT_MODE subregs can't be paradoxical.  Combine will occasionally
         create such rtl, and we must reject it.  */
       if (SCALAR_FLOAT_MODE_P (GET_MODE (op))
@@ -1008,8 +1080,12 @@ general_operand (rtx op, enum machine_mode mode)
       if (! volatile_ok && MEM_VOLATILE_P (op))
        return 0;
 
-      /* Use the mem's mode, since it will be reloaded thus.  */
-      if (memory_address_addr_space_p (GET_MODE (op), y, MEM_ADDR_SPACE (op)))
+      /* Use the mem's mode, since it will be reloaded thus.  LRA can
+        generate move insn with invalid addresses which is made valid
+        and efficiently calculated by LRA through further numerous
+        transformations.  */
+      if (lra_in_progress
+         || memory_address_addr_space_p (GET_MODE (op), y, MEM_ADDR_SPACE (op)))
        return 1;
     }
 
@@ -1023,7 +1099,7 @@ general_operand (rtx op, enum machine_mode mode)
    expressions in the machine description.  */
 
 int
-address_operand (rtx op, enum machine_mode mode)
+address_operand (rtx op, machine_mode mode)
 {
   return memory_address_p (mode, op);
 }
@@ -1035,11 +1111,8 @@ address_operand (rtx op, enum machine_mode mode)
    expressions in the machine description.  */
 
 int
-register_operand (rtx op, enum machine_mode mode)
+register_operand (rtx op, machine_mode mode)
 {
-  if (GET_MODE (op) != mode && mode != VOIDmode)
-    return 0;
-
   if (GET_CODE (op) == SUBREG)
     {
       rtx sub = SUBREG_REG (op);
@@ -1050,43 +1123,18 @@ register_operand (rtx op, enum machine_mode mode)
         (Ideally, (SUBREG (MEM)...) should not exist after reload,
         but currently it does result from (SUBREG (REG)...) where the
         reg went on the stack.)  */
-      if (! reload_completed && MEM_P (sub))
-       return general_operand (op, mode);
-
-#ifdef CANNOT_CHANGE_MODE_CLASS
-      if (REG_P (sub)
-         && REGNO (sub) < FIRST_PSEUDO_REGISTER
-         && REG_CANNOT_CHANGE_MODE_P (REGNO (sub), GET_MODE (sub), mode)
-         && GET_MODE_CLASS (GET_MODE (sub)) != MODE_COMPLEX_INT
-         && GET_MODE_CLASS (GET_MODE (sub)) != MODE_COMPLEX_FLOAT)
+      if (!REG_P (sub) && (reload_completed || !MEM_P (sub)))
        return 0;
-#endif
-
-      /* FLOAT_MODE subregs can't be paradoxical.  Combine will occasionally
-        create such rtl, and we must reject it.  */
-      if (SCALAR_FLOAT_MODE_P (GET_MODE (op))
-         /* LRA can use subreg to store a floating point value in an
-            integer mode.  Although the floating point and the
-            integer modes need the same number of hard registers, the
-            size of floating point mode can be less than the integer
-            mode.  */
-         && ! lra_in_progress 
-         && GET_MODE_SIZE (GET_MODE (op)) > GET_MODE_SIZE (GET_MODE (sub)))
-       return 0;
-
-      op = sub;
     }
-
-  return (REG_P (op)
-         && (REGNO (op) >= FIRST_PSEUDO_REGISTER
-             || in_hard_reg_set_p (operand_reg_set,
-                                   GET_MODE (op), REGNO (op))));
+  else if (!REG_P (op))
+    return 0;
+  return general_operand (op, mode);
 }
 
 /* Return 1 for a register in Pmode; ignore the tested mode.  */
 
 int
-pmode_register_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
+pmode_register_operand (rtx op, machine_mode mode ATTRIBUTE_UNUSED)
 {
   return register_operand (op, Pmode);
 }
@@ -1095,14 +1143,16 @@ pmode_register_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
    or a hard register.  */
 
 int
-scratch_operand (rtx op, enum machine_mode mode)
+scratch_operand (rtx op, machine_mode mode)
 {
   if (GET_MODE (op) != mode && mode != VOIDmode)
     return 0;
 
   return (GET_CODE (op) == SCRATCH
          || (REG_P (op)
-             && (lra_in_progress || REGNO (op) < FIRST_PSEUDO_REGISTER)));
+             && (lra_in_progress
+                 || (REGNO (op) < FIRST_PSEUDO_REGISTER
+                     && REGNO_REG_CLASS (REGNO (op)) != NO_REGS))));
 }
 
 /* Return 1 if OP is a valid immediate operand for mode MODE.
@@ -1111,7 +1161,7 @@ scratch_operand (rtx op, enum machine_mode mode)
    expressions in the machine description.  */
 
 int
-immediate_operand (rtx op, enum machine_mode mode)
+immediate_operand (rtx op, machine_mode mode)
 {
   /* Don't accept CONST_INT or anything similar
      if the caller wants something floating.  */
@@ -1134,10 +1184,10 @@ immediate_operand (rtx op, enum machine_mode mode)
                                            : mode, op));
 }
 
-/* Returns 1 if OP is an operand that is a CONST_INT.  */
+/* Returns 1 if OP is an operand that is a CONST_INT of mode MODE.  */
 
 int
-const_int_operand (rtx op, enum machine_mode mode)
+const_int_operand (rtx op, machine_mode mode)
 {
   if (!CONST_INT_P (op))
     return 0;
@@ -1149,11 +1199,54 @@ const_int_operand (rtx op, enum machine_mode mode)
   return 1;
 }
 
+#if TARGET_SUPPORTS_WIDE_INT
+/* Returns 1 if OP is an operand that is a CONST_INT or CONST_WIDE_INT
+   of mode MODE.  */
+int
+const_scalar_int_operand (rtx op, machine_mode mode)
+{
+  if (!CONST_SCALAR_INT_P (op))
+    return 0;
+
+  if (CONST_INT_P (op))
+    return const_int_operand (op, mode);
+
+  if (mode != VOIDmode)
+    {
+      int prec = GET_MODE_PRECISION (mode);
+      int bitsize = GET_MODE_BITSIZE (mode);
+
+      if (CONST_WIDE_INT_NUNITS (op) * HOST_BITS_PER_WIDE_INT > bitsize)
+       return 0;
+
+      if (prec == bitsize)
+       return 1;
+      else
+       {
+         /* Multiword partial int.  */
+         HOST_WIDE_INT x
+           = CONST_WIDE_INT_ELT (op, CONST_WIDE_INT_NUNITS (op) - 1);
+         return (sext_hwi (x, prec & (HOST_BITS_PER_WIDE_INT - 1)) == x);
+       }
+    }
+  return 1;
+}
+
 /* Returns 1 if OP is an operand that is a constant integer or constant
-   floating-point number.  */
+   floating-point number of MODE.  */
 
 int
-const_double_operand (rtx op, enum machine_mode mode)
+const_double_operand (rtx op, machine_mode mode)
+{
+  return (GET_CODE (op) == CONST_DOUBLE)
+         && (GET_MODE (op) == mode || mode == VOIDmode);
+}
+#else
+/* Returns 1 if OP is an operand that is a constant integer or constant
+   floating-point number of MODE.  */
+
+int
+const_double_operand (rtx op, machine_mode mode)
 {
   /* Don't accept CONST_INT or anything similar
      if the caller wants something floating.  */
@@ -1166,11 +1259,12 @@ const_double_operand (rtx op, enum machine_mode mode)
          && (mode == VOIDmode || GET_MODE (op) == mode
              || GET_MODE (op) == VOIDmode));
 }
-
-/* Return 1 if OP is a general operand that is not an immediate operand.  */
+#endif
+/* Return 1 if OP is a general operand that is not an immediate
+   operand of mode MODE.  */
 
 int
-nonimmediate_operand (rtx op, enum machine_mode mode)
+nonimmediate_operand (rtx op, machine_mode mode)
 {
   return (general_operand (op, mode) && ! CONSTANT_P (op));
 }
@@ -1178,31 +1272,11 @@ nonimmediate_operand (rtx op, enum machine_mode mode)
 /* Return 1 if OP is a register reference or immediate value of mode MODE.  */
 
 int
-nonmemory_operand (rtx op, enum machine_mode mode)
+nonmemory_operand (rtx op, machine_mode mode)
 {
   if (CONSTANT_P (op))
     return immediate_operand (op, mode);
-
-  if (GET_MODE (op) != mode && mode != VOIDmode)
-    return 0;
-
-  if (GET_CODE (op) == SUBREG)
-    {
-      /* Before reload, we can allow (SUBREG (MEM...)) as a register operand
-        because it is guaranteed to be reloaded into one.
-        Just make sure the MEM is valid in itself.
-        (Ideally, (SUBREG (MEM)...) should not exist after reload,
-        but currently it does result from (SUBREG (REG)...) where the
-        reg went on the stack.)  */
-      if (! reload_completed && MEM_P (SUBREG_REG (op)))
-       return general_operand (op, mode);
-      op = SUBREG_REG (op);
-    }
-
-  return (REG_P (op)
-         && (REGNO (op) >= FIRST_PSEUDO_REGISTER
-             || in_hard_reg_set_p (operand_reg_set,
-                                   GET_MODE (op), REGNO (op))));
+  return register_operand (op, mode);
 }
 
 /* Return 1 if OP is a valid operand that stands for pushing a
@@ -1212,7 +1286,7 @@ nonmemory_operand (rtx op, enum machine_mode mode)
    expressions in the machine description.  */
 
 int
-push_operand (rtx op, enum machine_mode mode)
+push_operand (rtx op, machine_mode mode)
 {
   unsigned int rounded_size = GET_MODE_SIZE (mode);
 
@@ -1239,12 +1313,8 @@ push_operand (rtx op, enum machine_mode mode)
          || GET_CODE (XEXP (op, 1)) != PLUS
          || XEXP (XEXP (op, 1), 0) != XEXP (op, 0)
          || !CONST_INT_P (XEXP (XEXP (op, 1), 1))
-#ifdef STACK_GROWS_DOWNWARD
-         || INTVAL (XEXP (XEXP (op, 1), 1)) != - (int) rounded_size
-#else
-         || INTVAL (XEXP (XEXP (op, 1), 1)) != (int) rounded_size
-#endif
-         )
+         || INTVAL (XEXP (XEXP (op, 1), 1))
+            != ((STACK_GROWS_DOWNWARD ? -1 : 1) * (int) rounded_size))
        return 0;
     }
 
@@ -1258,7 +1328,7 @@ push_operand (rtx op, enum machine_mode mode)
    expressions in the machine description.  */
 
 int
-pop_operand (rtx op, enum machine_mode mode)
+pop_operand (rtx op, machine_mode mode)
 {
   if (!MEM_P (op))
     return 0;
@@ -1278,7 +1348,7 @@ pop_operand (rtx op, enum machine_mode mode)
    for mode MODE in address space AS.  */
 
 int
-memory_address_addr_space_p (enum machine_mode mode ATTRIBUTE_UNUSED,
+memory_address_addr_space_p (machine_mode mode ATTRIBUTE_UNUSED,
                             rtx addr, addr_space_t as)
 {
 #ifdef GO_IF_LEGITIMATE_ADDRESS
@@ -1300,7 +1370,7 @@ memory_address_addr_space_p (enum machine_mode mode ATTRIBUTE_UNUSED,
    expressions in the machine description.  */
 
 int
-memory_operand (rtx op, enum machine_mode mode)
+memory_operand (rtx op, machine_mode mode)
 {
   rtx inner;
 
@@ -1323,7 +1393,7 @@ memory_operand (rtx op, enum machine_mode mode)
    that is, a memory reference whose address is a general_operand.  */
 
 int
-indirect_operand (rtx op, enum machine_mode mode)
+indirect_operand (rtx op, machine_mode mode)
 {
   /* Before reload, a SUBREG isn't in memory (see memory_operand, above).  */
   if (! reload_completed
@@ -1356,7 +1426,7 @@ indirect_operand (rtx op, enum machine_mode mode)
    ORDERED and UNORDERED).  */
 
 int
-ordered_comparison_operator (rtx op, enum machine_mode mode)
+ordered_comparison_operator (rtx op, machine_mode mode)
 {
   if (mode != VOIDmode && GET_MODE (op) != mode)
     return false;
@@ -1382,7 +1452,7 @@ ordered_comparison_operator (rtx op, enum machine_mode mode)
    MATCH_OPERATOR to recognize all the branch insns.  */
 
 int
-comparison_operator (rtx op, enum machine_mode mode)
+comparison_operator (rtx op, machine_mode mode)
 {
   return ((mode == VOIDmode || GET_MODE (op) == mode)
          && COMPARISON_P (op));
@@ -1503,7 +1573,7 @@ asm_noperands (const_rtx body)
 
 const char *
 decode_asm_operands (rtx body, rtx *operands, rtx **operand_locs,
-                    const char **constraints, enum machine_mode *modes,
+                    const char **constraints, machine_mode *modes,
                     location_t *loc)
 {
   int nbase = 0, n, i;
@@ -1599,6 +1669,50 @@ decode_asm_operands (rtx body, rtx *operands, rtx **operand_locs,
   return ASM_OPERANDS_TEMPLATE (asmop);
 }
 
+/* Parse inline assembly string STRING and determine which operands are
+   referenced by % markers.  For the first NOPERANDS operands, set USED[I]
+   to true if operand I is referenced.
+
+   This is intended to distinguish barrier-like asms such as:
+
+      asm ("" : "=m" (...));
+
+   from real references such as:
+
+      asm ("sw\t$0, %0" : "=m" (...));  */
+
+void
+get_referenced_operands (const char *string, bool *used,
+                        unsigned int noperands)
+{
+  memset (used, 0, sizeof (bool) * noperands);
+  const char *p = string;
+  while (*p)
+    switch (*p)
+      {
+      case '%':
+       p += 1;
+       /* A letter followed by a digit indicates an operand number.  */
+       if (ISALPHA (p[0]) && ISDIGIT (p[1]))
+         p += 1;
+       if (ISDIGIT (*p))
+         {
+           char *endptr;
+           unsigned long opnum = strtoul (p, &endptr, 10);
+           if (endptr != p && opnum < noperands)
+             used[opnum] = true;
+           p = endptr;
+         }
+       else
+         p += 1;
+       break;
+
+      default:
+       p++;
+       break;
+      }
+}
+
 /* Check if an asm_operand matches its constraints.
    Return > 0 if ok, = 0 if bad, < 0 if inconclusive.  */
 
@@ -1620,6 +1734,7 @@ asm_operand_ok (rtx op, const char *constraint, const char **constraints)
 
   while (*constraint)
     {
+      enum constraint_num cn;
       char c = *constraint;
       int len;
       switch (c)
@@ -1627,20 +1742,11 @@ asm_operand_ok (rtx op, const char *constraint, const char **constraints)
        case ',':
          constraint++;
          continue;
-       case '=':
-       case '+':
-       case '*':
-       case '%':
-       case '!':
-       case '#':
-       case '&':
-       case '?':
-         break;
 
        case '0': case '1': case '2': case '3': case '4':
        case '5': case '6': case '7': case '8': case '9':
          /* If caller provided constraints pointer, look up
-            the maching constraint.  Otherwise, our caller should have
+            the matching constraint.  Otherwise, our caller should have
             given us the proper matching constraint, but we can't
             actually fail the check if they didn't.  Indicate that
             results are inconclusive.  */
@@ -1664,156 +1770,70 @@ asm_operand_ok (rtx op, const char *constraint, const char **constraints)
            }
          continue;
 
-       case 'p':
-         if (address_operand (op, VOIDmode))
-           result = 1;
-         break;
-
-       case TARGET_MEM_CONSTRAINT:
-       case 'V': /* non-offsettable */
-         if (memory_operand (op, VOIDmode))
-           result = 1;
-         break;
+         /* The rest of the compiler assumes that reloading the address
+            of a MEM into a register will make it fit an 'o' constraint.
+            That is, if it sees a MEM operand for an 'o' constraint,
+            it assumes that (mem (base-reg)) will fit.
 
+            That assumption fails on targets that don't have offsettable
+            addresses at all.  We therefore need to treat 'o' asm
+            constraints as a special case and only accept operands that
+            are already offsettable, thus proving that at least one
+            offsettable address exists.  */
        case 'o': /* offsettable */
          if (offsettable_nonstrict_memref_p (op))
            result = 1;
          break;
 
-       case '<':
-         /* ??? Before auto-inc-dec, auto inc/dec insns are not supposed to exist,
-            excepting those that expand_call created.  Further, on some
-            machines which do not have generalized auto inc/dec, an inc/dec
-            is not a memory_operand.
-
-            Match any memory and hope things are resolved after reload.  */
-
-         if (MEM_P (op)
-             && (1
-                 || GET_CODE (XEXP (op, 0)) == PRE_DEC
-                 || GET_CODE (XEXP (op, 0)) == POST_DEC))
+       case 'g':
+         if (general_operand (op, VOIDmode))
            result = 1;
-#ifdef AUTO_INC_DEC
-         incdec_ok = true;
-#endif
          break;
 
-       case '>':
-         if (MEM_P (op)
-             && (1
-                 || GET_CODE (XEXP (op, 0)) == PRE_INC
-                 || GET_CODE (XEXP (op, 0)) == POST_INC))
-           result = 1;
 #ifdef AUTO_INC_DEC
+       case '<':
+       case '>':
+         /* ??? Before auto-inc-dec, auto inc/dec insns are not supposed
+            to exist, excepting those that expand_call created.  Further,
+            on some machines which do not have generalized auto inc/dec,
+            an inc/dec is not a memory_operand.
+
+            Match any memory and hope things are resolved after reload.  */
          incdec_ok = true;
 #endif
-         break;
-
-       case 'E':
-       case 'F':
-         if (CONST_DOUBLE_AS_FLOAT_P (op) 
-             || (GET_CODE (op) == CONST_VECTOR
-                 && GET_MODE_CLASS (GET_MODE (op)) == MODE_VECTOR_FLOAT))
-           result = 1;
-         break;
-
-       case 'G':
-         if (CONST_DOUBLE_AS_FLOAT_P (op)
-             && CONST_DOUBLE_OK_FOR_CONSTRAINT_P (op, 'G', constraint))
-           result = 1;
-         break;
-       case 'H':
-         if (CONST_DOUBLE_AS_FLOAT_P (op)
-             && CONST_DOUBLE_OK_FOR_CONSTRAINT_P (op, 'H', constraint))
-           result = 1;
-         break;
-
-       case 's':
-         if (CONST_SCALAR_INT_P (op))
-           break;
-         /* Fall through.  */
-
-       case 'i':
-         if (CONSTANT_P (op) && (! flag_pic || LEGITIMATE_PIC_OPERAND_P (op)))
-           result = 1;
-         break;
-
-       case 'n':
-         if (CONST_SCALAR_INT_P (op))
-           result = 1;
-         break;
+       default:
+         cn = lookup_constraint (constraint);
+         switch (get_constraint_type (cn))
+           {
+           case CT_REGISTER:
+             if (!result
+                 && reg_class_for_constraint (cn) != NO_REGS
+                 && GET_MODE (op) != BLKmode
+                 && register_operand (op, VOIDmode))
+               result = 1;
+             break;
 
-       case 'I':
-         if (CONST_INT_P (op)
-             && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), 'I', constraint))
-           result = 1;
-         break;
-       case 'J':
-         if (CONST_INT_P (op)
-             && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), 'J', constraint))
-           result = 1;
-         break;
-       case 'K':
-         if (CONST_INT_P (op)
-             && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), 'K', constraint))
-           result = 1;
-         break;
-       case 'L':
-         if (CONST_INT_P (op)
-             && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), 'L', constraint))
-           result = 1;
-         break;
-       case 'M':
-         if (CONST_INT_P (op)
-             && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), 'M', constraint))
-           result = 1;
-         break;
-       case 'N':
-         if (CONST_INT_P (op)
-             && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), 'N', constraint))
-           result = 1;
-         break;
-       case 'O':
-         if (CONST_INT_P (op)
-             && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), 'O', constraint))
-           result = 1;
-         break;
-       case 'P':
-         if (CONST_INT_P (op)
-             && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), 'P', constraint))
-           result = 1;
-         break;
+           case CT_CONST_INT:
+             if (!result
+                 && CONST_INT_P (op)
+                 && insn_const_int_ok_for_constraint (INTVAL (op), cn))
+               result = 1;
+             break;
 
-       case 'X':
-         result = 1;
-         break;
+           case CT_MEMORY:
+             /* Every memory operand can be reloaded to fit.  */
+             result = result || memory_operand (op, VOIDmode);
+             break;
 
-       case 'g':
-         if (general_operand (op, VOIDmode))
-           result = 1;
-         break;
+           case CT_ADDRESS:
+             /* Every address operand can be reloaded to fit.  */
+             result = result || address_operand (op, VOIDmode);
+             break;
 
-       default:
-         /* For all other letters, we first check for a register class,
-            otherwise it is an EXTRA_CONSTRAINT.  */
-         if (REG_CLASS_FROM_CONSTRAINT (c, constraint) != NO_REGS)
-           {
-           case 'r':
-             if (GET_MODE (op) == BLKmode)
-               break;
-             if (register_operand (op, VOIDmode))
-               result = 1;
+           case CT_FIXED_FORM:
+             result = result || constraint_satisfied_p (op, cn);
+             break;
            }
-#ifdef EXTRA_CONSTRAINT_STR
-         else if (EXTRA_MEMORY_CONSTRAINT (c, constraint))
-           /* Every memory operand can be reloaded to fit.  */
-           result = result || memory_operand (op, VOIDmode);
-         else if (EXTRA_ADDRESS_CONSTRAINT (c, constraint))
-           /* Every address operand can be reloaded to fit.  */
-           result = result || address_operand (op, VOIDmode);
-         else if (EXTRA_CONSTRAINT_STR (op, c, constraint))
-           result = 1;
-#endif
          break;
        }
       len = CONSTRAINT_LEN (c, constraint);
@@ -1931,14 +1951,14 @@ offsettable_nonstrict_memref_p (rtx op)
    for the sake of use in reload.c.  */
 
 int
-offsettable_address_addr_space_p (int strictp, enum machine_mode mode, rtx y,
+offsettable_address_addr_space_p (int strictp, machine_mode mode, rtx y,
                                  addr_space_t as)
 {
   enum rtx_code ycode = GET_CODE (y);
   rtx z;
   rtx y1 = y;
   rtx *y2;
-  int (*addressp) (enum machine_mode, rtx, addr_space_t) =
+  int (*addressp) (machine_mode, rtx, addr_space_t) =
     (strictp ? strict_memory_address_addr_space_p
             : memory_address_addr_space_p);
   unsigned int mode_sz = GET_MODE_SIZE (mode);
@@ -1952,6 +1972,13 @@ offsettable_address_addr_space_p (int strictp, enum machine_mode mode, rtx y,
   if (mode_dependent_address_p (y, as))
     return 0;
 
+  machine_mode address_mode = GET_MODE (y);
+  if (address_mode == VOIDmode)
+    address_mode = targetm.addr_space.address_mode (as);
+#ifdef POINTERS_EXTEND_UNSIGNED
+  machine_mode pointer_mode = targetm.addr_space.pointer_mode (as);
+#endif
+
   /* ??? How much offset does an offsettable BLKmode reference need?
      Clearly that depends on the situation in which it's being used.
      However, the current situation in which we test 0xffffffff is
@@ -1967,7 +1994,7 @@ offsettable_address_addr_space_p (int strictp, enum machine_mode mode, rtx y,
       int good;
 
       y1 = *y2;
-      *y2 = plus_constant (GET_MODE (y), *y2, mode_sz - 1);
+      *y2 = plus_constant (address_mode, *y2, mode_sz - 1);
       /* Use QImode because an odd displacement may be automatically invalid
         for any wider mode.  But it should be valid for a single byte.  */
       good = (*addressp) (QImode, y, as);
@@ -1988,11 +2015,20 @@ offsettable_address_addr_space_p (int strictp, enum machine_mode mode, rtx y,
   if (GET_CODE (y) == LO_SUM
       && mode != BLKmode
       && mode_sz <= GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT)
-    z = gen_rtx_LO_SUM (GET_MODE (y), XEXP (y, 0),
-                       plus_constant (GET_MODE (y), XEXP (y, 1),
+    z = gen_rtx_LO_SUM (address_mode, XEXP (y, 0),
+                       plus_constant (address_mode, XEXP (y, 1),
                                       mode_sz - 1));
+#ifdef POINTERS_EXTEND_UNSIGNED
+  /* Likewise for a ZERO_EXTEND from pointer_mode.  */
+  else if (POINTERS_EXTEND_UNSIGNED > 0
+          && GET_CODE (y) == ZERO_EXTEND
+          && GET_MODE (XEXP (y, 0)) == pointer_mode)
+    z = gen_rtx_ZERO_EXTEND (address_mode,
+                            plus_constant (pointer_mode, XEXP (y, 0),
+                                           mode_sz - 1));
+#endif
   else
-    z = plus_constant (GET_MODE (y), y, mode_sz - 1);
+    z = plus_constant (address_mode, y, mode_sz - 1);
 
   /* Use QImode because an odd displacement may be automatically invalid
      for any wider mode.  But it should be valid for a single byte.  */
@@ -2022,12 +2058,151 @@ mode_dependent_address_p (rtx addr, addr_space_t addrspace)
   return targetm.mode_dependent_address_p (addr, addrspace);
 }
 \f
+/* Return true if boolean attribute ATTR is supported.  */
+
+static bool
+have_bool_attr (bool_attr attr)
+{
+  switch (attr)
+    {
+    case BA_ENABLED:
+      return HAVE_ATTR_enabled;
+    case BA_PREFERRED_FOR_SIZE:
+      return HAVE_ATTR_enabled || HAVE_ATTR_preferred_for_size;
+    case BA_PREFERRED_FOR_SPEED:
+      return HAVE_ATTR_enabled || HAVE_ATTR_preferred_for_speed;
+    }
+  gcc_unreachable ();
+}
+
+/* Return the value of ATTR for instruction INSN.  */
+
+static bool
+get_bool_attr (rtx_insn *insn, bool_attr attr)
+{
+  switch (attr)
+    {
+    case BA_ENABLED:
+      return get_attr_enabled (insn);
+    case BA_PREFERRED_FOR_SIZE:
+      return get_attr_enabled (insn) && get_attr_preferred_for_size (insn);
+    case BA_PREFERRED_FOR_SPEED:
+      return get_attr_enabled (insn) && get_attr_preferred_for_speed (insn);
+    }
+  gcc_unreachable ();
+}
+
+/* Like get_bool_attr_mask, but don't use the cache.  */
+
+static alternative_mask
+get_bool_attr_mask_uncached (rtx_insn *insn, bool_attr attr)
+{
+  /* Temporarily install enough information for get_attr_<foo> to assume
+     that the insn operands are already cached.  As above, the attribute
+     mustn't depend on the values of operands, so we don't provide their
+     real values here.  */
+  rtx_insn *old_insn = recog_data.insn;
+  int old_alternative = which_alternative;
+
+  recog_data.insn = insn;
+  alternative_mask mask = ALL_ALTERNATIVES;
+  int n_alternatives = insn_data[INSN_CODE (insn)].n_alternatives;
+  for (int i = 0; i < n_alternatives; i++)
+    {
+      which_alternative = i;
+      if (!get_bool_attr (insn, attr))
+       mask &= ~ALTERNATIVE_BIT (i);
+    }
+
+  recog_data.insn = old_insn;
+  which_alternative = old_alternative;
+  return mask;
+}
+
+/* Return the mask of operand alternatives that are allowed for INSN
+   by boolean attribute ATTR.  This mask depends only on INSN and on
+   the current target; it does not depend on things like the values of
+   operands.  */
+
+static alternative_mask
+get_bool_attr_mask (rtx_insn *insn, bool_attr attr)
+{
+  /* Quick exit for asms and for targets that don't use these attributes.  */
+  int code = INSN_CODE (insn);
+  if (code < 0 || !have_bool_attr (attr))
+    return ALL_ALTERNATIVES;
+
+  /* Calling get_attr_<foo> can be expensive, so cache the mask
+     for speed.  */
+  if (!this_target_recog->x_bool_attr_masks[code][attr])
+    this_target_recog->x_bool_attr_masks[code][attr]
+      = get_bool_attr_mask_uncached (insn, attr);
+  return this_target_recog->x_bool_attr_masks[code][attr];
+}
+
+/* Return the set of alternatives of INSN that are allowed by the current
+   target.  */
+
+alternative_mask
+get_enabled_alternatives (rtx_insn *insn)
+{
+  return get_bool_attr_mask (insn, BA_ENABLED);
+}
+
+/* Return the set of alternatives of INSN that are allowed by the current
+   target and are preferred for the current size/speed optimization
+   choice.  */
+
+alternative_mask
+get_preferred_alternatives (rtx_insn *insn)
+{
+  if (optimize_bb_for_speed_p (BLOCK_FOR_INSN (insn)))
+    return get_bool_attr_mask (insn, BA_PREFERRED_FOR_SPEED);
+  else
+    return get_bool_attr_mask (insn, BA_PREFERRED_FOR_SIZE);
+}
+
+/* Return the set of alternatives of INSN that are allowed by the current
+   target and are preferred for the size/speed optimization choice
+   associated with BB.  Passing a separate BB is useful if INSN has not
+   been emitted yet or if we are considering moving it to a different
+   block.  */
+
+alternative_mask
+get_preferred_alternatives (rtx_insn *insn, basic_block bb)
+{
+  if (optimize_bb_for_speed_p (bb))
+    return get_bool_attr_mask (insn, BA_PREFERRED_FOR_SPEED);
+  else
+    return get_bool_attr_mask (insn, BA_PREFERRED_FOR_SIZE);
+}
+
+/* Assert that the cached boolean attributes for INSN are still accurate.
+   The backend is required to define these attributes in a way that only
+   depends on the current target (rather than operands, compiler phase,
+   etc.).  */
+
+bool
+check_bool_attrs (rtx_insn *insn)
+{
+  int code = INSN_CODE (insn);
+  if (code >= 0)
+    for (int i = 0; i <= BA_LAST; ++i)
+      {
+       enum bool_attr attr = (enum bool_attr) i;
+       if (this_target_recog->x_bool_attr_masks[code][attr])
+         gcc_assert (this_target_recog->x_bool_attr_masks[code][attr]
+                     == get_bool_attr_mask_uncached (insn, attr));
+      }
+  return true;
+}
+
 /* Like extract_insn, but save insn extracted and don't extract again, when
    called again for the same insn expecting that recog_data still contain the
    valid information.  This is used primary by gen_attr infrastructure that
    often does extract insn again and again.  */
 void
-extract_insn_cached (rtx insn)
+extract_insn_cached (rtx_insn *insn)
 {
   if (recog_data.insn == insn && INSN_CODE (insn) >= 0)
     return;
@@ -2035,23 +2210,35 @@ extract_insn_cached (rtx insn)
   recog_data.insn = insn;
 }
 
+/* Do uncached extract_insn, constrain_operands and complain about failures.
+   This should be used when extracting a pre-existing constrained instruction
+   if the caller wants to know which alternative was chosen.  */
+void
+extract_constrain_insn (rtx_insn *insn)
+{
+  extract_insn (insn);
+  if (!constrain_operands (reload_completed, get_enabled_alternatives (insn)))
+    fatal_insn_not_found (insn);
+}
+
 /* Do cached extract_insn, constrain_operands and complain about failures.
    Used by insn_attrtab.  */
 void
-extract_constrain_insn_cached (rtx insn)
+extract_constrain_insn_cached (rtx_insn *insn)
 {
   extract_insn_cached (insn);
   if (which_alternative == -1
-      && !constrain_operands (reload_completed))
+      && !constrain_operands (reload_completed,
+                             get_enabled_alternatives (insn)))
     fatal_insn_not_found (insn);
 }
 
-/* Do cached constrain_operands and complain about failures.  */
+/* Do cached constrain_operands on INSN and complain about failures.  */
 int
-constrain_operands_cached (int strict)
+constrain_operands_cached (rtx_insn *insn, int strict)
 {
   if (which_alternative == -1)
-    return constrain_operands (strict);
+    return constrain_operands (strict, get_enabled_alternatives (insn));
   else
     return 1;
 }
@@ -2059,7 +2246,7 @@ constrain_operands_cached (int strict)
 /* Analyze INSN and fill in recog_data.  */
 
 void
-extract_insn (rtx insn)
+extract_insn (rtx_insn *insn)
 {
   int i;
   int icode;
@@ -2154,60 +2341,38 @@ extract_insn (rtx insn)
 
   gcc_assert (recog_data.n_alternatives <= MAX_RECOG_ALTERNATIVES);
 
-  if (INSN_CODE (insn) < 0)
-    for (i = 0; i < recog_data.n_alternatives; i++)
-      recog_data.alternative_enabled_p[i] = true;
-  else
-    {
-      recog_data.insn = insn;
-      for (i = 0; i < recog_data.n_alternatives; i++)
-       {
-         which_alternative = i;
-         recog_data.alternative_enabled_p[i]
-           = HAVE_ATTR_enabled ? get_attr_enabled (insn) : 1;
-       }
-    }
-
   recog_data.insn = NULL;
   which_alternative = -1;
 }
 
-/* After calling extract_insn, you can use this function to extract some
-   information from the constraint strings into a more usable form.
-   The collected data is stored in recog_op_alt.  */
+/* Fill in OP_ALT_BASE for an instruction that has N_OPERANDS operands,
+   N_ALTERNATIVES alternatives and constraint strings CONSTRAINTS.
+   OP_ALT_BASE has N_ALTERNATIVES * N_OPERANDS entries and CONSTRAINTS
+   has N_OPERANDS entries.  */
+
 void
-preprocess_constraints (void)
+preprocess_constraints (int n_operands, int n_alternatives,
+                       const char **constraints,
+                       operand_alternative *op_alt_base)
 {
-  int i;
-
-  for (i = 0; i < recog_data.n_operands; i++)
-    memset (recog_op_alt[i], 0, (recog_data.n_alternatives
-                                * sizeof (struct operand_alternative)));
-
-  for (i = 0; i < recog_data.n_operands; i++)
+  for (int i = 0; i < n_operands; i++)
     {
       int j;
       struct operand_alternative *op_alt;
-      const char *p = recog_data.constraints[i];
+      const char *p = constraints[i];
 
-      op_alt = recog_op_alt[i];
+      op_alt = op_alt_base;
 
-      for (j = 0; j < recog_data.n_alternatives; j++)
+      for (j = 0; j < n_alternatives; j++, op_alt += n_operands)
        {
-         op_alt[j].cl = NO_REGS;
-         op_alt[j].constraint = p;
-         op_alt[j].matches = -1;
-         op_alt[j].matched = -1;
-
-         if (!recog_data.alternative_enabled_p[j])
-           {
-             p = skip_alternative (p);
-             continue;
-           }
+         op_alt[i].cl = NO_REGS;
+         op_alt[i].constraint = p;
+         op_alt[i].matches = -1;
+         op_alt[i].matched = -1;
 
          if (*p == '\0' || *p == ',')
            {
-             op_alt[j].anything_ok = 1;
+             op_alt[i].anything_ok = 1;
              continue;
            }
 
@@ -2226,87 +2391,65 @@ preprocess_constraints (void)
 
              switch (c)
                {
-               case '=': case '+': case '*': case '%':
-               case 'E': case 'F': case 'G': case 'H':
-               case 's': case 'i': case 'n':
-               case 'I': case 'J': case 'K': case 'L':
-               case 'M': case 'N': case 'O': case 'P':
-                 /* These don't say anything we care about.  */
-                 break;
-
                case '?':
-                 op_alt[j].reject += 6;
+                 op_alt[i].reject += 6;
                  break;
                case '!':
-                 op_alt[j].reject += 600;
+                 op_alt[i].reject += 600;
                  break;
                case '&':
-                 op_alt[j].earlyclobber = 1;
+                 op_alt[i].earlyclobber = 1;
                  break;
 
                case '0': case '1': case '2': case '3': case '4':
                case '5': case '6': case '7': case '8': case '9':
                  {
                    char *end;
-                   op_alt[j].matches = strtoul (p, &end, 10);
-                   recog_op_alt[op_alt[j].matches][j].matched = i;
+                   op_alt[i].matches = strtoul (p, &end, 10);
+                   op_alt[op_alt[i].matches].matched = i;
                    p = end;
                  }
                  continue;
 
-               case TARGET_MEM_CONSTRAINT:
-                 op_alt[j].memory_ok = 1;
-                 break;
-               case '<':
-                 op_alt[j].decmem_ok = 1;
-                 break;
-               case '>':
-                 op_alt[j].incmem_ok = 1;
-                 break;
-               case 'V':
-                 op_alt[j].nonoffmem_ok = 1;
-                 break;
-               case 'o':
-                 op_alt[j].offmem_ok = 1;
-                 break;
                case 'X':
-                 op_alt[j].anything_ok = 1;
-                 break;
-
-               case 'p':
-                 op_alt[j].is_address = 1;
-                 op_alt[j].cl = reg_class_subunion[(int) op_alt[j].cl]
-                     [(int) base_reg_class (VOIDmode, ADDR_SPACE_GENERIC,
-                                            ADDRESS, SCRATCH)];
+                 op_alt[i].anything_ok = 1;
                  break;
 
                case 'g':
-               case 'r':
-                 op_alt[j].cl =
-                  reg_class_subunion[(int) op_alt[j].cl][(int) GENERAL_REGS];
+                 op_alt[i].cl =
+                  reg_class_subunion[(int) op_alt[i].cl][(int) GENERAL_REGS];
                  break;
 
                default:
-                 if (EXTRA_MEMORY_CONSTRAINT (c, p))
+                 enum constraint_num cn = lookup_constraint (p);
+                 enum reg_class cl;
+                 switch (get_constraint_type (cn))
                    {
-                     op_alt[j].memory_ok = 1;
+                   case CT_REGISTER:
+                     cl = reg_class_for_constraint (cn);
+                     if (cl != NO_REGS)
+                       op_alt[i].cl = reg_class_subunion[op_alt[i].cl][cl];
                      break;
-                   }
-                 if (EXTRA_ADDRESS_CONSTRAINT (c, p))
-                   {
-                     op_alt[j].is_address = 1;
-                     op_alt[j].cl
+
+                   case CT_CONST_INT:
+                     break;
+
+                   case CT_MEMORY:
+                     op_alt[i].memory_ok = 1;
+                     break;
+
+                   case CT_ADDRESS:
+                     op_alt[i].is_address = 1;
+                     op_alt[i].cl
                        = (reg_class_subunion
-                          [(int) op_alt[j].cl]
+                          [(int) op_alt[i].cl]
                           [(int) base_reg_class (VOIDmode, ADDR_SPACE_GENERIC,
                                                  ADDRESS, SCRATCH)]);
                      break;
-                   }
 
-                 op_alt[j].cl
-                   = (reg_class_subunion
-                      [(int) op_alt[j].cl]
-                      [(int) REG_CLASS_FROM_CONSTRAINT ((unsigned char) c, p)]);
+                   case CT_FIXED_FORM:
+                     break;
+                   }
                  break;
                }
              p += CONSTRAINT_LEN (c, p);
@@ -2315,8 +2458,62 @@ preprocess_constraints (void)
     }
 }
 
+/* Return an array of operand_alternative instructions for
+   instruction ICODE.  */
+
+const operand_alternative *
+preprocess_insn_constraints (int icode)
+{
+  gcc_checking_assert (IN_RANGE (icode, 0, LAST_INSN_CODE));
+  if (this_target_recog->x_op_alt[icode])
+    return this_target_recog->x_op_alt[icode];
+
+  int n_operands = insn_data[icode].n_operands;
+  if (n_operands == 0)
+    return 0;
+  /* Always provide at least one alternative so that which_op_alt ()
+     works correctly.  If the instruction has 0 alternatives (i.e. all
+     constraint strings are empty) then each operand in this alternative
+     will have anything_ok set.  */
+  int n_alternatives = MAX (insn_data[icode].n_alternatives, 1);
+  int n_entries = n_operands * n_alternatives;
+
+  operand_alternative *op_alt = XCNEWVEC (operand_alternative, n_entries);
+  const char **constraints = XALLOCAVEC (const char *, n_operands);
+
+  for (int i = 0; i < n_operands; ++i)
+    constraints[i] = insn_data[icode].operand[i].constraint;
+  preprocess_constraints (n_operands, n_alternatives, constraints, op_alt);
+
+  this_target_recog->x_op_alt[icode] = op_alt;
+  return op_alt;
+}
+
+/* After calling extract_insn, you can use this function to extract some
+   information from the constraint strings into a more usable form.
+   The collected data is stored in recog_op_alt.  */
+
+void
+preprocess_constraints (rtx_insn *insn)
+{
+  int icode = INSN_CODE (insn);
+  if (icode >= 0)
+    recog_op_alt = preprocess_insn_constraints (icode);
+  else
+    {
+      int n_operands = recog_data.n_operands;
+      int n_alternatives = recog_data.n_alternatives;
+      int n_entries = n_operands * n_alternatives;
+      memset (asm_op_alt, 0, n_entries * sizeof (operand_alternative));
+      preprocess_constraints (n_operands, n_alternatives,
+                             recog_data.constraints, asm_op_alt);
+      recog_op_alt = asm_op_alt;
+    }
+}
+
 /* Check the operands of an insn against the insn's operand constraints
-   and return 1 if they are valid.
+   and return 1 if they match any of the alternatives in ALTERNATIVES.
+
    The information about the insn's operands, constraints, operand modes
    etc. is obtained from the global variables set up by extract_insn.
 
@@ -2348,7 +2545,7 @@ struct funny_match
 };
 
 int
-constrain_operands (int strict)
+constrain_operands (int strict, alternative_mask alternatives)
 {
   const char *constraints[MAX_RECOG_OPERANDS];
   int matching_operands[MAX_RECOG_OPERANDS];
@@ -2375,7 +2572,7 @@ constrain_operands (int strict)
       int lose = 0;
       funny_match_index = 0;
 
-      if (!recog_data.alternative_enabled_p[which_alternative])
+      if (!TEST_BIT (alternatives, which_alternative))
        {
          int i;
 
@@ -2389,7 +2586,7 @@ constrain_operands (int strict)
       for (opno = 0; opno < recog_data.n_operands; opno++)
        {
          rtx op = recog_data.operand[opno];
-         enum machine_mode mode = GET_MODE (op);
+         machine_mode mode = GET_MODE (op);
          const char *p = constraints[opno];
          int offset = 0;
          int win = 0;
@@ -2429,10 +2626,6 @@ constrain_operands (int strict)
                c = '\0';
                break;
 
-             case '?':  case '!': case '*':  case '%':
-             case '=':  case '+':
-               break;
-
              case '#':
                /* Ignore rest of this alternative as far as
                   constraint checking is concerned.  */
@@ -2532,123 +2725,10 @@ constrain_operands (int strict)
                  win = 1;
                break;
 
-             case 'X':
-               /* This is used for a MATCH_SCRATCH in the cases when
-                  we don't actually need anything.  So anything goes
-                  any time.  */
-               win = 1;
-               break;
-
-             case TARGET_MEM_CONSTRAINT:
-               /* Memory operands must be valid, to the extent
-                  required by STRICT.  */
-               if (MEM_P (op))
-                 {
-                   if (strict > 0
-                       && !strict_memory_address_addr_space_p
-                            (GET_MODE (op), XEXP (op, 0),
-                             MEM_ADDR_SPACE (op)))
-                     break;
-                   if (strict == 0
-                       && !memory_address_addr_space_p
-                            (GET_MODE (op), XEXP (op, 0),
-                             MEM_ADDR_SPACE (op)))
-                     break;
-                   win = 1;
-                 }
-               /* Before reload, accept what reload can turn into mem.  */
-               else if (strict < 0 && CONSTANT_P (op))
-                 win = 1;
-               /* During reload, accept a pseudo  */
-               else if (reload_in_progress && REG_P (op)
-                        && REGNO (op) >= FIRST_PSEUDO_REGISTER)
-                 win = 1;
-               break;
-
-             case '<':
-               if (MEM_P (op)
-                   && (GET_CODE (XEXP (op, 0)) == PRE_DEC
-                       || GET_CODE (XEXP (op, 0)) == POST_DEC))
-                 win = 1;
-               break;
-
-             case '>':
-               if (MEM_P (op)
-                   && (GET_CODE (XEXP (op, 0)) == PRE_INC
-                       || GET_CODE (XEXP (op, 0)) == POST_INC))
-                 win = 1;
-               break;
-
-             case 'E':
-             case 'F':
-               if (CONST_DOUBLE_AS_FLOAT_P (op)
-                   || (GET_CODE (op) == CONST_VECTOR
-                       && GET_MODE_CLASS (GET_MODE (op)) == MODE_VECTOR_FLOAT))
-                 win = 1;
-               break;
-
-             case 'G':
-             case 'H':
-               if (CONST_DOUBLE_AS_FLOAT_P (op)
-                   && CONST_DOUBLE_OK_FOR_CONSTRAINT_P (op, c, p))
-                 win = 1;
-               break;
-
-             case 's':
-               if (CONST_SCALAR_INT_P (op))
-                 break;
-             case 'i':
-               if (CONSTANT_P (op))
-                 win = 1;
-               break;
-
-             case 'n':
-               if (CONST_SCALAR_INT_P (op))
-                 win = 1;
-               break;
-
-             case 'I':
-             case 'J':
-             case 'K':
-             case 'L':
-             case 'M':
-             case 'N':
-             case 'O':
-             case 'P':
-               if (CONST_INT_P (op)
-                   && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), c, p))
-                 win = 1;
-               break;
-
-             case 'V':
-               if (MEM_P (op)
-                   && ((strict > 0 && ! offsettable_memref_p (op))
-                       || (strict < 0
-                           && !(CONSTANT_P (op) || MEM_P (op)))
-                       || (reload_in_progress
-                           && !(REG_P (op)
-                                && REGNO (op) >= FIRST_PSEUDO_REGISTER))))
-                 win = 1;
-               break;
-
-             case 'o':
-               if ((strict > 0 && offsettable_memref_p (op))
-                   || (strict == 0 && offsettable_nonstrict_memref_p (op))
-                   /* Before reload, accept what reload can handle.  */
-                   || (strict < 0
-                       && (CONSTANT_P (op) || MEM_P (op)))
-                   /* During reload, accept a pseudo  */
-                   || (reload_in_progress && REG_P (op)
-                       && REGNO (op) >= FIRST_PSEUDO_REGISTER))
-                 win = 1;
-               break;
-
              default:
                {
-                 enum reg_class cl;
-
-                 cl = (c == 'r'
-                          ? GENERAL_REGS : REG_CLASS_FROM_CONSTRAINT (c, p));
+                 enum constraint_num cn = lookup_constraint (p);
+                 enum reg_class cl = reg_class_for_constraint (cn);
                  if (cl != NO_REGS)
                    {
                      if (strict < 0
@@ -2660,21 +2740,25 @@ constrain_operands (int strict)
                              && reg_fits_class_p (op, cl, offset, mode)))
                        win = 1;
                    }
-#ifdef EXTRA_CONSTRAINT_STR
-                 else if (EXTRA_CONSTRAINT_STR (op, c, p))
+
+                 else if (constraint_satisfied_p (op, cn))
                    win = 1;
 
-                 else if (EXTRA_MEMORY_CONSTRAINT (c, p)
+                 else if (insn_extra_memory_constraint (cn)
                           /* Every memory operand can be reloaded to fit.  */
                           && ((strict < 0 && MEM_P (op))
                               /* Before reload, accept what reload can turn
-                                 into mem.  */
+                                 into mem.  */
                               || (strict < 0 && CONSTANT_P (op))
+                              /* Before reload, accept a pseudo,
+                                 since LRA can turn it into a mem.  */
+                              || (strict < 0 && targetm.lra_p () && REG_P (op)
+                                  && REGNO (op) >= FIRST_PSEUDO_REGISTER)
                               /* During reload, accept a pseudo  */
                               || (reload_in_progress && REG_P (op)
                                   && REGNO (op) >= FIRST_PSEUDO_REGISTER)))
                    win = 1;
-                 else if (EXTRA_ADDRESS_CONSTRAINT (c, p)
+                 else if (insn_extra_address_constraint (cn)
                           /* Every address operand can be reloaded to fit.  */
                           && strict < 0)
                    win = 1;
@@ -2685,10 +2769,9 @@ constrain_operands (int strict)
                           && REGNO (op) >= FIRST_PSEUDO_REGISTER
                           && reg_renumber[REGNO (op)] < 0
                           && reg_equiv_mem (REGNO (op)) != 0
-                          && EXTRA_CONSTRAINT_STR
-                             (reg_equiv_mem (REGNO (op)), c, p))
+                          && constraint_satisfied_p
+                             (reg_equiv_mem (REGNO (op)), cn))
                    win = 1;
-#endif
                  break;
                }
              }
@@ -2775,7 +2858,7 @@ constrain_operands (int strict)
   /* If we are about to reject this, but we are not to test strictly,
      try a very loose test.  Only return failure if it fails also.  */
   if (strict == 0)
-    return constrain_operands (-1);
+    return constrain_operands (-1, alternatives);
   else
     return 0;
 }
@@ -2787,7 +2870,7 @@ constrain_operands (int strict)
 
 bool
 reg_fits_class_p (const_rtx operand, reg_class_t cl, int offset,
-                 enum machine_mode mode)
+                 machine_mode mode)
 {
   unsigned int regno = REGNO (operand);
 
@@ -2805,16 +2888,16 @@ reg_fits_class_p (const_rtx operand, reg_class_t cl, int offset,
    split_all_insns_noflow.  Return last insn in the sequence if successful,
    or NULL if unsuccessful.  */
 
-static rtx
-split_insn (rtx insn)
+static rtx_insn *
+split_insn (rtx_insn *insn)
 {
   /* Split insns here to get max fine-grain parallelism.  */
-  rtx first = PREV_INSN (insn);
-  rtx last = try_split (PATTERN (insn), insn, 1);
+  rtx_insn *first = PREV_INSN (insn);
+  rtx_insn *last = try_split (PATTERN (insn), insn, 1);
   rtx insn_set, last_set, note;
 
   if (last == insn)
-    return NULL_RTX;
+    return NULL;
 
   /* If the original instruction was a single set that was known to be
      equivalent to a constant, see if we can say the same about the last
@@ -2865,13 +2948,13 @@ split_all_insns (void)
   bool changed;
   basic_block bb;
 
-  blocks = sbitmap_alloc (last_basic_block);
+  blocks = sbitmap_alloc (last_basic_block_for_fn (cfun));
   bitmap_clear (blocks);
   changed = false;
 
-  FOR_EACH_BB_REVERSE (bb)
+  FOR_EACH_BB_REVERSE_FN (bb, cfun)
     {
-      rtx insn, next;
+      rtx_insn *insn, *next;
       bool finish = false;
 
       rtl_profile_for_bb (bb);
@@ -2927,7 +3010,7 @@ split_all_insns (void)
 unsigned int
 split_all_insns_noflow (void)
 {
-  rtx next, insn;
+  rtx_insn *next, *insn;
 
   for (insn = get_insns (); insn; insn = next)
     {
@@ -2960,7 +3043,7 @@ split_all_insns_noflow (void)
 #ifdef HAVE_peephole2
 struct peep2_insn_data
 {
-  rtx insn;
+  rtx_insn *insn;
   regset live_before;
 };
 
@@ -2973,10 +3056,9 @@ static bool peep2_do_cleanup_cfg;
 /* The number of instructions available to match a peep2.  */
 int peep2_current_count;
 
-/* A non-insn marker indicating the last insn of the block.
-   The live_before regset for this element is correct, indicating
-   DF_LIVE_OUT for the block.  */
-#define PEEP2_EOB      pc_rtx
+/* A marker indicating the last insn of the block.  The live_before regset
+   for this element is correct, indicating DF_LIVE_OUT for the block.  */
+#define PEEP2_EOB invalid_insn_rtx
 
 /* Wrap N to fit into the peep2_insn_data buffer.  */
 
@@ -2992,7 +3074,7 @@ peep2_buf_position (int n)
    does not exist.  Used by the recognizer to find the next insn to match
    in a multi-insn pattern.  */
 
-rtx
+rtx_insn *
 peep2_next_insn (int n)
 {
   gcc_assert (n <= peep2_current_count);
@@ -3022,22 +3104,22 @@ peep2_regno_dead_p (int ofs, int regno)
 int
 peep2_reg_dead_p (int ofs, rtx reg)
 {
-  int regno, n;
-
   gcc_assert (ofs < MAX_INSNS_PER_PEEP2 + 1);
 
   ofs = peep2_buf_position (peep2_current + ofs);
 
   gcc_assert (peep2_insn_data[ofs].insn != NULL_RTX);
 
-  regno = REGNO (reg);
-  n = hard_regno_nregs[regno][GET_MODE (reg)];
-  while (--n >= 0)
-    if (REGNO_REG_SET_P (peep2_insn_data[ofs].live_before, regno + n))
+  unsigned int end_regno = END_REGNO (reg);
+  for (unsigned int regno = REGNO (reg); regno < end_regno; ++regno)
+    if (REGNO_REG_SET_P (peep2_insn_data[ofs].live_before, regno))
       return 0;
   return 1;
 }
 
+/* Regno offset to be used in the register search.  */
+static int search_ofs;
+
 /* Try to find a hard register of mode MODE, matching the register class in
    CLASS_STR, which is available at the beginning of insn CURRENT_INSN and
    remains available until the end of LAST_INSN.  LAST_INSN may be NULL_RTX,
@@ -3051,12 +3133,11 @@ peep2_reg_dead_p (int ofs, rtx reg)
 
 rtx
 peep2_find_free_register (int from, int to, const char *class_str,
-                         enum machine_mode mode, HARD_REG_SET *reg_set)
+                         machine_mode mode, HARD_REG_SET *reg_set)
 {
-  static int search_ofs;
   enum reg_class cl;
   HARD_REG_SET live;
-  df_ref *def_rec;
+  df_ref def;
   int i;
 
   gcc_assert (from < MAX_INSNS_PER_PEEP2 + 1);
@@ -3073,15 +3154,13 @@ peep2_find_free_register (int from, int to, const char *class_str,
       gcc_assert (peep2_insn_data[from].insn != NULL_RTX);
 
       /* Don't use registers set or clobbered by the insn.  */
-      for (def_rec = DF_INSN_DEFS (peep2_insn_data[from].insn);
-          *def_rec; def_rec++)
-       SET_HARD_REG_BIT (live, DF_REF_REGNO (*def_rec));
+      FOR_EACH_INSN_DEF (def, peep2_insn_data[from].insn)
+       SET_HARD_REG_BIT (live, DF_REF_REGNO (def));
 
       from = peep2_buf_position (from + 1);
     }
 
-  cl = (class_str[0] == 'r' ? GENERAL_REGS
-          : REG_CLASS_FROM_CONSTRAINT (class_str[0], class_str));
+  cl = reg_class_for_constraint (lookup_constraint (class_str));
 
   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
     {
@@ -3097,32 +3176,53 @@ peep2_find_free_register (int from, int to, const char *class_str,
       regno = raw_regno;
 #endif
 
-      /* Don't allocate fixed registers.  */
-      if (fixed_regs[regno])
-       continue;
-      /* Don't allocate global registers.  */
-      if (global_regs[regno])
-       continue;
-      /* Make sure the register is of the right class.  */
-      if (! TEST_HARD_REG_BIT (reg_class_contents[cl], regno))
-       continue;
-      /* And can support the mode we need.  */
+      /* Can it support the mode we need?  */
       if (! HARD_REGNO_MODE_OK (regno, mode))
        continue;
-      /* And that we don't create an extra save/restore.  */
-      if (! call_used_regs[regno] && ! df_regs_ever_live_p (regno))
-       continue;
-      if (! targetm.hard_regno_scratch_ok (regno))
-       continue;
-
-      /* And we don't clobber traceback for noreturn functions.  */
-      if ((regno == FRAME_POINTER_REGNUM || regno == HARD_FRAME_POINTER_REGNUM)
-         && (! reload_completed || frame_pointer_needed))
-       continue;
 
       success = 1;
-      for (j = hard_regno_nregs[regno][mode] - 1; j >= 0; j--)
+      for (j = 0; success && j < hard_regno_nregs[regno][mode]; j++)
        {
+         /* Don't allocate fixed registers.  */
+         if (fixed_regs[regno + j])
+           {
+             success = 0;
+             break;
+           }
+         /* Don't allocate global registers.  */
+         if (global_regs[regno + j])
+           {
+             success = 0;
+             break;
+           }
+         /* Make sure the register is of the right class.  */
+         if (! TEST_HARD_REG_BIT (reg_class_contents[cl], regno + j))
+           {
+             success = 0;
+             break;
+           }
+         /* And that we don't create an extra save/restore.  */
+         if (! call_used_regs[regno + j] && ! df_regs_ever_live_p (regno + j))
+           {
+             success = 0;
+             break;
+           }
+
+         if (! targetm.hard_regno_scratch_ok (regno + j))
+           {
+             success = 0;
+             break;
+           }
+
+         /* And we don't clobber traceback for noreturn functions.  */
+         if ((regno + j == FRAME_POINTER_REGNUM
+              || regno + j == HARD_FRAME_POINTER_REGNUM)
+             && (! reload_completed || frame_pointer_needed))
+           {
+             success = 0;
+             break;
+           }
+
          if (TEST_HARD_REG_BIT (*reg_set, regno + j)
              || TEST_HARD_REG_BIT (live, regno + j))
            {
@@ -3130,6 +3230,7 @@ peep2_find_free_register (int from, int to, const char *class_str,
              break;
            }
        }
+
       if (success)
        {
          add_to_hard_reg_set (reg_set, mode, regno);
@@ -3157,7 +3258,7 @@ peep2_reinit_state (regset live)
 
   /* Indicate that all slots except the last holds invalid data.  */
   for (i = 0; i < MAX_INSNS_PER_PEEP2; ++i)
-    peep2_insn_data[i].insn = NULL_RTX;
+    peep2_insn_data[i].insn = NULL;
   peep2_current_count = 0;
 
   /* Indicate that the last slot contains live_after data.  */
@@ -3172,12 +3273,14 @@ peep2_reinit_state (regset live)
    replacing them with ATTEMPT.  Returns the last insn emitted, or NULL
    if the replacement is rejected.  */
 
-static rtx
-peep2_attempt (basic_block bb, rtx insn, int match_len, rtx attempt)
+static rtx_insn *
+peep2_attempt (basic_block bb, rtx_insn *insn, int match_len, rtx_insn *attempt)
 {
   int i;
-  rtx last, eh_note, as_note, before_try, x;
-  rtx old_insn, new_insn;
+  rtx_insn *last, *before_try, *x;
+  rtx eh_note, as_note;
+  rtx_insn *old_insn;
+  rtx_insn *new_insn;
   bool was_call = false;
 
   /* If we are splitting an RTX_FRAME_RELATED_P insn, do not allow it to
@@ -3287,6 +3390,7 @@ peep2_attempt (basic_block bb, rtx insn, int match_len, rtx attempt)
 
       CALL_INSN_FUNCTION_USAGE (new_insn)
        = CALL_INSN_FUNCTION_USAGE (old_insn);
+      SIBLING_CALL_P (new_insn) = SIBLING_CALL_P (old_insn);
 
       for (note = REG_NOTES (old_insn);
           note;
@@ -3331,9 +3435,10 @@ peep2_attempt (basic_block bb, rtx insn, int match_len, rtx attempt)
   eh_note = find_reg_note (peep2_insn_data[i].insn, REG_EH_REGION, NULL_RTX);
 
   /* Replace the old sequence with the new.  */
+  rtx_insn *peepinsn = peep2_insn_data[i].insn;
   last = emit_insn_after_setloc (attempt,
                                 peep2_insn_data[i].insn,
-                                INSN_LOCATION (peep2_insn_data[i].insn));
+                                INSN_LOCATION (peepinsn));
   before_try = PREV_INSN (insn);
   delete_insn_chain (insn, peep2_insn_data[i].insn, false);
 
@@ -3404,10 +3509,11 @@ peep2_attempt (basic_block bb, rtx insn, int match_len, rtx attempt)
    matched, and which now need to be replaced in the buffer.  */
 
 static void
-peep2_update_life (basic_block bb, int match_len, rtx last, rtx prev)
+peep2_update_life (basic_block bb, int match_len, rtx_insn *last,
+                  rtx_insn *prev)
 {
   int i = peep2_buf_position (peep2_current + match_len + 1);
-  rtx x;
+  rtx_insn *x;
   regset_head live;
 
   INIT_REG_SET (&live);
@@ -3446,7 +3552,7 @@ peep2_update_life (basic_block bb, int match_len, rtx last, rtx prev)
    add more instructions to the buffer.  */
 
 static bool
-peep2_fill_buffer (basic_block bb, rtx insn, regset live)
+peep2_fill_buffer (basic_block bb, rtx_insn *insn, regset live)
 {
   int pos;
 
@@ -3481,7 +3587,7 @@ peep2_fill_buffer (basic_block bb, rtx insn, regset live)
 static void
 peephole2_optimize (void)
 {
-  rtx insn;
+  rtx_insn *insn;
   bitmap live;
   int i;
   basic_block bb;
@@ -3496,9 +3602,10 @@ peephole2_optimize (void)
   /* Initialize the regsets we're going to use.  */
   for (i = 0; i < MAX_INSNS_PER_PEEP2 + 1; ++i)
     peep2_insn_data[i].live_before = BITMAP_ALLOC (&reg_obstack);
+  search_ofs = 0;
   live = BITMAP_ALLOC (&reg_obstack);
 
-  FOR_EACH_BB_REVERSE (bb)
+  FOR_EACH_BB_REVERSE_FN (bb, cfun)
     {
       bool past_end = false;
       int pos;
@@ -3513,7 +3620,7 @@ peephole2_optimize (void)
       insn = BB_HEAD (bb);
       for (;;)
        {
-         rtx attempt, head;
+         rtx_insn *attempt, *head;
          int match_len;
 
          if (!past_end && !NONDEBUG_INSN_P (insn))
@@ -3543,7 +3650,7 @@ peephole2_optimize (void)
          attempt = peephole2_insns (PATTERN (head), head, &match_len);
          if (attempt != NULL)
            {
-             rtx last = peep2_attempt (bb, head, match_len, attempt);
+             rtx_insn *last = peep2_attempt (bb, head, match_len, attempt);
              if (last)
                {
                  peep2_update_life (bb, match_len, last, PREV_INSN (attempt));
@@ -3563,6 +3670,8 @@ peephole2_optimize (void)
   BITMAP_FREE (live);
   if (peep2_do_rebuild_jump_labels)
     rebuild_jump_labels (get_insns ());
+  if (peep2_do_cleanup_cfg)
+    cleanup_cfg (CLEANUP_CFG_CHANGED);
 }
 #endif /* HAVE_peephole2 */
 
@@ -3573,7 +3682,7 @@ peephole2_optimize (void)
    must be either a single_set or a PARALLEL with SETs inside.  */
 
 int
-store_data_bypass_p (rtx out_insn, rtx in_insn)
+store_data_bypass_p (rtx_insn *out_insn, rtx_insn *in_insn)
 {
   rtx out_set, in_set;
   rtx out_pat, in_pat;
@@ -3666,7 +3775,7 @@ store_data_bypass_p (rtx out_insn, rtx in_insn)
    of insn categorization may be any JUMP or CALL insn.  */
 
 int
-if_test_bypass_p (rtx out_insn, rtx in_insn)
+if_test_bypass_p (rtx_insn *out_insn, rtx_insn *in_insn)
 {
   rtx out_set, in_set;
 
@@ -3714,12 +3823,6 @@ if_test_bypass_p (rtx out_insn, rtx in_insn)
   return true;
 }
 \f
-static bool
-gate_handle_peephole2 (void)
-{
-  return (optimize > 0 && flag_peephole2);
-}
-
 static unsigned int
 rest_of_handle_peephole2 (void)
 {
@@ -3729,54 +3832,90 @@ rest_of_handle_peephole2 (void)
   return 0;
 }
 
-struct rtl_opt_pass pass_peephole2 =
-{
- {
-  RTL_PASS,
-  "peephole2",                          /* name */
-  OPTGROUP_NONE,                        /* optinfo_flags */
-  gate_handle_peephole2,                /* gate */
-  rest_of_handle_peephole2,             /* execute */
-  NULL,                                 /* sub */
-  NULL,                                 /* next */
-  0,                                    /* static_pass_number */
-  TV_PEEPHOLE2,                         /* tv_id */
-  0,                                    /* properties_required */
-  0,                                    /* properties_provided */
-  0,                                    /* properties_destroyed */
-  0,                                    /* todo_flags_start */
-  TODO_df_finish | TODO_verify_rtl_sharing |
-  0                                    /* todo_flags_finish */
- }
+namespace {
+
+const pass_data pass_data_peephole2 =
+{
+  RTL_PASS, /* type */
+  "peephole2", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  TV_PEEPHOLE2, /* tv_id */
+  0, /* properties_required */
+  0, /* properties_provided */
+  0, /* properties_destroyed */
+  0, /* todo_flags_start */
+  TODO_df_finish, /* todo_flags_finish */
 };
 
-static unsigned int
-rest_of_handle_split_all_insns (void)
+class pass_peephole2 : public rtl_opt_pass
 {
-  split_all_insns ();
-  return 0;
+public:
+  pass_peephole2 (gcc::context *ctxt)
+    : rtl_opt_pass (pass_data_peephole2, ctxt)
+  {}
+
+  /* opt_pass methods: */
+  /* The epiphany backend creates a second instance of this pass, so we need
+     a clone method.  */
+  opt_pass * clone () { return new pass_peephole2 (m_ctxt); }
+  virtual bool gate (function *) { return (optimize > 0 && flag_peephole2); }
+  virtual unsigned int execute (function *)
+    {
+      return rest_of_handle_peephole2 ();
+    }
+
+}; // class pass_peephole2
+
+} // anon namespace
+
+rtl_opt_pass *
+make_pass_peephole2 (gcc::context *ctxt)
+{
+  return new pass_peephole2 (ctxt);
 }
 
-struct rtl_opt_pass pass_split_all_insns =
-{
- {
-  RTL_PASS,
-  "split1",                             /* name */
-  OPTGROUP_NONE,                        /* optinfo_flags */
-  NULL,                                 /* gate */
-  rest_of_handle_split_all_insns,       /* execute */
-  NULL,                                 /* sub */
-  NULL,                                 /* next */
-  0,                                    /* static_pass_number */
-  TV_NONE,                              /* tv_id */
-  0,                                    /* properties_required */
-  0,                                    /* properties_provided */
-  0,                                    /* properties_destroyed */
-  0,                                    /* todo_flags_start */
-  0                                     /* todo_flags_finish */
- }
+namespace {
+
+const pass_data pass_data_split_all_insns =
+{
+  RTL_PASS, /* type */
+  "split1", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  TV_NONE, /* tv_id */
+  0, /* properties_required */
+  0, /* properties_provided */
+  0, /* properties_destroyed */
+  0, /* todo_flags_start */
+  0, /* todo_flags_finish */
 };
 
+class pass_split_all_insns : public rtl_opt_pass
+{
+public:
+  pass_split_all_insns (gcc::context *ctxt)
+    : rtl_opt_pass (pass_data_split_all_insns, ctxt)
+  {}
+
+  /* opt_pass methods: */
+  /* The epiphany backend creates a second instance of this pass, so
+     we need a clone method.  */
+  opt_pass * clone () { return new pass_split_all_insns (m_ctxt); }
+  virtual unsigned int execute (function *)
+    {
+      split_all_insns ();
+      return 0;
+    }
+
+}; // class pass_split_all_insns
+
+} // anon namespace
+
+rtl_opt_pass *
+make_pass_split_all_insns (gcc::context *ctxt)
+{
+  return new pass_split_all_insns (ctxt);
+}
+
 static unsigned int
 rest_of_handle_split_after_reload (void)
 {
@@ -3788,28 +3927,78 @@ rest_of_handle_split_after_reload (void)
   return 0;
 }
 
-struct rtl_opt_pass pass_split_after_reload =
-{
- {
-  RTL_PASS,
-  "split2",                             /* name */
-  OPTGROUP_NONE,                        /* optinfo_flags */
-  NULL,                                 /* gate */
-  rest_of_handle_split_after_reload,    /* execute */
-  NULL,                                 /* sub */
-  NULL,                                 /* next */
-  0,                                    /* static_pass_number */
-  TV_NONE,                              /* tv_id */
-  0,                                    /* properties_required */
-  0,                                    /* properties_provided */
-  0,                                    /* properties_destroyed */
-  0,                                    /* todo_flags_start */
-  0                                     /* todo_flags_finish */
- }
+namespace {
+
+const pass_data pass_data_split_after_reload =
+{
+  RTL_PASS, /* type */
+  "split2", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  TV_NONE, /* tv_id */
+  0, /* properties_required */
+  0, /* properties_provided */
+  0, /* properties_destroyed */
+  0, /* todo_flags_start */
+  0, /* todo_flags_finish */
 };
 
-static bool
-gate_handle_split_before_regstack (void)
+class pass_split_after_reload : public rtl_opt_pass
+{
+public:
+  pass_split_after_reload (gcc::context *ctxt)
+    : rtl_opt_pass (pass_data_split_after_reload, ctxt)
+  {}
+
+  /* opt_pass methods: */
+  virtual unsigned int execute (function *)
+    {
+      return rest_of_handle_split_after_reload ();
+    }
+
+}; // class pass_split_after_reload
+
+} // anon namespace
+
+rtl_opt_pass *
+make_pass_split_after_reload (gcc::context *ctxt)
+{
+  return new pass_split_after_reload (ctxt);
+}
+
+namespace {
+
+const pass_data pass_data_split_before_regstack =
+{
+  RTL_PASS, /* type */
+  "split3", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  TV_NONE, /* tv_id */
+  0, /* properties_required */
+  0, /* properties_provided */
+  0, /* properties_destroyed */
+  0, /* todo_flags_start */
+  0, /* todo_flags_finish */
+};
+
+class pass_split_before_regstack : public rtl_opt_pass
+{
+public:
+  pass_split_before_regstack (gcc::context *ctxt)
+    : rtl_opt_pass (pass_data_split_before_regstack, ctxt)
+  {}
+
+  /* opt_pass methods: */
+  virtual bool gate (function *);
+  virtual unsigned int execute (function *)
+    {
+      split_all_insns ();
+      return 0;
+    }
+
+}; // class pass_split_before_regstack
+
+bool
+pass_split_before_regstack::gate (function *)
 {
 #if HAVE_ATTR_length && defined (STACK_REGS)
   /* If flow2 creates new instructions which need splitting
@@ -3826,100 +4015,137 @@ gate_handle_split_before_regstack (void)
 #endif
 }
 
+} // anon namespace
+
+rtl_opt_pass *
+make_pass_split_before_regstack (gcc::context *ctxt)
+{
+  return new pass_split_before_regstack (ctxt);
+}
+
 static unsigned int
-rest_of_handle_split_before_regstack (void)
+rest_of_handle_split_before_sched2 (void)
 {
+#ifdef INSN_SCHEDULING
   split_all_insns ();
+#endif
   return 0;
 }
 
-struct rtl_opt_pass pass_split_before_regstack =
-{
- {
-  RTL_PASS,
-  "split3",                             /* name */
-  OPTGROUP_NONE,                        /* optinfo_flags */
-  gate_handle_split_before_regstack,    /* gate */
-  rest_of_handle_split_before_regstack, /* execute */
-  NULL,                                 /* sub */
-  NULL,                                 /* next */
-  0,                                    /* static_pass_number */
-  TV_NONE,                              /* tv_id */
-  0,                                    /* properties_required */
-  0,                                    /* properties_provided */
-  0,                                    /* properties_destroyed */
-  0,                                    /* todo_flags_start */
-  0                                     /* todo_flags_finish */
- }
+namespace {
+
+const pass_data pass_data_split_before_sched2 =
+{
+  RTL_PASS, /* type */
+  "split4", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  TV_NONE, /* tv_id */
+  0, /* properties_required */
+  0, /* properties_provided */
+  0, /* properties_destroyed */
+  0, /* todo_flags_start */
+  0, /* todo_flags_finish */
 };
 
-static bool
-gate_handle_split_before_sched2 (void)
+class pass_split_before_sched2 : public rtl_opt_pass
 {
+public:
+  pass_split_before_sched2 (gcc::context *ctxt)
+    : rtl_opt_pass (pass_data_split_before_sched2, ctxt)
+  {}
+
+  /* opt_pass methods: */
+  virtual bool gate (function *)
+    {
 #ifdef INSN_SCHEDULING
-  return optimize > 0 && flag_schedule_insns_after_reload;
+      return optimize > 0 && flag_schedule_insns_after_reload;
 #else
-  return 0;
+      return false;
 #endif
-}
+    }
 
-static unsigned int
-rest_of_handle_split_before_sched2 (void)
+  virtual unsigned int execute (function *)
+    {
+      return rest_of_handle_split_before_sched2 ();
+    }
+
+}; // class pass_split_before_sched2
+
+} // anon namespace
+
+rtl_opt_pass *
+make_pass_split_before_sched2 (gcc::context *ctxt)
 {
-#ifdef INSN_SCHEDULING
-  split_all_insns ();
-#endif
-  return 0;
+  return new pass_split_before_sched2 (ctxt);
 }
 
-struct rtl_opt_pass pass_split_before_sched2 =
-{
- {
-  RTL_PASS,
-  "split4",                             /* name */
-  OPTGROUP_NONE,                        /* optinfo_flags */
-  gate_handle_split_before_sched2,      /* gate */
-  rest_of_handle_split_before_sched2,   /* execute */
-  NULL,                                 /* sub */
-  NULL,                                 /* next */
-  0,                                    /* static_pass_number */
-  TV_NONE,                              /* tv_id */
-  0,                                    /* properties_required */
-  0,                                    /* properties_provided */
-  0,                                    /* properties_destroyed */
-  0,                                    /* todo_flags_start */
-  TODO_verify_flow                      /* todo_flags_finish */
- }
+namespace {
+
+const pass_data pass_data_split_for_shorten_branches =
+{
+  RTL_PASS, /* type */
+  "split5", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  TV_NONE, /* tv_id */
+  0, /* properties_required */
+  0, /* properties_provided */
+  0, /* properties_destroyed */
+  0, /* todo_flags_start */
+  0, /* todo_flags_finish */
 };
 
-/* The placement of the splitting that we do for shorten_branches
-   depends on whether regstack is used by the target or not.  */
-static bool
-gate_do_final_split (void)
+class pass_split_for_shorten_branches : public rtl_opt_pass
 {
+public:
+  pass_split_for_shorten_branches (gcc::context *ctxt)
+    : rtl_opt_pass (pass_data_split_for_shorten_branches, ctxt)
+  {}
+
+  /* opt_pass methods: */
+  virtual bool gate (function *)
+    {
+      /* The placement of the splitting that we do for shorten_branches
+        depends on whether regstack is used by the target or not.  */
 #if HAVE_ATTR_length && !defined (STACK_REGS)
-  return 1;
+      return true;
 #else
-  return 0;
+      return false;
 #endif
+    }
+
+  virtual unsigned int execute (function *)
+    {
+      return split_all_insns_noflow ();
+    }
+
+}; // class pass_split_for_shorten_branches
+
+} // anon namespace
+
+rtl_opt_pass *
+make_pass_split_for_shorten_branches (gcc::context *ctxt)
+{
+  return new pass_split_for_shorten_branches (ctxt);
 }
 
-struct rtl_opt_pass pass_split_for_shorten_branches =
-{
- {
-  RTL_PASS,
-  "split5",                             /* name */
-  OPTGROUP_NONE,                        /* optinfo_flags */
-  gate_do_final_split,                  /* gate */
-  split_all_insns_noflow,               /* execute */
-  NULL,                                 /* sub */
-  NULL,                                 /* next */
-  0,                                    /* static_pass_number */
-  TV_NONE,                              /* tv_id */
-  0,                                    /* properties_required */
-  0,                                    /* properties_provided */
-  0,                                    /* properties_destroyed */
-  0,                                    /* todo_flags_start */
-  TODO_verify_rtl_sharing               /* todo_flags_finish */
- }
-};
+/* (Re)initialize the target information after a change in target.  */
+
+void
+recog_init ()
+{
+  /* The information is zero-initialized, so we don't need to do anything
+     first time round.  */
+  if (!this_target_recog->x_initialized)
+    {
+      this_target_recog->x_initialized = true;
+      return;
+    }
+  memset (this_target_recog->x_bool_attr_masks, 0,
+         sizeof (this_target_recog->x_bool_attr_masks));
+  for (int i = 0; i < LAST_INSN_CODE; ++i)
+    if (this_target_recog->x_op_alt[i])
+      {
+       free (this_target_recog->x_op_alt[i]);
+       this_target_recog->x_op_alt[i] = 0;
+      }
+}