diff mbox

[SH,committed] Fix PR 64659

Message ID 1422480001.5268.36.camel@yam-132-YW-E178-FTW
State New
Headers show

Commit Message

Oleg Endo Jan. 28, 2015, 9:20 p.m. UTC
Hi,

Attached patch allows the atomic ops on SH to utilize some of the
immediate value insns, which can save an insn and reg sometimes.  The
actual changes are in the predicates, constraints and some adjustments
to some of the asm snippets.  While at it, I've changed uses of
register_operand into arith_reg_dest and arith_reg_operand respectively.

Committed as r220217.  Tested with
make -k check-gcc RUNTESTFLAGS="sh.exp=pr64659* --target_board=sh-sim
\{-m2/-ml,-m2/-mb,-m2a/-mb,-m2e/-ml,-m2e/-mb,-m3/-ml,-m3/-mb,-m3e/-ml,-m3e/-mb,-m4/-ml,-m4/-mb,-m4a/-ml,-m4a/-mb}"
to verify that the insns actually work.  Will observe daily sh4-linux
test results for fallouts.

Cheers,
Oleg

gcc/ChangeLog:
	PR target/64659
	* config/sh/predicates.md (atomic_arith_operand,
	atomic_logical_operand): Remove.
	* config/sh/sync.md (fetchop_predicate, fetchop_constraint): Remove.
	(atomic_arith_operand_0): New predicate.
	(atomic_compare_and_swap<mode>): Use arith_reg_dest for output values.
	Use atomic_arith_operand_0 for input values.
	(atomic_compare_and_swapsi_hard, atomic_compare_and_swap<mode>_hard,
	atomic_compare_and_swap<mode>_soft_gusa,
	atomic_compare_and_swap<mode>_soft_tcb,
	atomic_compare_and_swap<mode>_soft_imask): Use arith_reg_dest and
	arith_reg_operand instead of register_operand.
	(atomic_exchange<mode>): Use arith_reg_dest for output value.  Use
	atomic_arith_operand_0 for newval input.
	(atomic_exchangesi_hard, atomic_exchange<mode>_hard,
	atomic_exchange<mode>_soft_gusa, atomic_exchange<mode>_soft_tcb,
	atomic_exchange<mode>_soft_imask): Use arith_reg_dest and
	arith_reg_operand instead of register_operand.
	(atomic_arith_operand_1, atomic_logical_operand_1): New predicates.
	fetchop_predicate_1, fetchop_constraint_1_llcs,
	fetchop_constraint_1_gusa, fetchop_constraint_1_tcb,
	fetchop_constraint_1_imask): New code iterator attributes.
	(atomic_fetch_<fetchop_name><mode>): Use arith_reg_dest instead of
	register_operand.  Use fetchop_predicate_1.
	(atomic_fetch_<fetchop_name>si_hard,
	atomic_fetch_<fetchop_name><mode>_hard): Use arith_reg_dest instead of
	register_operand.  Use fetchop_predicate_1, fetchop_constraint_1_llcs.
	(atomic_fetch_<fetchop_name><mode>_soft_gusa): Use arith_reg_dest
	and arith_reg_operand instead of register_operand.  Use
	fetchop_predicate_1, fetchop_constraint_1_gusa.
	(atomic_fetch_<fetchop_name><mode>_soft_tcb): Use arith_reg_dest
	and arith_reg_operand instead of register_operand.  Use
	fetchop_predicate_1, fetchop_constraint_1_tcb.  Adjust asm sequence
	to allow R0 usage.
	(atomic_fetch_<fetchop_name><mode>_soft_imask): Use arith_reg_dest
	and arith_reg_operand instead of register_operand.  Use
	fetchop_predicate_1, fetchop_constraint_1_imask.  Adjust asm sequence
	to allow R0 usage.
	(atomic_fetch_nand<mode>): Use arith_reg_dest instead of
	register_operand.  Use atomic_logical_operand_1.
	(atomic_fetch_nandsi_hard, atomic_fetch_nand<mode>_hard,
	atomic_fetch_nand<mode>_soft_gusa): Use arith_reg_dest and
	arith_reg_operand instead of register_operand.
	(atomic_fetch_nand<mode>_soft_tcb, atomic_fetch_nand<mode>_soft_imask):
	Use arith_reg_dest and arith_reg_operand instead of register_operand.
	Use logical_operand and rK08.  Adjust asm sequence to allow R0 usage.
	(atomic_<fetchop_name>_fetch<mode>): Use arith_reg_dest instead of
	register_operand.  Use fetchop_predicate_1.
	(atomic_<fetchop_name>_fetchsi_hard,
	atomic_<fetchop_name>_fetch<mode>_hard): Use arith_reg_dest and
	arith_reg_operand instead of register_operand.  Use fetchop_predicate_1,
	fetchop_constraint_1_llcs.
	(atomic_<fetchop_name>_fetch<mode>_soft_gusa): Use arith_reg_dest and
	arith_reg_operand instead of register_operand.  Use fetchop_predicate_1,
	fetchop_constraint_1_gusa.
	(atomic_<fetchop_name>_fetch<mode>_soft_tcb): Use arith_reg_dest and
	arith_reg_operand instead of register_operand.  Use fetchop_predicate_1,
	fetchop_constraint_1_tcb.  Adjust asm sequence to allow R0 usage.
	(atomic_<fetchop_name>_fetch<mode>_soft_imask): Use arith_reg_dest and
	arith_reg_operand instead of register_operand.  Use fetchop_predicate_1,
	fetchop_constraint_1_imask.  Adjust asm sequence to allow R0 usage.
	(atomic_nand_fetch<mode>): Use arith_reg_dest instead of
	register_operand.  Use atomic_logical_operand_1.
	(atomic_nand_fetchsi_hard, atomic_nand_fetch<mode>_hard,
	atomic_nand_fetch<mode>_soft_gusa): Use arith_reg_dest and
	arith_reg_operand instead of register_operand.
	(atomic_nand_fetch<mode>_soft_tcb): Use arith_reg_dest and
	arith_reg_operand instead of register_operand.  Use logical_operand
	and K08.  Adjust asm sequence to allow R0 usage.
	(atomic_nand_fetch<mode>_soft_imask): Use arith_reg_dest and
	arith_reg_operand instead of register_operand.  Use logical_operand
	and K08.

gcc/testsuite/ChangeLog:
	PR target/64659
	* gcc.target/sh/sh.exp
	(check_effective_target_atomic_model_soft_gusa_available,
	check_effective_target_atomic_model_soft_tcb_available,
	check_effective_target_atomic_model_soft_imask_available,
	check_effective_target_atomic_model_hard_llcs_available): New.
	* gcc.target/sh/pr64659-0.h: New.
	* gcc.target/sh/pr64659-1.c: New.
	* gcc.target/sh/pr64659-2.c: New.
	* gcc.target/sh/pr64659-3.c: New.
	* gcc.target/sh/pr64659-4.c: New.
diff mbox

Patch

