diff --git a/gcc/doc/md.texi b/gcc/doc/md.texi
index 5d86152e5dd..dc8c068646d 100644
--- a/gcc/doc/md.texi
+++ b/gcc/doc/md.texi
@@ -4513,8 +4513,8 @@ Register constraints correspond directly to register classes.
 @xref{Register Classes}.  There is thus not much flexibility in their
 definitions.
 
-@deffn {MD Expression} define_register_constraint name regclass docstring
-All three arguments are string constants.
+@deffn {MD Expression} define_register_constraint name regclass docstring [filter]
+All arguments are string constants.
 @var{name} is the name of the constraint, as it will appear in
 @code{match_operand} expressions.  If @var{name} is a multi-letter
 constraint its length shall be the same for all constraints starting
@@ -4526,6 +4526,43 @@ look at the operand.  The usual use of expressions is to map some
 register constraints to @code{NO_REGS} when the register class
 is not available on a given subarchitecture.
 
+If an operand occupies multiple hard registers, the constraint
+requires all of those registers to belong to @var{regclass}.
+For example, if @var{regclass} is @code{GENERAL_REGS} and
+@code{GENERAL_REGS} contains registers @code{r0} to @code{r15},
+the constraint does not allow @var{r15} to be used for modes
+that occupy more than one register.
+
+@cindex @code{TARGET_HARD_REGNO_MODE_OK} and constraints
+The choice of register is also constrained by @code{TARGET_HARD_REGNO_MODE_OK}.
+For example, if @code{TARGET_HARD_REGNO_MODE_OK} disallows @samp{(reg:DI r1)},
+that requirement applies to all constraints whose classes include @code{r1}.
+
+However, it is sometimes useful to impose extra operand-specific
+requirements on the register number.  For example, a target might not
+want to prevent @emph{all} odd-even pairs from holding @code{DImode}
+values, but it might still need to prevent specific operands from
+having an odd-numbered register.  The optional @var{filter} argument
+exists for such cases.  When given, @var{filter} is a C++ expression
+that evaluates to true if @code{regno} is a valid register for the
+operand.  If an operand occupies multiple registers, the condition
+applies only to the first register.
+
+For example:
+
+@smallexample
+(define_register_constraint "e" "GENERAL_REGS" "..." "regno % 2 == 0")
+@end smallexample
+
+defines a constraint that requires an even-numbered general register.
+
+Filter conditions that impose an alignment are encouraged to test
+the alignment of @code{regno} itself, as in the example, rather than
+calculate an offset relative to the start of the class.  If it is
+sometimes necessary for a register of class @var{c} to be aligned
+to @var{n}, the first register in @var{c} should itself by divisible
+by @var{n}.
+
 @var{docstring} is a sentence documenting the meaning of the
 constraint.  Docstrings are explained further below.
 @end deffn
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index abc23b2bb73..b13b5161161 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -2478,7 +2478,8 @@ When a value occupying several consecutive registers is expected in a
 certain class, all the registers used must belong to that class.
 Therefore, register classes cannot be used to enforce a requirement for
 a register pair to start with an even-numbered register.  The way to
-specify this requirement is with @code{TARGET_HARD_REGNO_MODE_OK}.
+specify this requirement is with @code{TARGET_HARD_REGNO_MODE_OK},
+or with a filter expression in a @code{define_register_constraint}.
 
 Register classes used for input-operands of bitwise-and or shift
 instructions have a special requirement: each such class must have, for
diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
index 3d3ae12cc2f..9a92cb97337 100644
--- a/gcc/doc/tm.texi.in
+++ b/gcc/doc/tm.texi.in
@@ -2060,7 +2060,8 @@ When a value occupying several consecutive registers is expected in a
 certain class, all the registers used must belong to that class.
 Therefore, register classes cannot be used to enforce a requirement for
 a register pair to start with an even-numbered register.  The way to
-specify this requirement is with @code{TARGET_HARD_REGNO_MODE_OK}.
+specify this requirement is with @code{TARGET_HARD_REGNO_MODE_OK},
+or with a filter expression in a @code{define_register_constraint}.
 
 Register classes used for input-operands of bitwise-and or shift
 instructions have a special requirement: each such class must have, for
