Index: target.def
===================================================================
--- target.def	(revision 190665)
+++ target.def	(working copy)
@@ -1984,7 +1984,16 @@ DEFHOOK
  const char *, (const_rtx insn),
  default_invalid_within_doloop)
 
+/* Returns true for a legitimate combined insn.  */
 DEFHOOK
+(legitimate_combined_insn,
+"Take an instruction in @var{insn} and return @code{false} if the instruction\
+ is not appropriate as a combination of two or more instructions.  The\
+ default is to accept all instructions.",
+ bool, (rtx insn),
+ hook_bool_rtx_true)
+
+DEFHOOK
 (valid_dllimport_attribute_p,
 "@var{decl} is a variable or function with @code{__attribute__((dllimport))}\
  specified.  Use this hook if the target needs to add extra validation\
Index: hooks.c
===================================================================
--- hooks.c	(revision 190665)
+++ hooks.c	(working copy)
@@ -269,6 +269,12 @@ hook_bool_tree_bool_false (tree a ATTRIBUTE_UNUSED
 }
 
 bool
+hook_bool_rtx_true (rtx a ATTRIBUTE_UNUSED)
+{
+  return true;
+}
+
+bool
 hook_bool_rtx_false (rtx a ATTRIBUTE_UNUSED)
 {
   return false;
Index: hooks.h
===================================================================
--- hooks.h	(revision 190665)
+++ hooks.h	(working copy)
@@ -50,6 +50,7 @@ extern bool hook_bool_const_tree_hwi_hwi_const_tre
 							  HOST_WIDE_INT,
 							  HOST_WIDE_INT,
 							  const_tree);
+extern bool hook_bool_rtx_true (rtx);
 extern bool hook_bool_rtx_false (rtx);
 extern bool hook_bool_rtx_int_false (rtx, int);
 extern bool hook_bool_uintp_uintp_false (unsigned int *, unsigned int *);
Index: doc/tm.texi
===================================================================
--- doc/tm.texi	(revision 190665)
+++ doc/tm.texi	(working copy)
@@ -10938,6 +10938,10 @@ By default, the RTL loop optimizer does not use a
 loops containing function calls or branch on table instructions.
 @end deftypefn
 
+@deftypefn {Target Hook} bool TARGET_LEGITIMATE_COMBINED_INSN (rtx @var{insn})
+Take an instruction in @var{insn} and return @code{false} if the instruction is not appropriate as a combination of two or more instructions.  The default is to accept all instructions.
+@end deftypefn
+
 @defmac MD_CAN_REDIRECT_BRANCH (@var{branch1}, @var{branch2})
 
 Take a branch insn in @var{branch1} and another in @var{branch2}.
Index: doc/tm.texi.in
===================================================================
--- doc/tm.texi.in	(revision 190665)
+++ doc/tm.texi.in	(working copy)
@@ -10796,6 +10796,8 @@ By default, the RTL loop optimizer does not use a
 loops containing function calls or branch on table instructions.
 @end deftypefn
 
+@hook TARGET_LEGITIMATE_COMBINED_INSN
+
 @defmac MD_CAN_REDIRECT_BRANCH (@var{branch1}, @var{branch2})
 
 Take a branch insn in @var{branch1} and another in @var{branch2}.
Index: combine.c
===================================================================
--- combine.c	(revision 190665)
+++ combine.c	(working copy)
@@ -10500,11 +10500,13 @@ static int
 recog_for_combine (rtx *pnewpat, rtx insn, rtx *pnotes)
 {
   rtx pat = *pnewpat;
+  rtx pat_without_clobbers;
   int insn_code_number;
   int num_clobbers_to_add = 0;
   int i;
-  rtx notes = 0;
+  rtx notes = NULL_RTX;
   rtx old_notes, old_pat;
+  int old_icode;
 
   /* If PAT is a PARALLEL, check to see if it contains the CLOBBER
      we use to indicate that something didn't match.  If we find such a
@@ -10518,7 +10520,7 @@ recog_for_combine (rtx *pnewpat, rtx insn, rtx *pn
   old_pat = PATTERN (insn);
   old_notes = REG_NOTES (insn);
   PATTERN (insn) = pat;
-  REG_NOTES (insn) = 0;
+  REG_NOTES (insn) = NULL_RTX;
 
   insn_code_number = recog (pat, insn, &num_clobbers_to_add);
   if (dump_file && (dump_flags & TDF_DETAILS))
@@ -10564,6 +10566,9 @@ recog_for_combine (rtx *pnewpat, rtx insn, rtx *pn
 	  print_rtl_single (dump_file, pat);
 	}
     }
+
+  pat_without_clobbers = pat;
+
   PATTERN (insn) = old_pat;
   REG_NOTES (insn) = old_notes;
 
@@ -10605,6 +10610,35 @@ recog_for_combine (rtx *pnewpat, rtx insn, rtx *pn
       pat = newpat;
     }
 
+  if (insn_code_number >= 0
+      && insn_code_number != NOOP_MOVE_INSN_CODE)
+    {
+      old_pat = PATTERN (insn);
+      old_notes = REG_NOTES (insn);
+      old_icode = INSN_CODE (insn);
+      PATTERN (insn) = pat;
+      REG_NOTES (insn) = notes;
+
+      /* Allow targets to reject combined insn.  */
+      if (!targetm.legitimate_combined_insn (insn))
+	{
+	  if (dump_file && (dump_flags & TDF_DETAILS))
+	    fputs ("Instruction not appropriate for target.",
+		   dump_file);
+
+	  /* Callers expect recog_for_combine to strip
+	     clobbers from the pattern on failure.  */
+	  pat = pat_without_clobbers;
+	  notes = NULL_RTX;
+
+	  insn_code_number = -1;
+	}
+
+      PATTERN (insn) = old_pat;
+      REG_NOTES (insn) = old_notes;
+      INSN_CODE (insn) = old_icode;
+    }
+
   *pnewpat = pat;
   *pnotes = notes;
 