Index: gcc/testsuite/gcc.target/sh/pr64659-2.c
===================================================================
--- gcc/testsuite/gcc.target/sh/pr64659-2.c	(revision 0)
+++ gcc/testsuite/gcc.target/sh/pr64659-2.c	(revision 0)
@@ -0,0 +1,10 @@ 
+/* Check that atomic ops utilize insns with immediate values.  */
+/* { dg-do compile { target { atomic_model_soft_tcb_available } } }  */
+/* { dg-options "-O2 -matomic-model=soft-tcb,gbr-offset=0,strict" }  */
+/* { dg-final { scan-assembler-times "add\t#1" 6 } }  */
+/* { dg-final { scan-assembler-times "add\t#-1" 6 } }  */
+/* { dg-final { scan-assembler-times "and\t#1" 12 } }  */
+/* { dg-final { scan-assembler-times "\tor\t#1" 6 } }  */
+/* { dg-final { scan-assembler-times "xor\t#1" 6 } }  */
+
+#include "pr64659-0.h"
Index: gcc/testsuite/gcc.target/sh/pr64659-3.c
===================================================================
--- gcc/testsuite/gcc.target/sh/pr64659-3.c	(revision 0)
+++ gcc/testsuite/gcc.target/sh/pr64659-3.c	(revision 0)
@@ -0,0 +1,10 @@ 
+/* Check that atomic ops utilize insns with immediate values.  */
+/* { dg-do compile { target { atomic_model_soft_imask_available } } }  */
+/* { dg-options "-O2 -matomic-model=soft-imask,strict -mno-usermode" }  */
+/* { dg-final { scan-assembler-times "add\t#1" 6 } }  */
+/* { dg-final { scan-assembler-times "add\t#-1" 6 } }  */
+/* { dg-final { scan-assembler-times "and\t#1" 12 } }  */
+/* { dg-final { scan-assembler-times "\tor\t#1" 6 } }  */
+/* { dg-final { scan-assembler-times "xor\t#1" 6 } }  */
+
+#include "pr64659-0.h"
Index: gcc/testsuite/gcc.target/sh/pr64659-4.c
===================================================================
--- gcc/testsuite/gcc.target/sh/pr64659-4.c	(revision 0)
+++ gcc/testsuite/gcc.target/sh/pr64659-4.c	(revision 0)
@@ -0,0 +1,11 @@ 
+/* Check that atomic ops utilize insns with immediate values.  */
+/* { dg-do compile { target { atomic_model_hard_llcs_available } } }  */
+/* { dg-options "-O2 -matomic-model=hard-llcs,strict" }  */
+/* { dg-final { scan-assembler-times "add\t#1" 6 } }  */
+/* { dg-final { scan-assembler-times "add\t#-1" 6 } }  */
+/* { dg-final { scan-assembler-times "and\t#1" 12 } }  */
+/* { dg-final { scan-assembler-times "\tor\t#1" 6 } }  */
+/* { dg-final { scan-assembler-times "xor\t#1" 6 } }  */
+/* { dg-final { scan-assembler-times "cmp/eq\t#1" 1 } }  */
+
+#include "pr64659-0.h"
Index: gcc/testsuite/gcc.target/sh/pr64659-0.h
===================================================================
--- gcc/testsuite/gcc.target/sh/pr64659-0.h	(revision 0)
+++ gcc/testsuite/gcc.target/sh/pr64659-0.h	(revision 0)
@@ -0,0 +1,60 @@ 
+/* Check that atomic ops utilize insns with immediate values.  */
+
+#define emitfuncs(name)\
+  void test_ ## name ## _0 (char* mem)\
+  {\
+    name (mem, 1, __ATOMIC_ACQ_REL);\
+  }\
+  void test_ ## name ## _1 (short* mem)\
+  {\
+    name (mem, 1, __ATOMIC_ACQ_REL);\
+  }\
+  void test_ ## name ##_2 (int* mem)\
+  {\
+    name (mem, 1, __ATOMIC_ACQ_REL);\
+  }\
+
+emitfuncs (__atomic_add_fetch)
+emitfuncs (__atomic_fetch_add)
+
+emitfuncs (__atomic_sub_fetch)
+emitfuncs (__atomic_fetch_sub)
+
+emitfuncs (__atomic_and_fetch)
+emitfuncs (__atomic_fetch_and)
+
+emitfuncs (__atomic_or_fetch)
+emitfuncs (__atomic_fetch_or)
+
+emitfuncs (__atomic_xor_fetch)
+emitfuncs (__atomic_fetch_xor)
+
+emitfuncs (__atomic_nand_fetch)
+emitfuncs (__atomic_fetch_nand)
+
+void
+test___atomic_compare_exchange_0 (char* mem)
+{
+  char expected = 1;
+  char desired = 5;
+  __atomic_compare_exchange (mem, &expected, &desired, 0, __ATOMIC_ACQ_REL,
+			     __ATOMIC_RELAXED);
+}
+
+void
+test___atomic_compare_exchange_1 (short* mem)
+{
+  short expected = 1;
+  short desired = 5;
+  __atomic_compare_exchange (mem, &expected, &desired, 0, __ATOMIC_ACQ_REL,
+			     __ATOMIC_RELAXED);
+}
+
+void
+test___atomic_compare_exchange_2 (int* mem)
+{
+  int expected = 1;
+  int desired = 5;
+  __atomic_compare_exchange (mem, &expected, &desired, 0, __ATOMIC_ACQ_REL,
+			     __ATOMIC_RELAXED);
+}
Index: gcc/testsuite/gcc.target/sh/pr64659-1.c
===================================================================
--- gcc/testsuite/gcc.target/sh/pr64659-1.c	(revision 0)
+++ gcc/testsuite/gcc.target/sh/pr64659-1.c	(revision 0)
@@ -0,0 +1,7 @@ 
+/* Check that atomic ops utilize insns with immediate values.  */
+/* { dg-do compile { target { atomic_model_soft_gusa_available } } }  */
+/* { dg-options "-O2 -matomic-model=soft-gusa,strict" }  */
+/* { dg-final { scan-assembler-times "add\t#1" 6 } }  */
+/* { dg-final { scan-assembler-times "add\t#-1" 6 } }  */
+
+#include "pr64659-0.h"
Index: gcc/testsuite/gcc.target/sh/sh.exp
===================================================================
--- gcc/testsuite/gcc.target/sh/sh.exp	(revision 220143)
+++ gcc/testsuite/gcc.target/sh/sh.exp	(working copy)
@@ -33,6 +33,34 @@ 
     } ""]
 }
 
+# Return 1 if target supports atomic-model=soft-gusa
+proc check_effective_target_atomic_model_soft_gusa_available { } {
+    return [check_no_compiler_messages atomic_model_soft_gusa_available object {
+	     int x = 0;
+    } "-matomic-model=soft-gusa"]
+}
+
+# Return 1 if target supports atomic-model=soft-tcb
+proc check_effective_target_atomic_model_soft_tcb_available { } {
+    return [check_no_compiler_messages atomic_model_soft_tcb_available object {
+	     int x = 0;
+    } "-matomic-model=soft-tcb,gbr-offset=0"]
+}
+
+# Return 1 if target supports atomic-model=soft-imask
+proc check_effective_target_atomic_model_soft_imask_available { } {
+    return [check_no_compiler_messages atomic_model_soft_imask_available object {
+	     int x = 0;
+    } "-matomic-model=soft-imask -mno-usermode"]
+}
+
+# Return 1 if target supports atomic-model=hard-llcs
+proc check_effective_target_atomic_model_hard_llcs_available { } {
+    return [check_no_compiler_messages atomic_model_hard_llcs_available object {
+	     int x = 0;
+    } "-matomic-model=hard-llcs"]
+}
+
 # If a testcase doesn't have special options, use these.
 global DEFAULT_CFLAGS
 if ![info exists DEFAULT_CFLAGS] then {
Index: gcc/config/sh/predicates.md
===================================================================
--- gcc/config/sh/predicates.md	(revision 220143)
+++ gcc/config/sh/predicates.md	(working copy)
@@ -1134,24 +1134,6 @@ 
   return 0;
 })
 
