diff --git a/gcc/ira-build.cc b/gcc/ira-build.cc
index 93e46033170..c715a834f12 100644
--- a/gcc/ira-build.cc
+++ b/gcc/ira-build.cc
@@ -498,6 +498,7 @@ ira_create_allocno (int regno, bool cap_p,
   ALLOCNO_NREFS (a) = 0;
   ALLOCNO_FREQ (a) = 0;
   ALLOCNO_MIGHT_CONFLICT_WITH_PARENT_P (a) = false;
+  ALLOCNO_SET_REGISTER_FILTERS (a, 0);
   ALLOCNO_HARD_REGNO (a) = -1;
   ALLOCNO_CALL_FREQ (a) = 0;
   ALLOCNO_CALLS_CROSSED_NUM (a) = 0;
@@ -902,6 +903,7 @@ create_cap_allocno (ira_allocno_t a)
   ALLOCNO_NREFS (cap) = ALLOCNO_NREFS (a);
   ALLOCNO_FREQ (cap) = ALLOCNO_FREQ (a);
   ALLOCNO_CALL_FREQ (cap) = ALLOCNO_CALL_FREQ (a);
+  ALLOCNO_SET_REGISTER_FILTERS (cap, ALLOCNO_REGISTER_FILTERS (a));
 
   merge_hard_reg_conflicts (a, cap, false);
 
@@ -2064,6 +2066,9 @@ propagate_allocno_info (void)
 	    ALLOCNO_BAD_SPILL_P (parent_a) = false;
 	  ALLOCNO_NREFS (parent_a) += ALLOCNO_NREFS (a);
 	  ALLOCNO_FREQ (parent_a) += ALLOCNO_FREQ (a);
+	  ALLOCNO_SET_REGISTER_FILTERS (parent_a,
+					ALLOCNO_REGISTER_FILTERS (parent_a)
+					| ALLOCNO_REGISTER_FILTERS (a));
 
 	  /* If A's allocation can differ from PARENT_A's, we can if necessary
 	     spill PARENT_A on entry to A's loop and restore it afterwards.
@@ -2465,6 +2470,9 @@ propagate_some_info_from_allocno (ira_allocno_t a, ira_allocno_t from_a)
   ALLOCNO_CROSSED_CALLS_ABIS (a) |= ALLOCNO_CROSSED_CALLS_ABIS (from_a);
   ALLOCNO_CROSSED_CALLS_CLOBBERED_REGS (a)
     |= ALLOCNO_CROSSED_CALLS_CLOBBERED_REGS (from_a);
+  ALLOCNO_SET_REGISTER_FILTERS (a,
+				ALLOCNO_REGISTER_FILTERS (from_a)
+				| ALLOCNO_REGISTER_FILTERS (a));
 
   ALLOCNO_EXCESS_PRESSURE_POINTS_NUM (a)
     += ALLOCNO_EXCESS_PRESSURE_POINTS_NUM (from_a);
diff --git a/gcc/ira-color.cc b/gcc/ira-color.cc
index f2e8ea34152..214a4f16d3c 100644
--- a/gcc/ira-color.cc
+++ b/gcc/ira-color.cc
@@ -2163,6 +2163,9 @@ assign_hard_reg (ira_allocno_t a, bool retry_p)
       if (! check_hard_reg_p (a, hard_regno,
 			      conflicting_regs, profitable_hard_regs))
 	continue;
+      if (NUM_REGISTER_FILTERS
+	  && !test_register_filters (ALLOCNO_REGISTER_FILTERS (a), hard_regno))
+	continue;
       cost = costs[i];
       full_cost = full_costs[i];
       if (!HONOR_REG_ALLOC_ORDER)
@@ -3205,6 +3208,9 @@ improve_allocation (void)
 	  if (! check_hard_reg_p (a, hregno,
 				  conflicting_regs, profitable_hard_regs))
 	    continue;
+	  if (NUM_REGISTER_FILTERS
+	      && !test_register_filters (ALLOCNO_REGISTER_FILTERS (a), hregno))
+	    continue;
 	  ira_assert (ira_class_hard_reg_index[aclass][hregno] == j);
 	  k = allocno_costs == NULL ? 0 : j;
 	  costs[hregno] = (allocno_costs == NULL
@@ -5275,6 +5281,10 @@ fast_allocation (void)
 	      || (TEST_HARD_REG_BIT
 		  (ira_prohibited_class_mode_regs[aclass][mode], hard_regno)))
 	    continue;
+	  if (NUM_REGISTER_FILTERS
+	      && !test_register_filters (ALLOCNO_REGISTER_FILTERS (a),
+					 hard_regno))
+	    continue;
 	  if (costs == NULL)
 	    {
 	      best_hard_regno = hard_regno;
diff --git a/gcc/ira-int.h b/gcc/ira-int.h
index 0685e1f4e8d..1c3548df4ea 100644
--- a/gcc/ira-int.h
+++ b/gcc/ira-int.h
@@ -328,6 +328,13 @@ struct ira_allocno
 
      This is only ever true for non-cap allocnos.  */
   unsigned int might_conflict_with_parent_p : 1;
+#ifndef NUM_REGISTER_FILTERS
+#error "insn-config.h not included"
+#elif NUM_REGISTER_FILTERS
+  /* The set of register filters applied to the allocno by operand
+     alternatives that accept class ACLASS.  */
+  unsigned int register_filters : NUM_REGISTER_FILTERS;
+#endif
   /* Accumulated usage references of the allocno.  Here and below,
      word 'accumulated' means info for given region and all nested
      subregions.  In this case, 'accumulated' means sum of references
@@ -432,6 +439,13 @@ struct ira_allocno
 #define ALLOCNO_FREQ(A) ((A)->freq)
 #define ALLOCNO_MIGHT_CONFLICT_WITH_PARENT_P(A) \
   ((A)->might_conflict_with_parent_p)
+#if NUM_REGISTER_FILTERS
+#define ALLOCNO_REGISTER_FILTERS(A) (A)->register_filters
+#define ALLOCNO_SET_REGISTER_FILTERS(A, X) ((A)->register_filters = (X))
+#else
+#define ALLOCNO_REGISTER_FILTERS(A) 0
+#define ALLOCNO_SET_REGISTER_FILTERS(A, X) ((void) (A), gcc_assert ((X) == 0))
+#endif
 #define ALLOCNO_HARD_REGNO(A) ((A)->hard_regno)
 #define ALLOCNO_CALL_FREQ(A) ((A)->call_freq)
 #define ALLOCNO_CALLS_CROSSED_NUM(A) ((A)->calls_crossed_num)
diff --git a/gcc/ira-lives.cc b/gcc/ira-lives.cc
index 81af5c06460..63f2314409f 100644
--- a/gcc/ira-lives.cc
+++ b/gcc/ira-lives.cc
@@ -1066,6 +1066,66 @@ process_single_reg_class_operands (bool in_p, int freq)
     }
 }
 
+/* Go through the operands of the extracted insn looking for operand
+   alternatives that apply a register filter.  Record any such filters
+   in the operand's allocno.  */
+static void
+process_register_constraint_filters ()
+{
+  for (int opno = 0; opno < recog_data.n_operands; ++opno)
+    {
+      rtx op = recog_data.operand[opno];
+      if (SUBREG_P (op))
+	op = SUBREG_REG (op);
+      if (REG_P (op) && !HARD_REGISTER_P (op))
+	{
+	  ira_allocno_t a = ira_curr_regno_allocno_map[REGNO (op)];
+	  for (int alt = 0; alt < recog_data.n_alternatives; alt++)
+	    {
+	      if (!TEST_BIT (preferred_alternatives, alt))
+		continue;
+
+	      auto *op_alt = &recog_op_alt[alt * recog_data.n_operands];
+	      auto cl = alternative_class (op_alt, opno);
+	      /* The two extremes are easy:
+
+		 - We should record the filter if CL matches the
+		   allocno class.
+
+		 - We should ignore the filter if CL and the allocno class
+		   are disjoint.  We'll either pick a different alternative
+		   or reload the operand.
+
+		 Things are trickier if the classes overlap.  However:
+
+		 - If the allocno class includes registers that are not
+		   in CL, some choices of hard register will need a reload
+		   anyway.  It isn't obvious that reloads due to filters
+		   are worse than reloads due to regnos being outside CL.
+
+		 - Conversely, if the allocno class is a subset of CL,
+		   any allocation will satisfy the class requirement.
+		   We should try to make sure it satisfies the filter
+		   requirement too.  This is useful if, for example,
+		   an allocno needs to be in "low" registers to satisfy
+		   some uses, and its allocno class is therefore those
+		   low registers, but the allocno is elsewhere allowed
+		   to be in any even-numbered register.  Picking an
+		   even-numbered low register satisfies both types of use.  */
+	      if (!ira_class_subset_p[ALLOCNO_CLASS (a)][cl])
+		continue;
+
+	      auto filters = alternative_register_filters (op_alt, opno);
+	      if (!filters)
+		continue;
+
+	      filters |= ALLOCNO_REGISTER_FILTERS (a);
+	      ALLOCNO_SET_REGISTER_FILTERS (a, filters);
+	    }
+	}
+    }
+}
+
 /* Look through the CALL_INSN_FUNCTION_USAGE of a call insn INSN, and see if
    we find a SET rtx that we can use to deduce that a register can be cheaply
    caller-saved.  Return such a register, or NULL_RTX if none is found.  */
@@ -1378,6 +1438,7 @@ process_bb_node_lives (ira_loop_tree_node_t loop_tree_node)
 	      }
 
 	  preferred_alternatives = ira_setup_alts (insn);
+	  process_register_constraint_filters ();
 	  process_single_reg_class_operands (false, freq);
 
 	  if (call_p)
