diff --git a/gcc/config/rx/predicates.md b/gcc/config/rx/predicates.md
index 0ab4df3..5ae5d22 100644
--- a/gcc/config/rx/predicates.md
+++ b/gcc/config/rx/predicates.md
@@ -310,3 +310,7 @@
 (define_predicate "rx_fp_comparison_operator"
   (match_code "eq,ne,lt,ge,ordered,unordered,uneq,unlt,unge,ltgt")
 )
+
+(define_predicate "rshift_operator"
+  (match_code "ashiftrt,lshiftrt")
+)
diff --git a/gcc/config/rx/rx-protos.h b/gcc/config/rx/rx-protos.h
index 9bb76b2..3c3f2d4 100644
--- a/gcc/config/rx/rx-protos.h
+++ b/gcc/config/rx/rx-protos.h
@@ -33,7 +33,6 @@ extern int		rx_initial_elimination_offset (int, int);
 extern void             rx_emit_stack_popm (rtx *, bool);
 extern void             rx_emit_stack_pushm (rtx *);
 extern void		rx_expand_epilogue (bool);
-extern bool		rx_expand_insv (rtx *);
 extern char *		rx_gen_move_template (rtx *, bool);
 extern bool		rx_is_legitimate_constant (rtx);
 extern bool 		rx_is_mode_dependent_addr (rtx);
diff --git a/gcc/config/rx/rx.c b/gcc/config/rx/rx.c
index 16646ae..8cc46e7 100644
--- a/gcc/config/rx/rx.c
+++ b/gcc/config/rx/rx.c
@@ -2339,48 +2339,6 @@ rx_is_ms_bitfield_layout (const_tree record_type ATTRIBUTE_UNUSED)
   /* The packed attribute overrides the MS behaviour.  */
   return ! TYPE_PACKED (record_type);
 }
-
-/* Try to generate code for the "isnv" pattern which inserts bits
-   into a word.
-     operands[0] => Location to be altered.
-     operands[1] => Number of bits to change.
-     operands[2] => Starting bit.
-     operands[3] => Value to insert.
-   Returns TRUE if successful, FALSE otherwise.  */
-
-bool
-rx_expand_insv (rtx * operands)
-{
-  if (INTVAL (operands[1]) != 1
-      || ! CONST_INT_P (operands[3]))
-    return false;
-
-  if (MEM_P (operands[0])
-      && INTVAL (operands[2]) > 7)
-    return false;
-
-  switch (INTVAL (operands[3]))
-    {
-    case 0:
-      if (MEM_P (operands[0]))
-	emit_insn (gen_bitclr_in_memory (operands[0], operands[0],
-					 operands[2]));
-      else
-	emit_insn (gen_bitclr (operands[0], operands[0], operands[2]));
-      break;
-    case 1:
-    case -1:
-      if (MEM_P (operands[0]))
-	emit_insn (gen_bitset_in_memory (operands[0], operands[0],
-					 operands[2]));
-      else
-	emit_insn (gen_bitset (operands[0], operands[0], operands[2]));
-      break;
-   default:
-      return false;
-    }
-  return true;
-}
 
 /* Returns true if X a legitimate constant for an immediate
    operand on the RX.  X is already known to satisfy CONSTANT_P.  */
diff --git a/gcc/config/rx/rx.md b/gcc/config/rx/rx.md
index 864b4a5..7fa8668 100644
--- a/gcc/config/rx/rx.md
+++ b/gcc/config/rx/rx.md
@@ -1518,91 +1518,208 @@
 )
 
 ;; Bit manipulation instructions.
-;; Note - there are two versions of each pattern because the memory
-;; accessing versions use QImode whilst the register accessing
-;; versions use SImode.
-;; The peephole are here because the combiner only looks at a maximum
-;; of three instructions at a time.
 
-(define_insn "bitset"
+;; ??? The *_in_memory patterns will not be matched without further help.
+;; At one time we had the insv expander generate them, but I suspect that
+;; in general we get better performance by exposing the register load to
+;; the optimizers.
+;;
+;; An alternate solution would be to re-organize these patterns such
+;; that allow both register and memory operands.  This would allow the
+;; register allocator to spill and not load the register operand.  This
+;; would be possible only for operations for which we have a constant
+;; bit offset, so that we can adjust the address by ofs/8 and replace
+;; the offset in the insn by ofs%8.
+
+(define_insn "*bitset"
   [(set (match_operand:SI                    0 "register_operand" "=r")
-	(ior:SI (match_operand:SI            1 "register_operand" "0")
-		(ashift:SI (const_int 1)
-			   (match_operand:SI 2 "nonmemory_operand" "ri"))))]
+	(ior:SI (ashift:SI (const_int 1)
+			   (match_operand:SI 1 "rx_shift_operand" "ri"))
+		(match_operand:SI            2 "register_operand" "0")))]
   ""