-;; The atomic_* operand predicates are used for the atomic patterns.
-;; Depending on the particular pattern some operands can be immediate
-;; values.  Using these predicates avoids the usage of 'force_reg' in the
-;; expanders.
-(define_predicate "atomic_arith_operand"
-  (ior (match_code "subreg,reg")
-       (and (match_test "satisfies_constraint_I08 (op)")
-	    (match_test "mode != QImode")
-	    (match_test "mode != HImode")
-	    (match_test "TARGET_SH4A"))))
-
-(define_predicate "atomic_logical_operand"
-  (ior (match_code "subreg,reg")
-       (and (match_test "satisfies_constraint_K08 (op)")
-	    (match_test "mode != QImode")
-	    (match_test "mode != HImode")
-	    (match_test "TARGET_SH4A"))))
-
 ;; A predicate that matches any expression for which there is an
 ;; insn pattern that sets the T bit.
 (define_predicate "treg_set_expr"
Index: gcc/config/sh/sync.md
===================================================================
--- gcc/config/sh/sync.md	(revision 220143)
+++ gcc/config/sh/sync.md	(working copy)
@@ -195,26 +195,29 @@ 
 (define_code_attr fetchop_name
   [(plus "add") (minus "sub") (ior "or") (xor "xor") (and "and")])
 
-(define_code_attr fetchop_predicate
-  [(plus "atomic_arith_operand") (minus "register_operand")
-   (ior "atomic_logical_operand") (xor "atomic_logical_operand")
-   (and "atomic_logical_operand")])
-
-(define_code_attr fetchop_constraint
-  [(plus "rI08") (minus "r") (ior "rK08") (xor "rK08") (and "rK08")])
-
 ;;------------------------------------------------------------------------------
 ;; comapre and swap
 
+;; Only the hard_llcs SImode patterns can use an I08 for the comparison
+;; or for the new swapped in value.
+(define_predicate "atomic_arith_operand_0"
+  (and (match_code "subreg,reg,const_int")
+       (ior (match_operand 0 "arith_reg_operand")
+	    (and (match_test "satisfies_constraint_I08 (op)")
+		 (match_test "mode == SImode")
+		 (ior (match_test "TARGET_ATOMIC_HARD_LLCS")
+		      (match_test "TARGET_ATOMIC_ANY && TARGET_SH4A
+				   && !TARGET_ATOMIC_STRICT"))))))
+
 (define_expand "atomic_compare_and_swap<mode>"
-  [(match_operand:SI 0 "register_operand" "")		;; bool success output
-   (match_operand:QIHISI 1 "register_operand" "")	;; oldval output
-   (match_operand:QIHISI 2 "memory_operand" "")		;; memory
-   (match_operand:QIHISI 3 "atomic_arith_operand" "")	;; expected input
-   (match_operand:QIHISI 4 "atomic_arith_operand" "")	;; newval input
-   (match_operand:SI 5 "const_int_operand" "")		;; is_weak
-   (match_operand:SI 6 "const_int_operand" "")		;; success model
-   (match_operand:SI 7 "const_int_operand" "")]		;; failure model
+  [(match_operand:SI 0 "arith_reg_dest")		;; bool success output
+   (match_operand:QIHISI 1 "arith_reg_dest")		;; oldval output
+   (match_operand:QIHISI 2 "memory_operand")		;; memory
+   (match_operand:QIHISI 3 "atomic_arith_operand_0")	;; expected input
+   (match_operand:QIHISI 4 "atomic_arith_operand_0")	;; newval input
+   (match_operand:SI 5 "const_int_operand")		;; is_weak
+   (match_operand:SI 6 "const_int_operand")		;; success model
+   (match_operand:SI 7 "const_int_operand")]		;; failure model
   "TARGET_ATOMIC_ANY"
 {
   rtx addr = force_reg (Pmode, XEXP (operands[2], 0));
@@ -252,9 +255,9 @@ 
 })
 
 (define_insn "atomic_compare_and_swapsi_hard"
-  [(set (match_operand:SI 0 "register_operand" "=&r")
+  [(set (match_operand:SI 0 "arith_reg_dest" "=&r")
 	(unspec_volatile:SI
-	  [(mem:SI (match_operand:SI 1 "register_operand" "r"))
+	  [(mem:SI (match_operand:SI 1 "arith_reg_operand" "r"))
 	   (match_operand:SI 2 "arith_operand" "rI08")
 	   (match_operand:SI 3 "arith_operand" "rI08")]
 	  UNSPECV_CMPXCHG_1))
@@ -278,11 +281,11 @@ 
   [(set_attr "length" "14")])
 
 (define_insn "atomic_compare_and_swap<mode>_hard"
-  [(set (match_operand:SI 0 "register_operand" "=&r")
+  [(set (match_operand:SI 0 "arith_reg_dest" "=&r")
 	(unspec_volatile:SI
-	  [(mem:QIHI (match_operand:SI 1 "register_operand" "r"))
-	   (match_operand:QIHI 2 "register_operand" "r")
-	   (match_operand:QIHI 3 "register_operand" "r")]
+	  [(mem:QIHI (match_operand:SI 1 "arith_reg_operand" "r"))
+	   (match_operand:QIHI 2 "arith_reg_operand" "r")
+	   (match_operand:QIHI 3 "arith_reg_operand" "r")]
 	  UNSPECV_CMPXCHG_1))
    (set (mem:QIHI (match_dup 1))
 	(unspec_volatile:QIHI [(const_int 0)] UNSPECV_CMPXCHG_2))
@@ -314,11 +317,11 @@ 
   [(set_attr "length" "30")])
 
 (define_insn "atomic_compare_and_swap<mode>_soft_gusa"
-  [(set (match_operand:SI 0 "register_operand" "=&u")
+  [(set (match_operand:SI 0 "arith_reg_dest" "=&u")
 	(unspec_volatile:SI
-	  [(mem:QIHISI (match_operand:SI 1 "register_operand" "u"))
-	   (match_operand:QIHISI 2 "register_operand" "u")
-	   (match_operand:QIHISI 3 "register_operand" "u")]
+	  [(mem:QIHISI (match_operand:SI 1 "arith_reg_operand" "u"))
+	   (match_operand:QIHISI 2 "arith_reg_operand" "u")
+	   (match_operand:QIHISI 3 "arith_reg_operand" "u")]
 	  UNSPECV_CMPXCHG_1))
    (set (mem:QIHISI (match_dup 1))
 	(unspec_volatile:QIHISI [(const_int 0)] UNSPECV_CMPXCHG_2))
@@ -343,11 +346,11 @@ 
   [(set_attr "length" "20")])
 
 (define_insn "atomic_compare_and_swap<mode>_soft_tcb"
-  [(set (match_operand:SI 0 "register_operand" "=&r")
+  [(set (match_operand:SI 0 "arith_reg_dest" "=&r")
 	(unspec_volatile:SI
-	  [(mem:QIHISI (match_operand:SI 1 "register_operand" "r"))
-	   (match_operand:QIHISI 2 "register_operand" "r")
-	   (match_operand:QIHISI 3 "register_operand" "r")]
+	  [(mem:QIHISI (match_operand:SI 1 "arith_reg_operand" "r"))
+	   (match_operand:QIHISI 2 "arith_reg_operand" "r")
+	   (match_operand:QIHISI 3 "arith_reg_operand" "r")]
 	  UNSPECV_CMPXCHG_1))
    (set (mem:QIHISI (match_dup 1))
 	(unspec_volatile:QIHISI [(const_int 0)] UNSPECV_CMPXCHG_2))
@@ -374,11 +377,11 @@ 
   [(set_attr "length" "22")])
 
 (define_insn "atomic_compare_and_swap<mode>_soft_imask"
-  [(set (match_operand:SI 0 "register_operand" "=&z")
+  [(set (match_operand:SI 0 "arith_reg_dest" "=&z")
 	(unspec_volatile:SI
-	  [(mem:QIHISI (match_operand:SI 1 "register_operand" "r"))
-	   (match_operand:QIHISI 2 "register_operand" "r")
-	   (match_operand:QIHISI 3 "register_operand" "r")]
+	  [(mem:QIHISI (match_operand:SI 1 "arith_reg_operand" "r"))
+	   (match_operand:QIHISI 2 "arith_reg_operand" "r")
+	   (match_operand:QIHISI 3 "arith_reg_operand" "r")]
 	  UNSPECV_CMPXCHG_1))
    (set (mem:QIHISI (match_dup 1))
 	(unspec_volatile:QIHISI [(const_int 0)] UNSPECV_CMPXCHG_2))
@@ -426,10 +429,10 @@ 
 ;; read - write - return old value
 
 (define_expand "atomic_exchange<mode>"
-  [(match_operand:QIHISI 0 "register_operand" "")	;; oldval output
-   (match_operand:QIHISI 1 "memory_operand" "")		;; memory
-   (match_operand:QIHISI 2 "atomic_arith_operand" "")	;; newval input
-   (match_operand:SI 3 "const_int_operand" "")]		;; memory model
+  [(match_operand:QIHISI 0 "arith_reg_dest")		;; oldval output
+   (match_operand:QIHISI 1 "memory_operand")		;; memory
+   (match_operand:QIHISI 2 "atomic_arith_operand_0")	;; newval input
+   (match_operand:SI 3 "const_int_operand")]		;; memory model
   "TARGET_ATOMIC_ANY"
 {
   rtx addr = force_reg (Pmode, XEXP (operands[1], 0));
@@ -461,8 +464,8 @@ 
 })
 
 (define_insn "atomic_exchangesi_hard"
-  [(set (match_operand:SI 0 "register_operand" "=&r")
-	(mem:SI (match_operand:SI 1 "register_operand" "r")))
+  [(set (match_operand:SI 0 "arith_reg_dest" "=&r")
+	(mem:SI (match_operand:SI 1 "arith_reg_operand" "r")))
    (set (mem:SI (match_dup 1))
 	(unspec:SI
 	  [(match_operand:SI 2 "arith_operand" "rI08")] UNSPEC_ATOMIC))
@@ -480,11 +483,11 @@ 
   [(set_attr "length" "10")])
 
 (define_insn "atomic_exchange<mode>_hard"
-  [(set (match_operand:QIHI 0 "register_operand" "=&r")
-	(mem:QIHI (match_operand:SI 1 "register_operand" "r")))
+  [(set (match_operand:QIHI 0 "arith_reg_dest" "=&r")
+	(mem:QIHI (match_operand:SI 1 "arith_reg_operand" "r")))
    (set (mem:QIHI (match_dup 1))
 	(unspec:QIHI
-	  [(match_operand:QIHI 2 "register_operand" "r")] UNSPEC_ATOMIC))
+	  [(match_operand:QIHI 2 "arith_reg_operand" "r")] UNSPEC_ATOMIC))
    (set (reg:SI T_REG) (const_int 1))
    (clobber (reg:SI R0_REG))
    (clobber (match_scratch:SI 3 "=&r"))
@@ -507,11 +510,11 @@ 
   [(set_attr "length" "24")])
 
 (define_insn "atomic_exchange<mode>_soft_gusa"
-  [(set (match_operand:QIHISI 0 "register_operand" "=&u")
-	(mem:QIHISI (match_operand:SI 1 "register_operand" "u")))
+  [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&u")
+	(mem:QIHISI (match_operand:SI 1 "arith_reg_operand" "u")))
    (set (mem:QIHISI (match_dup 1))
 	(unspec:QIHISI
-	  [(match_operand:QIHISI 2 "register_operand" "u")] UNSPEC_ATOMIC))
+	  [(match_operand:QIHISI 2 "arith_reg_operand" "u")] UNSPEC_ATOMIC))
    (clobber (reg:SI R0_REG))
    (clobber (reg:SI R1_REG))]
   "TARGET_ATOMIC_SOFT_GUSA"
@@ -527,11 +530,11 @@ 
   [(set_attr "length" "14")])
 
 (define_insn "atomic_exchange<mode>_soft_tcb"
-  [(set (match_operand:QIHISI 0 "register_operand" "=&r")
-	(mem:QIHISI (match_operand:SI 1 "register_operand" "r")))
+  [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&r")
+	(mem:QIHISI (match_operand:SI 1 "arith_reg_operand" "r")))
    (set (mem:QIHISI (match_dup 1))
 	(unspec:QIHISI
-	  [(match_operand:QIHISI 2 "register_operand" "r")] UNSPEC_ATOMIC))
+	  [(match_operand:QIHISI 2 "arith_reg_operand" "r")] UNSPEC_ATOMIC))
    (clobber (reg:SI R0_REG))
    (clobber (reg:SI R1_REG))
    (use (match_operand:SI 3 "gbr_displacement"))]
@@ -549,11 +552,11 @@ 
   [(set_attr "length" "16")])
 
 (define_insn "atomic_exchange<mode>_soft_imask"
-  [(set (match_operand:QIHISI 0 "register_operand" "=&z")
-	(mem:QIHISI (match_operand:SI 1 "register_operand" "r")))
+  [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&z")
+	(mem:QIHISI (match_operand:SI 1 "arith_reg_operand" "r")))
    (set (mem:QIHISI (match_dup 1))
 	(unspec:QIHISI
-	  [(match_operand:QIHISI 2 "register_operand" "r")] UNSPEC_ATOMIC))
+	  [(match_operand:QIHISI 2 "arith_reg_operand" "r")] UNSPEC_ATOMIC))
    (clobber (match_scratch:SI 3 "=&r"))]
   "TARGET_ATOMIC_SOFT_IMASK"
 {
@@ -570,15 +573,52 @@ 
 ;;------------------------------------------------------------------------------
 ;; read - add|sub|or|and|xor|nand - write - return old value
 
+;; atomic_arith_operand_1 can be used by any atomic type for a plus op,
+;; since there's no r0 restriction.
+(define_predicate "atomic_arith_operand_1"
+  (and (match_code "subreg,reg,const_int")
+       (ior (match_operand 0 "arith_reg_operand")
+	    (match_test "satisfies_constraint_I08 (op)"))))
+
+;; atomic_logic_operand_1 can be used by the hard_llcs, tcb and soft_imask
+;; patterns only due to its r0 restriction. 
+(define_predicate "atomic_logical_operand_1"
+  (and (match_code "subreg,reg,const_int")
+       (ior (match_operand 0 "arith_reg_operand")
+	    (and (match_test "satisfies_constraint_K08 (op)")
+		 (ior (match_test "TARGET_ATOMIC_HARD_LLCS")
+		      (match_test "TARGET_ATOMIC_SOFT_IMASK")
+		      (match_test "TARGET_ATOMIC_SOFT_TCB")
+		      (match_test "TARGET_ATOMIC_ANY && TARGET_SH4A
+				   && mode == SImode
+				   && !TARGET_ATOMIC_STRICT"))))))
+
+(define_code_attr fetchop_predicate_1
+  [(plus "atomic_arith_operand_1") (minus "arith_reg_operand")
+   (ior "atomic_logical_operand_1") (xor "atomic_logical_operand_1")
+   (and "atomic_logical_operand_1")])
+
+(define_code_attr fetchop_constraint_1_llcs
+  [(plus "rI08") (minus "r") (ior "rK08") (xor "rK08") (and "rK08")])
+
+(define_code_attr fetchop_constraint_1_gusa
+  [(plus "uI08") (minus "u") (ior "u") (xor "u") (and "u")])
+
+(define_code_attr fetchop_constraint_1_tcb
+  [(plus "rI08") (minus "r") (ior "rK08") (xor "rK08") (and "rK08")])
+
+(define_code_attr fetchop_constraint_1_imask
+  [(plus "rI08") (minus "r") (ior "rK08") (xor "rK08") (and "rK08")])
+
 (define_expand "atomic_fetch_<fetchop_name><mode>"
-  [(set (match_operand:QIHISI 0 "register_operand" "")
-	(match_operand:QIHISI 1 "memory_operand" ""))
+  [(set (match_operand:QIHISI 0 "arith_reg_dest")
+	(match_operand:QIHISI 1 "memory_operand"))
    (set (match_dup 1)
 	(unspec:QIHISI
 	  [(FETCHOP:QIHISI (match_dup 1)
-	     (match_operand:QIHISI 2 "<fetchop_predicate>" ""))]
+	     (match_operand:QIHISI 2 "<fetchop_predicate_1>"))]
 	  UNSPEC_ATOMIC))
-   (match_operand:SI 3 "const_int_operand" "")]
+   (match_operand:SI 3 "const_int_operand")]
   "TARGET_ATOMIC_ANY"
 {
   rtx addr = force_reg (Pmode, XEXP (operands[1], 0));
@@ -612,12 +652,13 @@ 
 })
 
 (define_insn "atomic_fetch_<fetchop_name>si_hard"
-  [(set (match_operand:SI 0 "register_operand" "=&r")
-	(mem:SI (match_operand:SI 1 "register_operand" "r")))
+  [(set (match_operand:SI 0 "arith_reg_dest" "=&r")
+	(mem:SI (match_operand:SI 1 "arith_reg_operand" "r")))
    (set (mem:SI (match_dup 1))
 	(unspec:SI
 	  [(FETCHOP:SI (mem:SI (match_dup 1))
-	     (match_operand:SI 2 "<fetchop_predicate>" "<fetchop_constraint>"))]
+		       (match_operand:SI 2 "<fetchop_predicate_1>"
+					   "<fetchop_constraint_1_llcs>"))]
 	  UNSPEC_ATOMIC))
    (set (reg:SI T_REG) (const_int 1))
    (clobber (reg:SI R0_REG))]
@@ -633,12 +674,13 @@ 
   [(set_attr "length" "10")])
 
 (define_insn "atomic_fetch_<fetchop_name><mode>_hard"
-  [(set (match_operand:QIHI 0 "register_operand" "=&r")
-	(mem:QIHI (match_operand:SI 1 "register_operand" "r")))
+  [(set (match_operand:QIHI 0 "arith_reg_dest" "=&r")
+	(mem:QIHI (match_operand:SI 1 "arith_reg_operand" "r")))
    (set (mem:QIHI (match_dup 1))
 	(unspec:QIHI
 	  [(FETCHOP:QIHI (mem:QIHI (match_dup 1))
-	     (match_operand:QIHI 2 "<fetchop_predicate>" "<fetchop_constraint>"))]
+			 (match_operand:QIHI 2 "<fetchop_predicate_1>"
+					       "<fetchop_constraint_1_llcs>"))]
 	  UNSPEC_ATOMIC))
    (set (reg:SI T_REG) (const_int 1))
    (clobber (reg:SI R0_REG))
@@ -664,12 +706,14 @@ 
   [(set_attr "length" "28")])
 
 (define_insn "atomic_fetch_<fetchop_name><mode>_soft_gusa"
-  [(set (match_operand:QIHISI 0 "register_operand" "=&u")
-	(mem:QIHISI (match_operand:SI 1 "register_operand" "u")))
+  [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&u")
+	(mem:QIHISI (match_operand:SI 1 "arith_reg_operand" "u")))
    (set (mem:QIHISI (match_dup 1))
 	(unspec:QIHISI
-	  [(FETCHOP:QIHISI (mem:QIHISI (match_dup 1))
-	     (match_operand:QIHISI 2 "register_operand" "u"))]
+	  [(FETCHOP:QIHISI
+		(mem:QIHISI (match_dup 1))
+		(match_operand:QIHISI 2 "<fetchop_predicate_1>"
+					"<fetchop_constraint_1_gusa>"))]
 	  UNSPEC_ATOMIC))
    (clobber (match_scratch:QIHISI 3 "=&u"))
    (clobber (reg:SI R0_REG))
@@ -689,65 +733,68 @@ 
   [(set_attr "length" "18")])
 
 (define_insn "atomic_fetch_<fetchop_name><mode>_soft_tcb"
-  [(set (match_operand:QIHISI 0 "register_operand" "=&r")
-	(mem:QIHISI (match_operand:SI 1 "register_operand" "r")))
+  [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&r")
+	(mem:QIHISI (match_operand:SI 1 "arith_reg_operand" "r")))
    (set (mem:QIHISI (match_dup 1))
 	(unspec:QIHISI
-	  [(FETCHOP:QIHISI (mem:QIHISI (match_dup 1))
-	     (match_operand:QIHISI 2 "register_operand" "r"))]
+	  [(FETCHOP:QIHISI
+		(mem:QIHISI (match_dup 1))
+		(match_operand:QIHISI 2 "<fetchop_predicate_1>"
+					"<fetchop_constraint_1_tcb>"))]
 	  UNSPEC_ATOMIC))
    (use (match_operand:SI 3 "gbr_displacement"))
-   (clobber (match_scratch:QIHISI 4 "=&r"))
    (clobber (reg:SI R0_REG))
    (clobber (reg:SI R1_REG))]
   "TARGET_ATOMIC_SOFT_TCB"
 {
   return "\r	mova	1f,r0"			"\n"
+	 "	.align 2"			"\n"
 	 "	mov	#(0f-1f),r1"		"\n"
-	 "	.align 2"			"\n"
 	 "	mov.l	r0,@(%O3,gbr)"		"\n"
-	 "0:	mov.<bwl>	@%1,%0"		"\n"
-	 "	mov	#0,r0"			"\n"
-	 "	mov	%0,%4"			"\n"
-	 "	<fetchop_name>	%2,%4"		"\n"
-	 "	mov.<bwl>	%4,@%1"		"\n"
-	 "1:	mov.l	r0,@(%O3,gbr)";
+	 "0:	mov.<bwl>	@%1,r0"		"\n"
+	 "	mov	r0,%0"			"\n"
+	 "	<fetchop_name>	%2,r0"		"\n"
+	 "	mov.<bwl>	r0,@%1"		"\n"
+	 "1:	mov	#0,r0"			"\n"
+	 "	mov.l	r0,@(%O3,gbr)";
 }
   [(set_attr "length" "20")])
 
 (define_insn "atomic_fetch_<fetchop_name><mode>_soft_imask"
-  [(set (match_operand:QIHISI 0 "register_operand" "=&z")
-	(mem:QIHISI (match_operand:SI 1 "register_operand" "r")))
+  [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&r")
+	(mem:QIHISI (match_operand:SI 1 "arith_reg_operand" "r")))
    (set (mem:QIHISI (match_dup 1))
 	(unspec:QIHISI
-	  [(FETCHOP:QIHISI (mem:QIHISI (match_dup 1))
-	     (match_operand:QIHISI 2 "register_operand" "r"))]
+	  [(FETCHOP:QIHISI
+		(mem:QIHISI (match_dup 1))
+		(match_operand:QIHISI 2 "<fetchop_predicate_1>"
+					"<fetchop_constraint_1_imask>"))]
 	  UNSPEC_ATOMIC))
-   (clobber (match_scratch:QIHISI 3 "=&r"))
-   (clobber (match_scratch:SI 4 "=&r"))]
+   (clobber (reg:SI R0_REG))
+   (clobber (match_scratch:QIHISI 3 "=&r"))]
   "TARGET_ATOMIC_SOFT_IMASK"
 {
-  return "\r	stc	sr,%0"			"\n"
-	 "	mov	%0,%4"			"\n"
-	 "	or	#0xF0,%0"		"\n"
-	 "	ldc	%0,sr"			"\n"
-	 "	mov.<bwl>	@%1,%0"		"\n"
-	 "	mov	%0,%3"			"\n"
-	 "	<fetchop_name>	%2,%3"		"\n"
-	 "	mov.<bwl>	%3,@%1"		"\n"
-	 "	ldc	%4,sr";
+  return "\r	stc	sr,r0"			"\n"
+	 "	mov	r0,%3"			"\n"
+	 "	or	#0xF0,r0"		"\n"
+	 "	ldc	r0,sr"			"\n"
+	 "	mov.<bwl>	@%1,r0"		"\n"
+	 "	mov	r0,%0"			"\n"
+	 "	<fetchop_name>	%2,r0"		"\n"
+	 "	mov.<bwl>	r0,@%1"		"\n"
+	 "	ldc	%3,sr";
 }
   [(set_attr "length" "18")])
 
 (define_expand "atomic_fetch_nand<mode>"
-  [(set (match_operand:QIHISI 0 "register_operand" "")
-	(match_operand:QIHISI 1 "memory_operand" ""))
+  [(set (match_operand:QIHISI 0 "arith_reg_dest")
+	(match_operand:QIHISI 1 "memory_operand"))
    (set (match_dup 1)
 	(unspec:QIHISI
 	  [(not:QIHISI (and:QIHISI (match_dup 1)
-		       (match_operand:QIHISI 2 "atomic_logical_operand" "")))]
+		       (match_operand:QIHISI 2 "atomic_logical_operand_1")))]
 	  UNSPEC_ATOMIC))
-   (match_operand:SI 3 "const_int_operand" "")]
+   (match_operand:SI 3 "const_int_operand")]
   "TARGET_ATOMIC_ANY"
 {
   rtx addr = force_reg (Pmode, XEXP (operands[1], 0));
@@ -781,8 +828,8 @@ 
 })
 
 (define_insn "atomic_fetch_nandsi_hard"
-  [(set (match_operand:SI 0 "register_operand" "=&r")
-	(mem:SI (match_operand:SI 1 "register_operand" "r")))
+  [(set (match_operand:SI 0 "arith_reg_dest" "=&r")
+	(mem:SI (match_operand:SI 1 "arith_reg_operand" "r")))
    (set (mem:SI (match_dup 1))
 	(unspec:SI
 	  [(not:SI (and:SI (mem:SI (match_dup 1))
@@ -803,8 +850,8 @@ 
   [(set_attr "length" "12")])
 
 (define_insn "atomic_fetch_nand<mode>_hard"
-  [(set (match_operand:QIHI 0 "register_operand" "=&r")
-	(mem:QIHI (match_operand:SI 1 "register_operand" "r")))
+  [(set (match_operand:QIHI 0 "arith_reg_dest" "=&r")
+	(mem:QIHI (match_operand:SI 1 "arith_reg_operand" "r")))
    (set (mem:QIHI (match_dup 1))
 	(unspec:QIHI
 	  [(not:QIHI (and:QIHI (mem:QIHI (match_dup 1))
@@ -835,12 +882,13 @@ 
   [(set_attr "length" "30")])
 
 (define_insn "atomic_fetch_nand<mode>_soft_gusa"
-  [(set (match_operand:QIHISI 0 "register_operand" "=&u")
-	(mem:QIHISI (match_operand:SI 1 "register_operand" "u")))
+  [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&u")
+	(mem:QIHISI (match_operand:SI 1 "arith_reg_operand" "u")))
    (set (mem:QIHISI (match_dup 1))
 	(unspec:QIHISI
-	  [(not:QIHISI (and:QIHISI (mem:QIHISI (match_dup 1))
-	     (match_operand:QIHISI 2 "register_operand" "u")))]
+	  [(not:QIHISI
+	     (and:QIHISI (mem:QIHISI (match_dup 1))
+			 (match_operand:QIHISI 2 "arith_reg_operand" "u")))]
 	  UNSPEC_ATOMIC))
    (clobber (match_scratch:QIHISI 3 "=&u"))
    (clobber (reg:SI R0_REG))
@@ -861,55 +909,56 @@ 
   [(set_attr "length" "20")])
 
 (define_insn "atomic_fetch_nand<mode>_soft_tcb"
-  [(set (match_operand:QIHISI 0 "register_operand" "=&r")
-	(mem:QIHISI (match_operand:SI 1 "register_operand" "r")))
+  [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&r")
+	(mem:QIHISI (match_operand:SI 1 "arith_reg_operand" "r")))
    (set (mem:QIHISI (match_dup 1))
 	(unspec:QIHISI
-	  [(not:QIHISI (and:QIHISI (mem:QIHISI (match_dup 1))
-	     (match_operand:QIHISI 2 "register_operand" "r")))]
+	  [(not:QIHISI
+	     (and:QIHISI (mem:QIHISI (match_dup 1))
+			 (match_operand:QIHISI 2 "logical_operand" "rK08")))]
 	  UNSPEC_ATOMIC))
    (use (match_operand:SI 3 "gbr_displacement"))
-   (clobber (match_scratch:QIHISI 4 "=&r"))
    (clobber (reg:SI R0_REG))
    (clobber (reg:SI R1_REG))]
   "TARGET_ATOMIC_SOFT_TCB"
 {
   return "\r	mova	1f,r0"			"\n"
+	 "	mov	#(0f-1f),r1"		"\n"
 	 "	.align 2"			"\n"
-	 "	mov	#(0f-1f),r1"		"\n"
 	 "	mov.l	r0,@(%O3,gbr)"		"\n"
-	 "0:	mov.<bwl>	@%1,%0"		"\n"
-	 "	mov	#0,r0"			"\n"
-	 "	mov	%2,%4"			"\n"
-	 "	and	%0,%4"			"\n"
-	 "	not	%4,%4"			"\n"
-	 "	mov.<bwl>	%4,@%1"		"\n"
-	 "1:	mov.l	r0,@(%O3,gbr)";
+	 "0:	mov.<bwl>	@%1,r0"		"\n"
+	 "	mov	r0,%0"			"\n"
+	 "	and	%2,r0"			"\n"
+	 "	not	r0,r0"			"\n"
+	 "	mov.<bwl>	r0,@%1"		"\n"
+	 "1:	mov	#0,r0"			"\n"
+	 "	mov.l	r0,@(%O3,gbr)";
 }
   [(set_attr "length" "22")])
 
 (define_insn "atomic_fetch_nand<mode>_soft_imask"
-  [(set (match_operand:QIHISI 0 "register_operand" "=&z")
-	(mem:QIHISI (match_operand:SI 1 "register_operand" "r")))
+  [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&r")
+	(mem:QIHISI (match_operand:SI 1 "arith_reg_operand" "r")))
    (set (mem:QIHISI (match_dup 1))
 	(unspec:QIHISI
-	  [(not:QIHISI (and:QIHISI (mem:QIHISI (match_dup 1))
-	     (match_operand:QIHISI 2 "register_operand" "r")))]
+	  [(not:QIHISI
+	     (and:QIHISI (mem:QIHISI (match_dup 1))
+			 (match_operand:QIHISI 2 "logical_operand" "rK08")))]
 	  UNSPEC_ATOMIC))
-   (clobber (match_scratch:QIHISI 3 "=&r"))
-   (clobber (match_scratch:SI 4 "=&r"))]
+   (clobber (reg:SI R0_REG))
+   (clobber (match_scratch:SI 3 "=&r"))]
   "TARGET_ATOMIC_SOFT_IMASK"
 {
-  return "\r	stc	sr,%0"			"\n"
-	 "	mov	%0,%4"			"\n"
-	 "	or	#0xF0,%0"		"\n"
-	 "	ldc	%0,sr"			"\n"
-	 "	mov.<bwl>	@%1,%0"		"\n"
-	 "	mov	%2,%3"			"\n"
-	 "	and	%0,%3"			"\n"
-	 "	not	%3,%3"			"\n"
-	 "	mov.<bwl>	%3,@%1"		"\n"
-	 "	ldc	%4,sr";
+  return "\r	stc	sr,r0"			"\n"
+	 "	mov	r0,%3"			"\n"
+	 "	or	#0xF0,r0"		"\n"
+	 "	ldc	r0,sr"			"\n"
+	 "	mov.<bwl>	@%1,r0"		"\n"
+	 "	mov	r0,%0"			"\n"
+	 "	and	%2,r0"			"\n"
+	 "	not	r0,r0"			"\n"
+	 "	mov.<bwl>	r0,@%1"		"\n"
+	 "	ldc	%3,sr";
 }
   [(set_attr "length" "20")])
 
@@ -917,10 +966,10 @@ 
 ;; read - add|sub|or|and|xor|nand - write - return new value
 
 (define_expand "atomic_<fetchop_name>_fetch<mode>"
-  [(set (match_operand:QIHISI 0 "register_operand" "")
+  [(set (match_operand:QIHISI 0 "arith_reg_dest")
 	(FETCHOP:QIHISI
-	  (match_operand:QIHISI 1 "memory_operand" "")
-	  (match_operand:QIHISI 2 "<fetchop_predicate>" "")))
+	  (match_operand:QIHISI 1 "memory_operand")
+	  (match_operand:QIHISI 2 "<fetchop_predicate_1>")))
    (set (match_dup 1)
 	(unspec:QIHISI
 	  [(FETCHOP:QIHISI (match_dup 1) (match_dup 2))]
@@ -959,10 +1008,11 @@ 
 })
 
 (define_insn "atomic_<fetchop_name>_fetchsi_hard"
-  [(set (match_operand:SI 0 "register_operand" "=&z")
+  [(set (match_operand:SI 0 "arith_reg_dest" "=&z")
 	(FETCHOP:SI
-	  (mem:SI (match_operand:SI 1 "register_operand" "r"))
-	  (match_operand:SI 2 "<fetchop_predicate>" "<fetchop_constraint>")))
+	  (mem:SI (match_operand:SI 1 "arith_reg_operand" "r"))
+	  (match_operand:SI 2 "<fetchop_predicate_1>"
+			      "<fetchop_constraint_1_llcs>")))
    (set (mem:SI (match_dup 1))
 	(unspec:SI
 	  [(FETCHOP:SI (mem:SI (match_dup 1)) (match_dup 2))]
@@ -979,10 +1029,11 @@ 
   [(set_attr "length" "8")])
 
 (define_insn "atomic_<fetchop_name>_fetch<mode>_hard"
-  [(set (match_operand:QIHI 0 "register_operand" "=&r")
+  [(set (match_operand:QIHI 0 "arith_reg_dest" "=&r")
 	(FETCHOP:QIHI
-	  (mem:QIHI (match_operand:SI 1 "register_operand" "r"))
-	  (match_operand:QIHI 2 "<fetchop_predicate>" "<fetchop_constraint>")))
+	  (mem:QIHI (match_operand:SI 1 "arith_reg_operand" "r"))
+	  (match_operand:QIHI 2 "<fetchop_predicate_1>"
+				"<fetchop_constraint_1_llcs>")))
    (set (mem:QIHI (match_dup 1))
 	(unspec:QIHI
 	  [(FETCHOP:QIHI (mem:QIHI (match_dup 1)) (match_dup 2))]
@@ -1011,10 +1062,11 @@ 
   [(set_attr "length" "28")])
 
 (define_insn "atomic_<fetchop_name>_fetch<mode>_soft_gusa"
-  [(set (match_operand:QIHISI 0 "register_operand" "=&u")
+  [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&u")
 	(FETCHOP:QIHISI
-	  (mem:QIHISI (match_operand:SI 1 "register_operand" "u"))
-	  (match_operand:QIHISI 2 "register_operand" "u")))
+	  (mem:QIHISI (match_operand:SI 1 "arith_reg_operand" "u"))
+	  (match_operand:QIHISI 2 "<fetchop_predicate_1>"
+				  "<fetchop_constraint_1_gusa>")))
    (set (mem:QIHISI (match_dup 1))
 	(unspec:QIHISI
 	  [(FETCHOP:QIHISI (mem:QIHISI (match_dup 1)) (match_dup 2))]
@@ -1035,10 +1087,11 @@ 
   [(set_attr "length" "16")])
 
 (define_insn "atomic_<fetchop_name>_fetch<mode>_soft_tcb"
-  [(set (match_operand:QIHISI 0 "register_operand" "=&r")
+  [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&r")
 	(FETCHOP:QIHISI
-	  (mem:QIHISI (match_operand:SI 1 "register_operand" "r"))
-	  (match_operand:QIHISI 2 "register_operand" "r")))
+	  (mem:QIHISI (match_operand:SI 1 "arith_reg_operand" "r"))
+	  (match_operand:QIHISI 2 "<fetchop_predicate_1>"
+				  "<fetchop_constraint_1_tcb>")))
    (set (mem:QIHISI (match_dup 1))
 	(unspec:QIHISI
 	  [(FETCHOP:QIHISI (mem:QIHISI (match_dup 1)) (match_dup 2))]
@@ -1049,22 +1102,24 @@ 
   "TARGET_ATOMIC_SOFT_TCB"
 {
   return "\r	mova	1f,r0"			"\n"
+	 "	mov	#(0f-1f),r1"		"\n"
 	 "	.align 2"			"\n"
-	 "	mov	#(0f-1f),r1"		"\n"
 	 "	mov.l	r0,@(%O3,gbr)"		"\n"
-	 "0:	mov.<bwl>	@%1,%0"		"\n"
+	 "0:	mov.<bwl>	@%1,r0"		"\n"
+	 "	<fetchop_name>	%2,r0"		"\n"
+	 "	mov.<bwl>	r0,@%1"		"\n"
+	 "1:	mov	r0,%0"			"\n"
 	 "	mov	#0,r0"			"\n"
-	 "	<fetchop_name>	%2,%0"		"\n"
-	 "	mov.<bwl>	%0,@%1"		"\n"
-	 "1:	mov.l	r0,@(%O3,gbr)";
+	 "	mov.l	r0,@(%O3,gbr)";
 }
-  [(set_attr "length" "18")])
+  [(set_attr "length" "20")])
 
 (define_insn "atomic_<fetchop_name>_fetch<mode>_soft_imask"
-  [(set (match_operand:QIHISI 0 "register_operand" "=&z")
+  [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&z")
 	(FETCHOP:QIHISI
-	  (mem:QIHISI (match_operand:SI 1 "register_operand" "r"))
-	  (match_operand:QIHISI 2 "register_operand" "r")))
+	  (mem:QIHISI (match_operand:SI 1 "arith_reg_operand" "r"))
+	  (match_operand:QIHISI 2 "<fetchop_predicate_1>"
+				  "<fetchop_constraint_1_imask>")))
    (set (mem:QIHISI (match_dup 1))
 	(unspec:QIHISI
 	  [(FETCHOP:QIHISI (mem:QIHISI (match_dup 1)) (match_dup 2))]
@@ -1084,15 +1139,15 @@ 
   [(set_attr "length" "16")])
 
 (define_expand "atomic_nand_fetch<mode>"
-  [(set (match_operand:QIHISI 0 "register_operand" "")
+  [(set (match_operand:QIHISI 0 "arith_reg_dest")
 	(not:QIHISI (and:QIHISI
-	  (match_operand:QIHISI 1 "memory_operand" "")
-	  (match_operand:QIHISI 2 "atomic_logical_operand" ""))))
+	  (match_operand:QIHISI 1 "memory_operand")
+	  (match_operand:QIHISI 2 "atomic_logical_operand_1"))))
    (set (match_dup 1)
 	(unspec:QIHISI
 	  [(not:QIHISI (and:QIHISI (match_dup 1) (match_dup 2)))]
 	  UNSPEC_ATOMIC))
-   (match_operand:SI 3 "const_int_operand" "")]
+   (match_operand:SI 3 "const_int_operand")]
   "TARGET_ATOMIC_ANY"
 {
   rtx addr = force_reg (Pmode, XEXP (operands[1], 0));
@@ -1126,8 +1181,8 @@ 
 })
 
 (define_insn "atomic_nand_fetchsi_hard"
-  [(set (match_operand:SI 0 "register_operand" "=&z")
-	(not:SI (and:SI (mem:SI (match_operand:SI 1 "register_operand" "r"))
+  [(set (match_operand:SI 0 "arith_reg_dest" "=&z")
+	(not:SI (and:SI (mem:SI (match_operand:SI 1 "arith_reg_operand" "r"))
 			(match_operand:SI 2 "logical_operand" "rK08"))))
    (set (mem:SI (match_dup 1))
 	(unspec:SI
@@ -1146,9 +1201,9 @@ 
   [(set_attr "length" "10")])
 
 (define_insn "atomic_nand_fetch<mode>_hard"
-  [(set (match_operand:QIHI 0 "register_operand" "=&r")
+  [(set (match_operand:QIHI 0 "arith_reg_dest" "=&r")
 	(not:QIHI
-	  (and:QIHI (mem:QIHI (match_operand:SI 1 "register_operand" "r"))
+	  (and:QIHI (mem:QIHI (match_operand:SI 1 "arith_reg_operand" "r"))
 		    (match_operand:QIHI 2 "logical_operand" "rK08"))))
    (set (mem:QIHI (match_dup 1))
 	(unspec:QIHI
@@ -1178,10 +1233,10 @@ 
   [(set_attr "length" "28")])
 
 (define_insn "atomic_nand_fetch<mode>_soft_gusa"
-  [(set (match_operand:QIHISI 0 "register_operand" "=&u")
+  [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&u")
 	(not:QIHISI (and:QIHISI
-	  (mem:QIHISI (match_operand:SI 1 "register_operand" "u"))
-	  (match_operand:QIHISI 2 "register_operand" "u"))))
+	  (mem:QIHISI (match_operand:SI 1 "arith_reg_operand" "u"))
+	  (match_operand:QIHISI 2 "arith_reg_operand" "u"))))
    (set (mem:QIHISI (match_dup 1))
 	(unspec:QIHISI
 	  [(not:QIHISI (and:QIHISI (mem:QIHISI (match_dup 1)) (match_dup 2)))]
@@ -1203,10 +1258,10 @@ 
   [(set_attr "length" "18")])
 
 (define_insn "atomic_nand_fetch<mode>_soft_tcb"
-  [(set (match_operand:QIHISI 0 "register_operand" "=&r")
+  [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&r")
 	(not:QIHISI (and:QIHISI
-	  (mem:QIHISI (match_operand:SI 1 "register_operand" "r"))
-	  (match_operand:QIHISI 2 "register_operand" "r"))))
+	  (mem:QIHISI (match_operand:SI 1 "arith_reg_operand" "r"))
+	  (match_operand:QIHISI 2 "logical_operand" "rK08"))))
    (set (mem:QIHISI (match_dup 1))
 	(unspec:QIHISI
 	  [(not:QIHISI (and:QIHISI (mem:QIHISI (match_dup 1)) (match_dup 2)))]
@@ -1220,20 +1275,21 @@ 
 	 "	mov	#(0f-1f),r1"		"\n"
 	 "	.align 2"			"\n"
 	 "	mov.l	r0,@(%O3,gbr)"		"\n"
-	 "0:	mov.<bwl>	@%1,%0"		"\n"
-	 "	mov	#0,r0"			"\n"
-	 "	and	%2,%0"			"\n"
-	 "	not	%0,%0"			"\n"
-	 "	mov.<bwl>	%0,@%1"		"\n"
-	 "1:	mov.l	r0,@(%O3,gbr)";
+	 "0:	mov.<bwl>	@%1,r0"		"\n"
+	 "	and	%2,r0"			"\n"
+	 "	not	r0,r0"			"\n"
+	 "	mov	r0,%0"			"\n"
+	 "	mov.<bwl>	r0,@%1"		"\n"
+	 "1:	mov	#0,r0"			"\n"
+	 "	mov.l	r0,@(%O3,gbr)";
 }
-  [(set_attr "length" "20")])
+  [(set_attr "length" "22")])
 
 (define_insn "atomic_nand_fetch<mode>_soft_imask"
-  [(set (match_operand:QIHISI 0 "register_operand" "=&z")
+  [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&z")
 	(not:QIHISI (and:QIHISI
-	  (mem:QIHISI (match_operand:SI 1 "register_operand" "r"))
-	  (match_operand:QIHISI 2 "register_operand" "r"))))
+	  (mem:QIHISI (match_operand:SI 1 "arith_reg_operand" "r"))
+	  (match_operand:QIHISI 2 "logical_operand" "rK08"))))
    (set (mem:QIHISI (match_dup 1))
 	(unspec:QIHISI
 	  [(not:QIHISI (and:QIHISI (mem:QIHISI (match_dup 1)) (match_dup 2)))]