diff --git a/gcc/genconfig.cc b/gcc/genconfig.cc
index 2ee323f80c3..c8c2ebef21c 100644
--- a/gcc/genconfig.cc
+++ b/gcc/genconfig.cc
@@ -360,6 +360,8 @@ main (int argc, const char **argv)
       printf ("#define MAX_INSNS_PER_PEEP2 0\n");
     }
 
+  printf ("#define NUM_REGISTER_FILTERS %d\n", register_filters.length ());
+
   puts ("\n#endif /* GCC_INSN_CONFIG_H */");
 
   if (ferror (stdout) || fflush (stdout) || fclose (stdout))
diff --git a/gcc/genpreds.cc b/gcc/genpreds.cc
index bdd65ef7d7a..5535a7512fb 100644
--- a/gcc/genpreds.cc
+++ b/gcc/genpreds.cc
@@ -677,6 +677,7 @@ public:
   size_t namelen;
   const char *regclass;  /* for register constraints */
   rtx exp;               /* for other constraints */
+  const char *filter;    /* the register filter condition, or null if none */
   unsigned int is_register	: 1;
   unsigned int is_const_int	: 1;
   unsigned int is_const_dbl	: 1;
@@ -763,7 +764,8 @@ mangle (const char *name)
    is the register class, if any; EXP is the expression to test, if any;
    IS_MEMORY, IS_SPECIAL_MEMORY, IS_RELAXED_MEMORY and IS_ADDRESS indicate
    memory, special memory, and address constraints, respectively; LOC is the .md
-   file location.
+   file location; FILTER is the filter condition for a register constraint,
+   or null if none.
 
    Not all combinations of arguments are valid; most importantly, REGCLASS is
    mutually exclusive with EXP, and