-  "bset\t%2, %0"
+  "bset\t%1, %0"
   [(set_attr "length" "3")]
 )
 
-(define_insn "bitset_in_memory"
-  [(set (match_operand:QI                    0 "memory_operand" "=m")
-	(ior:QI (match_operand:QI            1 "memory_operand" "0")
-		(ashift:QI (const_int 1)
-			   (match_operand:QI 2 "nonmemory_operand" "ri"))))]
+(define_insn "*bitset_in_memory"
+  [(set (match_operand:QI                    0 "memory_operand" "+Q")
+	(ior:QI (ashift:QI (const_int 1)
+			   (match_operand:QI 1 "nonmemory_operand" "ri"))
+		(match_dup 0)))]
   ""
-  "bset\t%2, %0.B"
+  "bset\t%1, %0.B"
   [(set_attr "length" "3")
    (set_attr "timings" "34")]
 )
 
 (define_insn "*bitinvert"
   [(set (match_operand:SI 0 "register_operand" "=r")
-	(xor:SI (match_operand:SI 1 "register_operand" "0")
-		(ashift:SI (const_int 1)
-			   (match_operand:SI 2 "nonmemory_operand" "ri"))))]
+	(xor:SI (ashift:SI (const_int 1)
+			   (match_operand:SI 1 "rx_shift_operand" "ri"))
+		(match_operand:SI 2 "register_operand" "0")))]
   ""
-  "bnot\t%2, %0"
+  "bnot\t%1, %0"
   [(set_attr "length" "3")]
 )
 
-(define_insn "bitinvert_in_memory"
-  [(set (match_operand:QI 0 "memory_operand" "+m")
-	(xor:QI (match_operand:QI 1 "register_operand" "0")
-		(ashift:QI (const_int 1)
-			   (match_operand:QI 2 "nonmemory_operand" "ri"))))]
+(define_insn "*bitinvert_in_memory"
+  [(set (match_operand:QI 0 "memory_operand" "+Q")
+	(xor:QI (ashift:QI (const_int 1)
+			   (match_operand:QI 1 "nonmemory_operand" "ri"))
+		(match_dup 0)))]
   ""
-  "bnot\t%2, %0.B"
+  "bnot\t%1, %0.B"
   [(set_attr "length" "5")
    (set_attr "timings" "33")]
 )
 
-(define_insn "bitclr"
+(define_insn "*bitclr"
   [(set (match_operand:SI 0 "register_operand" "=r")
-	(and:SI (match_operand:SI 1 "register_operand" "0")
-		(not:SI
+	(and:SI (not:SI
 		  (ashift:SI
 		    (const_int 1)
-		    (match_operand:SI 2 "nonmemory_operand" "ri")))))]
+		    (match_operand:SI 1 "rx_shift_operand" "ri")))
+		(match_operand:SI 2 "register_operand" "0")))]
   ""
-  "bclr\t%2, %0"
+  "bclr\t%1, %0"
   [(set_attr "length" "3")]
 )
 
-(define_insn "bitclr_in_memory"
-  [(set (match_operand:QI 0 "memory_operand" "=m")
-	(and:QI (match_operand:QI 1 "memory_operand" "0")
-		(not:QI
+(define_insn "*bitclr_in_memory"
+  [(set (match_operand:QI 0 "memory_operand" "+Q")
+	(and:QI (not:QI
 		  (ashift:QI
 		    (const_int 1)
-		    (match_operand:QI 2 "nonmemory_operand" "ri")))))]
+		    (match_operand:QI 1 "nonmemory_operand" "ri")))
+		(match_dup 0)))]
   ""
-  "bclr\t%2, %0.B"
+  "bclr\t%1, %0.B"
   [(set_attr "length" "3")
    (set_attr "timings" "34")]
 )
 
