IA MCU psABI support: changes to libraries
[gcc.git] / gcc / recog.c
index 057f41128a57533b9453b13b374b6fe8cca8e5c3..3fbfe076ed8b1f3c682cf07c987a53886eccea65 100644 (file)
@@ -1,5 +1,5 @@
 /* Subroutines used by or related to instruction recognition.
-   Copyright (C) 1987-2014 Free Software Foundation, Inc.
+   Copyright (C) 1987-2015 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -22,6 +22,8 @@ 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"
@@ -31,9 +33,23 @@ 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"
@@ -41,25 +57,22 @@ along with GCC; see the file COPYING3.  If not see
 #include "df.h"
 #include "insn-codes.h"
 
-#ifndef STACK_PUSH_CODE
-#ifdef STACK_GROWS_DOWNWARD
-#define STACK_PUSH_CODE PRE_DEC
-#else
-#define STACK_PUSH_CODE PRE_INC
-#endif
-#endif
-
 #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
@@ -73,9 +86,14 @@ int volatile_ok;
 
 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;
@@ -350,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;
     }
 
@@ -414,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);
 
@@ -490,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;
 }
 
@@ -560,8 +579,8 @@ cancel_changes (int num)
    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);
@@ -667,8 +686,8 @@ 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 && HAVE_extzv)
@@ -720,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)
@@ -809,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 ();
@@ -819,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 ();
@@ -832,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 ();
@@ -841,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 ();
@@ -852,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);
@@ -867,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
@@ -883,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;
 
@@ -898,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;
@@ -933,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)
@@ -950,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,
@@ -967,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);
 
@@ -1082,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);
 }
@@ -1094,7 +1111,7 @@ 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_CODE (op) == SUBREG)
     {
@@ -1117,7 +1134,7 @@ register_operand (rtx op, enum machine_mode 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);
 }
@@ -1126,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.
@@ -1142,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.  */
@@ -1165,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;
@@ -1180,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.  */
@@ -1197,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));
 }
@@ -1209,7 +1272,7 @@ 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);
@@ -1223,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);
 
@@ -1250,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;
     }
 
@@ -1269,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;
@@ -1289,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
@@ -1311,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;
 
@@ -1334,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
@@ -1367,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;
@@ -1393,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));
@@ -1514,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;
@@ -1675,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)
@@ -1682,15 +1742,6 @@ 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':
@@ -1719,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);
@@ -1986,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);
@@ -2007,11 +1972,11 @@ offsettable_address_addr_space_p (int strictp, enum machine_mode mode, rtx y,
   if (mode_dependent_address_p (y, as))
     return 0;
 
-  enum machine_mode address_mode = GET_MODE (y);
+  machine_mode address_mode = GET_MODE (y);
   if (address_mode == VOIDmode)
     address_mode = targetm.addr_space.address_mode (as);
 #ifdef POINTERS_EXTEND_UNSIGNED
-  enum machine_mode pointer_mode = targetm.addr_space.pointer_mode (as);
+  machine_mode pointer_mode = targetm.addr_space.pointer_mode (as);
 #endif
 
   /* ??? How much offset does an offsettable BLKmode reference need?
@@ -2093,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;
@@ -2106,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;
 }
@@ -2130,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;
@@ -2225,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;
            }
 
@@ -2297,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);
@@ -2386,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.
 
@@ -2419,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];
@@ -2446,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;
 
@@ -2460,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;
@@ -2500,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.  */
@@ -2603,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
@@ -2731,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;
@@ -2756,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;
                }
              }
@@ -2846,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;
 }
@@ -2858,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);
 
@@ -2876,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
@@ -2942,7 +2954,7 @@ split_all_insns (void)
 
   FOR_EACH_BB_REVERSE_FN (bb, cfun)
     {
-      rtx insn, next;
+      rtx_insn *insn, *next;
       bool finish = false;
 
       rtl_profile_for_bb (bb);
@@ -2998,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)
     {
@@ -3031,7 +3043,7 @@ split_all_insns_noflow (void)
 #ifdef HAVE_peephole2
 struct peep2_insn_data
 {
-  rtx insn;
+  rtx_insn *insn;
   regset live_before;
 };
 
@@ -3044,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.  */
 
@@ -3063,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);
@@ -3093,18 +3104,15 @@ 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;
 }
@@ -3125,11 +3133,11 @@ static int search_ofs;
 
 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)
 {
   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);
@@ -3146,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++)
     {
@@ -3252,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.  */
@@ -3267,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
@@ -3382,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;
@@ -3426,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);
 
@@ -3499,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);
@@ -3541,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;
 
@@ -3576,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;
@@ -3609,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))
@@ -3639,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));
@@ -3659,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 */
 
@@ -3669,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;
@@ -3762,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;
 
@@ -3826,13 +3839,12 @@ const pass_data pass_data_peephole2 =
   RTL_PASS, /* type */
   "peephole2", /* name */
   OPTGROUP_NONE, /* optinfo_flags */
-  true, /* has_execute */
   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 */
+  TODO_df_finish, /* todo_flags_finish */
 };
 
 class pass_peephole2 : public rtl_opt_pass
@@ -3869,7 +3881,6 @@ const pass_data pass_data_split_all_insns =
   RTL_PASS, /* type */
   "split1", /* name */
   OPTGROUP_NONE, /* optinfo_flags */
-  true, /* has_execute */
   TV_NONE, /* tv_id */
   0, /* properties_required */
   0, /* properties_provided */
@@ -3923,7 +3934,6 @@ const pass_data pass_data_split_after_reload =
   RTL_PASS, /* type */
   "split2", /* name */
   OPTGROUP_NONE, /* optinfo_flags */
-  true, /* has_execute */
   TV_NONE, /* tv_id */
   0, /* properties_required */
   0, /* properties_provided */
@@ -3962,7 +3972,6 @@ const pass_data pass_data_split_before_regstack =
   RTL_PASS, /* type */
   "split3", /* name */
   OPTGROUP_NONE, /* optinfo_flags */
-  true, /* has_execute */
   TV_NONE, /* tv_id */
   0, /* properties_required */
   0, /* properties_provided */
@@ -4030,13 +4039,12 @@ const pass_data pass_data_split_before_sched2 =
   RTL_PASS, /* type */
   "split4", /* name */
   OPTGROUP_NONE, /* optinfo_flags */
-  true, /* has_execute */
   TV_NONE, /* tv_id */
   0, /* properties_required */
   0, /* properties_provided */
   0, /* properties_destroyed */
   0, /* todo_flags_start */
-  TODO_verify_flow, /* todo_flags_finish */
+  0, /* todo_flags_finish */
 };
 
 class pass_split_before_sched2 : public rtl_opt_pass
@@ -4078,13 +4086,12 @@ const pass_data pass_data_split_for_shorten_branches =
   RTL_PASS, /* type */
   "split5", /* name */
   OPTGROUP_NONE, /* optinfo_flags */
-  true, /* has_execute */
   TV_NONE, /* tv_id */
   0, /* properties_required */
   0, /* properties_provided */
   0, /* properties_destroyed */
   0, /* todo_flags_start */
-  TODO_verify_rtl_sharing, /* todo_flags_finish */
+  0, /* todo_flags_finish */
 };
 
 class pass_split_for_shorten_branches : public rtl_opt_pass
@@ -4120,3 +4127,25 @@ make_pass_split_for_shorten_branches (gcc::context *ctxt)
 {
   return new pass_split_for_shorten_branches (ctxt);
 }
+
+/* (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;
+      }
+}