@@ -776,7 +778,8 @@ mangle (const char *name)
 static void
 add_constraint (const char *name, const char *regclass,
 		rtx exp, bool is_memory, bool is_special_memory,
-		bool is_relaxed_memory, bool is_address, file_location loc)
+		bool is_relaxed_memory, bool is_address, file_location loc,
+		const char *filter = nullptr)
 {
   class constraint_data *c, **iter, **slot;
   const char *p;
@@ -908,6 +911,7 @@ add_constraint (const char *name, const char *regclass,
   c->namelen = namelen;
   c->regclass = regclass;
   c->exp = exp;
+  c->filter = filter;
   c->is_register = regclass != 0;
   c->is_const_int = is_const_int;
   c->is_const_dbl = is_const_dbl;
@@ -966,7 +970,8 @@ static void
 process_define_register_constraint (md_rtx_info *info)
 {
   add_constraint (XSTR (info->def, 0), XSTR (info->def, 1),
-		  0, false, false, false, false, info->loc);
+		  0, false, false, false, false, info->loc,
+		  XSTR (info->def, 3));
 }
 
 /* Put the constraints into enum order.  We want to keep constraints
@@ -1319,6 +1324,34 @@ write_insn_const_int_ok_for_constraint (void)
 	"  return false;\n"
 	"}\n");
 }
+
+/* Print the init_reg_class_start_regs function, which initializes
+   this_target_constraints->register_filters from the C conditions
+   in the define_register_constraints.  */
+static void
+write_init_reg_class_start_regs ()
+{
+  printf ("\n"
+	  "void\n"
+	  "init_reg_class_start_regs ()\n"
+	  "{\n");
+  if (!register_filters.is_empty ())
+    {
+      printf ("  for (unsigned int regno = 0; regno < FIRST_PSEUDO_REGISTER;"
+	      " ++regno)\n"
+	      "    {\n");
+      for (unsigned int i = 0; i < register_filters.length (); ++i)
+	{
+	  printf ("      if (");
+	  rtx_reader_ptr->print_c_condition (register_filters[i]);
+	  printf (")\n"
+		  "        SET_HARD_REG_BIT (%s[%d], regno);\n",
+		  "this_target_constraints->register_filters", i);
+	}
+      printf ("    }\n");
+    }
+  printf ("}\n");
+}
 
 /* Write a definition for a function NAME that returns true if a given
    constraint_num is in the range [START, END).  */
@@ -1401,6 +1434,54 @@ print_type_tree (const vec <std::pair <unsigned int, const char *> > &vec,
   printf ("%*sreturn %s;\n", indent, "", fallback);
 }
 
+/* Print the get_register_filter function, which returns a pointer
+   to the start register filter for a given constraint, or null if none.  */
+static void
+write_get_register_filter ()
+{
+  constraint_data *c;
+
+  printf ("\n"
+	  "#ifdef GCC_HARD_REG_SET_H\n"
+	  "static inline const HARD_REG_SET *\n"
+	  "get_register_filter (constraint_num%s)\n",
+	  register_filters.is_empty () ? "" : " c");
+  printf ("{\n");
+  FOR_ALL_CONSTRAINTS (c)
+    if (c->is_register && c->filter)
+      {
+	printf ("  if (c == CONSTRAINT_%s)\n", c->c_name);
+	printf ("    return &this_target_constraints->register_filters[%d];\n",
+		get_register_filter_id (c->filter));
+      }
+  printf ("  return nullptr;\n"
+	  "}\n"
+	  "#endif\n");
+}
+
+/* Print the get_register_filter_id function, which returns the index
+   of the given constraint's register filter in
+   this_target_constraints->register_filters, or -1 if none.  */
+static void
+write_get_register_filter_id ()
+{
+  constraint_data *c;
+
+  printf ("\n"
+	  "static inline int\n"
+	  "get_register_filter_id (constraint_num%s)\n",
+	  register_filters.is_empty () ? "" : " c");
+  printf ("{\n");
+  FOR_ALL_CONSTRAINTS (c)
+    if (c->is_register && c->filter)
+      {
+	printf ("  if (c == CONSTRAINT_%s)\n", c->c_name);
+	printf ("    return %d;\n", get_register_filter_id (c->filter));
+      }
+  printf ("  return -1;\n"
+	  "}\n");
+}
+
 /* Write tm-preds.h.  Unfortunately, it is impossible to forward-declare
    an enumeration in portable C, so we have to condition all these
    prototypes on HAVE_MACHINE_MODES.  */
@@ -1425,6 +1506,53 @@ write_tm_preds_h (void)
 
   puts ("#endif /* HAVE_MACHINE_MODES */\n");
 
+  /* Print the definition of the target_constraints structure.  */
+  printf ("#ifdef GCC_HARD_REG_SET_H\n"
+	  "struct target_constraints {\n"
+	  "  HARD_REG_SET register_filters[%d];\n",
+	  MAX (register_filters.length (), 1));
+  printf ("};\n"
+	  "\n"
+	  "extern struct target_constraints default_target_constraints;\n"
+	  "#if SWITCHABLE_TARGET\n"
+	  "extern struct target_constraints *this_target_constraints;\n"
+	  "#else\n"
+	  "#define this_target_constraints (&default_target_constraints)\n"
+	  "#endif\n");
+
+  /* Print TEST_REGISTER_FILTER_BIT, which tests whether register REGNO
+     is a valid start register for register filter ID.  */
+  printf ("\n"
+	  "#define TEST_REGISTER_FILTER_BIT(ID, REGNO) \\\n");
+  if (register_filters.is_empty ())
+    printf ("  ((void) (ID), (void) (REGNO), false)\n");
+  else
+    printf ("  TEST_HARD_REG_BIT ("
+	    "this_target_constraints->register_filters[ID], REGNO)\n");
+
+  /* Print test_register_filters, which tests whether register REGNO
+     is a valid start register for the mask of register filters in MASK.  */
+  printf ("\n"
+	  "inline bool\n"
+	  "test_register_filters (unsigned int%s, unsigned int%s)\n",
+	  register_filters.is_empty () ? "" : " mask",
+	  register_filters.is_empty () ? "" : " regno");
+  printf ("{\n");
+  if (register_filters.is_empty ())
+    printf ("  return true;\n");
+  else
+    {
+      printf ("  for (unsigned int id = 0; id < %d; ++id)\n",
+	      register_filters.length ());
+      printf ("    if ((mask & (1U << id))\n"
+	      "\t&& !TEST_REGISTER_FILTER_BIT (id, regno))\n"
+	      "      return false;\n"
+	      "  return true;\n");
+    }
+  printf ("}\n"
+	  "#endif\n"
+	  "\n");
+
   if (constraint_max_namelen > 0)
     {
       write_enum_constraint_num ();
@@ -1548,6 +1676,9 @@ write_tm_preds_h (void)
 	values.safe_push (std::make_pair (address_end, "CT_FIXED_FORM"));
       print_type_tree (values, 0, values.length (), "CT_REGISTER", 2);
       puts ("}");
+
+      write_get_register_filter ();
+      write_get_register_filter_id ();
     }
 
   puts ("#endif /* tm-preds.h */");
@@ -1599,6 +1730,13 @@ write_insn_preds_c (void)
 #include \"tm-constrs.h\"\n\
 #include \"target.h\"\n");
 
+  printf ("\n"
+	  "struct target_constraints default_target_constraints;\n"
+	  "#if SWITCHABLE_TARGET\n"
+	  "struct target_constraints *this_target_constraints"
+	  " = &default_target_constraints;\n"
+	  "#endif\n");
+
   FOR_ALL_PREDICATES (p)
     write_one_predicate_function (p);
 
@@ -1613,6 +1751,8 @@ write_insn_preds_c (void)
       if (have_const_int_constraints)
 	write_insn_const_int_ok_for_constraint ();
     }