+(define_insn "*insv_imm"
+  [(set (zero_extract:SI
+	  (match_operand:SI 0 "register_operand" "+r")
+	  (const_int 1)
+	  (match_operand:SI 1 "rx_shift_operand" "ri"))
+	(match_operand:SI 2 "const_int_operand" ""))]
+  ""
+{
+  if (INTVAL (operands[2]) & 1)
+    return "bset\t%1, %0";
+  else
+    return "bclr\t%1, %0";
+}
+  [(set_attr "length" "3")]
+)
+
+(define_insn_and_split "rx_insv_reg"
+  [(set (zero_extract:SI
+	  (match_operand:SI 0 "register_operand" "+r")
+	  (const_int 1)
+	  (match_operand:SI 1 "const_int_operand" ""))
+	(match_operand:SI 2 "register_operand" "r"))
+   (clobber (reg:CC CC_REG))]
+  ""
+  "#"
+  "reload_completed"
+  [(set (zero_extract:SI (match_dup 0) (const_int 1) (match_dup 1))
+	(match_dup 3))]
+{
+  rtx flags, x;
+
+  /* Emit tst #1, op2.  */
+  flags = gen_rtx_REG (CC_ZSmode, CC_REG);
+  x = gen_rtx_AND (SImode, operands[2], const1_rtx);
+  x = gen_rtx_COMPARE (CC_ZSmode, x, const0_rtx);
+  x = gen_rtx_SET (VOIDmode, flags, x);
+  emit_insn (x);
+
+  /* Emit bmne.  */
+  operands[3] = gen_rtx_NE (SImode, flags, const0_rtx);
+})
+
+(define_insn_and_split "*insv_cond"
+  [(set (zero_extract:SI
+	  (match_operand:SI 0 "register_operand" "+r")
+	  (const_int 1)
+	  (match_operand:SI 1 "const_int_operand" ""))
+	(match_operator:SI 4 "comparison_operator"
+	  [(match_operand:SI 2 "register_operand" "r")
+	   (match_operand:SI 3 "rx_source_operand" "riQ")]))
+   (clobber (reg:CC CC_REG))]
+  ""
+  "#"
+  "reload_completed"
+  [(set (zero_extract:SI (match_dup 0) (const_int 1) (match_dup 1))
+	(match_dup 4))]
+{
+  rtx flags, x;
+
+  flags = gen_rtx_REG (CCmode, CC_REG);
+  x = gen_rtx_COMPARE (CCmode, operands[2], operands[3]);
+  x = gen_rtx_SET (VOIDmode, flags, x);
+  emit_insn (x);
+
+  operands[4] = gen_rtx_fmt_ee (GET_CODE (operands[4]), SImode,
+			        flags, const0_rtx);
+})
+
+(define_insn "*bmcc"
+  [(set (zero_extract:SI
+	  (match_operand:SI 0 "register_operand" "+r")
+	  (const_int 1)
+	  (match_operand:SI 1 "const_int_operand" ""))
+	(match_operator:SI 2 "comparison_operator"
+	  [(reg CC_REG) (const_int 0)]))]
+  "reload_completed"
+  "bm%B2\t%1, %0"
+  [(set_attr "length" "3")]
+)
+
+;; Work around the fact that X=Y<0 is preferentially expanded as a shift.
+(define_insn_and_split "*insv_cond_lt"
+  [(set (zero_extract:SI
+	  (match_operand:SI 0 "register_operand" "+r")
+	  (const_int 1)
+	  (match_operand:SI 1 "const_int_operand" ""))
+	(match_operator:SI 3 "rshift_operator"
+	  [(match_operand:SI 2 "register_operand" "r")
+	   (const_int 31)]))
+   (clobber (reg:CC CC_REG))]
+  ""
+  "#"
+  ""
+  [(parallel [(set (zero_extract:SI (match_dup 0) (const_int 1) (match_dup 1))
+		   (lt:SI (match_dup 2) (const_int 0)))
+	      (clobber (reg:CC CC_REG))])]
+  ""
+)
+
 (define_expand "insv"
-  [(set (zero_extract:SI (match_operand:SI 0 "nonimmediate_operand") ;; Destination
-		         (match_operand    1 "immediate_operand")    ;; # of bits to set
-			 (match_operand    2 "immediate_operand"))   ;; Starting bit
-	(match_operand	              3 "immediate_operand"))]       ;; Bits to insert
+  [(set (zero_extract:SI
+	  (match_operand:SI 0 "register_operand")	;; Destination
+	  (match_operand:SI 1 "const_int_operand")	;; # of bits to set
+	  (match_operand:SI 2 "nonmemory_operand"))	;; Starting bit
+	(match_operand:SI   3 "nonmemory_operand"))]	;; Bits to insert
   ""
-  {
-    if (rx_expand_insv (operands))
+{
+  /* We only handle single-bit inserts.  */
+  if (!CONST_INT_P (operands[1]) || INTVAL (operands[1]) != 1)
+    FAIL;
+
+  /* Either the bit to insert or the position must be constant.  */
+  if (CONST_INT_P (operands[3]))
+    operands[3] = GEN_INT (INTVAL (operands[3]) & 1);
+  else if (CONST_INT_P (operands[2]))
+    {
+      emit_insn (gen_rx_insv_reg (operands[0], operands[2], operands[3]));
       DONE;
+    }
+  else
     FAIL;
-  }
-)
+})
 
 ;; Atomic exchange operation.
 