+
+  write_init_reg_class_start_regs ();
 }
 
 /* Argument parsing.  */
diff --git a/gcc/gensupport.cc b/gcc/gensupport.cc
index 688808c7d12..0ac0d0772d4 100644
--- a/gcc/gensupport.cc
+++ b/gcc/gensupport.cc
@@ -400,6 +400,45 @@ process_define_predicate (rtx desc, file_location loc)
 #undef I
 #undef N
 #undef Y
+
+/* Maps register filter conditions to the associated filter identifier.  */
+static hash_map<nofree_string_hash, unsigned int> register_filter_map;
+
+/* All register filter conditions, indexed by identifier.  */
+vec<const char *> register_filters;
+
+/* Return the unique identifier for filter condition FILTER.  Identifiers
+   are assigned automatically when the define_register_constraint is
+   parsed.  */
+
+unsigned int
+get_register_filter_id (const char *filter)
+{
+  unsigned int *slot = register_filter_map.get (filter);
+  gcc_assert (slot);
+  return *slot;
+}
+
+/* Process define_register_constraint directive DESC, at location LOC.  */
+
+static void
+process_define_register_constraint (rtx desc, file_location loc)
+{
+  /* Assign identifiers to each unique register filter condition.  */
+  if (const char *filter = XSTR (desc, 3))
+    {
+      bool existed = false;
+      unsigned int &id = register_filter_map.get_or_insert (filter, &existed);
+      if (!existed)
+	{
+	  id = register_filters.length ();
+	  if (id == 32)
+	    fatal_at (loc, "too many distinct register filters, maximum"
+		      " is 32");
+	  register_filters.safe_push (filter);
+	}
+    }
+}
 
 /* Queue PATTERN on LIST_TAIL.  Return the address of the new queue
    element.  */
@@ -1075,10 +1114,15 @@ process_rtx (rtx desc, file_location loc)
     case DEFINE_PREDICATE:
     case DEFINE_SPECIAL_PREDICATE:
       process_define_predicate (desc, loc);
-      /* Fall through.  */
+      queue_pattern (desc, &define_pred_tail, loc);
+      break;
 
-    case DEFINE_CONSTRAINT:
     case DEFINE_REGISTER_CONSTRAINT:
+      process_define_register_constraint (desc, loc);
+      queue_pattern (desc, &define_pred_tail, loc);
+      break;
+
+    case DEFINE_CONSTRAINT:
     case DEFINE_MEMORY_CONSTRAINT:
     case DEFINE_SPECIAL_MEMORY_CONSTRAINT:
     case DEFINE_RELAXED_MEMORY_CONSTRAINT:
diff --git a/gcc/gensupport.h b/gcc/gensupport.h
index 7396118714b..27e8444a745 100644
--- a/gcc/gensupport.h
+++ b/gcc/gensupport.h
@@ -108,6 +108,9 @@ struct optab_def
 extern optab_def optabs[];
 extern unsigned int num_optabs;
 
+extern vec<const char *> register_filters;
+extern unsigned int get_register_filter_id (const char *);
+
 /* Information about an instruction name that matches an optab pattern.  */
 struct optab_pattern
 {
diff --git a/gcc/reginfo.cc b/gcc/reginfo.cc
index d472a35946a..5b6e706b35d 100644
--- a/gcc/reginfo.cc
+++ b/gcc/reginfo.cc
@@ -140,6 +140,9 @@ reginfo_cc_finalize (void)
   CLEAR_HARD_REG_SET (global_reg_set);
 }
 
+/* In insn-preds.cc.  */
+extern void init_reg_class_start_regs ();
+
 /* Given a register bitmap, turn on the bits in a HARD_REG_SET that
    correspond to the hard registers, if any, set in that map.  This
    could be done far more efficiently by having all sorts of special-cases
@@ -198,6 +201,8 @@ init_reg_sets (void)
 
   SET_HARD_REG_SET (accessible_reg_set);
   SET_HARD_REG_SET (operand_reg_set);
+
+  init_reg_class_start_regs ();
 }
 
 /* We need to save copies of some of the register information which
diff --git a/gcc/rtl.def b/gcc/rtl.def
index 88e2b198503..a40e1a7bb18 100644
--- a/gcc/rtl.def
+++ b/gcc/rtl.def
@@ -1016,8 +1016,10 @@ DEF_RTL_EXPR(DEFINE_SPECIAL_PREDICATE, "define_special_predicate", "ses", RTX_EX
       at -m switches and the like.
    2: A docstring for this constraint, in Texinfo syntax; not currently
       used, in future will be incorporated into the manual's list of
-      machine-specific operand constraints.  */
-DEF_RTL_EXPR(DEFINE_REGISTER_CONSTRAINT, "define_register_constraint", "sss", RTX_EXTRA)
+      machine-specific operand constraints.
+   3: A C expression that evalutes to true if "regno" is a valid
+      start register.  */
+DEF_RTL_EXPR(DEFINE_REGISTER_CONSTRAINT, "define_register_constraint", "sssS", RTX_EXTRA)
 
 /* Definition of a non-register operand constraint.  These look at the
    operand and decide whether it fits the constraint.
diff --git a/gcc/target-globals.cc b/gcc/target-globals.cc
index 81244b127fc..cfa0045e02c 100644
--- a/gcc/target-globals.cc
+++ b/gcc/target-globals.cc
@@ -41,6 +41,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "bb-reorder.h"
 #include "lower-subreg.h"
 #include "function-abi.h"
+#include "tm_p.h"
 
 #if SWITCHABLE_TARGET
 class target_globals default_target_globals = {
@@ -60,7 +61,8 @@ class target_globals default_target_globals = {
   &default_target_builtins,
   &default_target_gcse,
   &default_target_bb_reorder,
-  &default_target_lower_subreg
+  &default_target_lower_subreg,
+  &default_target_constraints
 };
 
 class target_globals *
@@ -84,6 +86,7 @@ save_target_globals (void)
   g->gcse = XCNEW (struct target_gcse);
   g->bb_reorder = XCNEW (struct target_bb_reorder);
   g->lower_subreg = XCNEW (struct target_lower_subreg);
+  g->constraints = XCNEW (target_constraints);
   restore_target_globals (g);
   init_reg_sets ();
   target_reinit ();
@@ -141,6 +144,7 @@ target_globals::~target_globals ()
       XDELETE (gcse);
       XDELETE (bb_reorder);
       XDELETE (lower_subreg);
+      XDELETE (constraints);
     }
 }
 
diff --git a/gcc/target-globals.h b/gcc/target-globals.h
index daedf66017f..42f082c589c 100644
--- a/gcc/target-globals.h
+++ b/gcc/target-globals.h
@@ -38,6 +38,7 @@ extern struct target_builtins *this_target_builtins;
 extern struct target_gcse *this_target_gcse;
 extern struct target_bb_reorder *this_target_bb_reorder;
 extern struct target_lower_subreg *this_target_lower_subreg;
+extern struct target_constraints *this_target_constraints;
 #endif
 
 class GTY(()) target_globals {
@@ -61,6 +62,7 @@ public:
   struct target_gcse *GTY((skip)) gcse;
   struct target_bb_reorder *GTY((skip)) bb_reorder;
   struct target_lower_subreg *GTY((skip)) lower_subreg;
+  struct target_constraints *GTY((skip)) constraints;
 };
 
 #if SWITCHABLE_TARGET
@@ -89,6 +91,7 @@ restore_target_globals (class target_globals *g)
   this_target_gcse = g->gcse;
   this_target_bb_reorder = g->bb_reorder;
   this_target_lower_subreg = g->lower_subreg;
+  this_target_constraints = g->constraints;
 }
 #endif
 
