diff mbox

[SH,committed] Use shorter atomic sequences if result values are unused

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

Commit Message

Oleg Endo Feb. 3, 2015, 8:35 p.m. UTC
Hi,

When the result values of atomic ops, such as the previous value of an
atomic_fetch_add, are unused, it's possible to use shorter asm sequences
on SH.  The attached patch does that by checking the reg unused notes of
the insns in split1 and replacing them with the simpler variants, if the
result value operand is unused.
This patch introduces a problem where memory aliasing info is lost,
because the mem operands are passed to the emitted insns not as such,
but only as the register holding the address.  This will be fixed with
PR 64661.

Committed as r220376.
Tested with make -k check-gcc RUNTESTFLAGS="sh.exp --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/splits actually work.  Will observe daily
sh4-linux test results for fallouts.

Cheers,
Oleg

gcc/ChangeLog:
	PR target/64660
	* config/sh/sync.md (atomic_<fetchop_name><mode>_hard,
	atomic_not<mode>_hard, atomic_<fetchop_name><mode>_soft_tcb,
	atomic_not<mode>_soft_tcb, atomic_nand<mode>_hard,
	atomic_nand<mode>_soft_tcb): New insns.
	(atomic_fetch_<fetchop_name>si_hard): Convert to insn_and_split.
	Split into atomic_<fetchop_name>_fetchsi_hard if operands[0] is unused.
	(define_insn "atomic_fetch_notsi_hard): Convert to insn_and_split.
	Split into atomic_not_fetchsi_hard if operands[0] is unused.
	(atomic_fetch_<fetchop_name><mode>_hard): Convert to insn_and_split.
	Split into atomic_<fetchop_name><mode>_hard if operands[0] is unused.
	(atomic_fetch_not<mode>_hard): Convert to insn_and_split.  Split into
	atomic_not<mode>_hard if operands[0] is unused.
	(atomic_fetch_<fetchop_name><mode>_soft_gusa): Convert to
	insn_and_split.  Split into atomic_<fetchop_name>_fetch<mode>_soft_gusa
	if operands[0] is unused.
	(atomic_fetch_not<mode>_soft_gusa): Convert to insn_and_split.  Split
	into atomic_not_fetch<mode>_soft_gusa if operands[0] is unused.
	(atomic_fetch_<fetchop_name><mode>_soft_tcb): Convert to insn_and_split.
	Split into atomic_<fetchop_name><mode>_soft_tcb if operands[0] is
	unused.
	(atomic_fetch_not<mode>_soft_tcb): Convert to insn_and_split.  Split
	into atomic_not<mode>_soft_tcb if operands[0] is unused.
	(atomic_fetch_<fetchop_name><mode>_soft_imask): Convert to
	insn_and_split.  Split into atomic_<fetchop_name>_fetch<mode>_soft_imask
	if operands[0] is unused.
	(atomic_fetch_not<mode>_soft_imask): Convert to insn_and_split.  Split
	into atomic_not_fetch<mode>_soft_imask is operands[0] is unused.
	(atomic_fetch_nandsi_hard): Convert to insn_and_split.  Split into
	atomic_nand_fetchsi_hard if operands[0] is unused.
	(atomic_fetch_nand<mode>_hard): Convert to insn_and_split.  Split into
	atomic_nand<mode>_hard if operands[0] is unused.
	(atomic_fetch_nand<mode>_soft_gusa): Convert to insn_and_split.  Split
	into atomic_nand_fetch<mode>_soft_gusa if operands[0] is unused.
	(atomic_fetch_nand<mode>_soft_tcb): Convert to insn_and_split.  Split
	into atomic_nand<mode>_soft_tcb if operands[0] is unused.
	(atomic_fetch_nand<mode>_soft_imask): Convert to insn_and_split.  Split
	into atomic_nand_fetch<mode>_soft_imask if operands[0] is unused.
	(atomic_<fetchop_name>_fetch<mode>_hard): Convert to insn_and_split.
	Split into atomic_<fetchop_name><mode>_hard if operands[0] is unused.
	(atomic_not_fetch<mode>_hard): Convert to insn_and_split.  Split into
	atomic_not<mode>_hard if operands[0] is unused.
	(atomic_<fetchop_name>_fetch<mode>_soft_tcb): Convert to insn_and_split.
	Split into atomic_<fetchop_name><mode>_soft_tcb if operands[0] is
	unused.
	(atomic_not_fetch<mode>_soft_tcb): Convert to insn_and_split.  Split
	into atomic_not<mode>_soft_tcb if operands[0] is unused.
	(atomic_nand_fetch<mode>_hard): Convert to insn_and_split.  Split into
	atomic_nand<mode>_hard if operands[0] is unused.
	(atomic_nand_fetch<mode>_soft_tcb): Convert to insn_and_split.  Split
	into atomic_nand<mode>_soft_tcb if operands[0] is unused.

gcc/testsuite/ChangeLog:
	PR target/64660
	* gcc.target/sh/pr64660-0.h: New.
	* gcc.target/sh/pr64660-1.c: New.
	* gcc.target/sh/pr64660-2.c: New.
	* gcc.target/sh/pr64660-3.c: New.
	* gcc.target/sh/pr64660-4.c: New.
diff mbox

Patch

Index: gcc/testsuite/gcc.target/sh/pr64660-2.c
===================================================================
--- gcc/testsuite/gcc.target/sh/pr64660-2.c	(revision 0)
+++ gcc/testsuite/gcc.target/sh/pr64660-2.c	(revision 0)
@@ -0,0 +1,13 @@ 
+/* Check that the appropriate atomic insns are used if the result values
+   are unused.  */
+/* { dg-do compile { target { atomic_model_soft_tcb_available } } }  */
+/* { dg-options "-dp -O2 -matomic-model=soft-tcb,gbr-offset=0,strict" }  */
+/* { dg-final { scan-assembler-times "atomic_add" 12 } }  */
+/* { dg-final { scan-assembler-times "atomic_and" 6 } }  */
+/* { dg-final { scan-assembler-times "atomic_or" 6 } }  */
+/* { dg-final { scan-assembler-times "atomic_xor" 6 } }  */
+/* { dg-final { scan-assembler-times "atomic_nand" 6 } }  */
+/* { dg-final { scan-assembler-times "atomic_not" 12 } }  */
+/* { dg-final { scan-assembler-not "fetch" } }  */
+
+#include "pr64660-0.h"
Index: gcc/testsuite/gcc.target/sh/pr64660-3.c
===================================================================
--- gcc/testsuite/gcc.target/sh/pr64660-3.c	(revision 0)
+++ gcc/testsuite/gcc.target/sh/pr64660-3.c	(revision 0)
@@ -0,0 +1,12 @@ 
+/* Check that the appropriate atomic insns are used if the result values
+   are unused.  */
+/* { dg-do compile { target { atomic_model_soft_imask_available } } }  */
+/* { dg-options "-dp -O2 -matomic-model=soft-imask,strict -mno-usermode" }  */
+/* { dg-final { scan-assembler-times "atomic_add_fetch" 12 } }  */
+/* { dg-final { scan-assembler-times "atomic_and_fetch" 6 } }  */
+/* { dg-final { scan-assembler-times "atomic_or_fetch" 6 } }  */
+/* { dg-final { scan-assembler-times "atomic_xor_fetch" 6 } }  */
+/* { dg-final { scan-assembler-times "atomic_nand_fetch" 6 } }  */
+/* { dg-final { scan-assembler-times "atomic_not_fetch" 12 } }  */
+
+#include "pr64660-0.h"
Index: gcc/testsuite/gcc.target/sh/pr64660-4.c
===================================================================
--- gcc/testsuite/gcc.target/sh/pr64660-4.c	(revision 0)
+++ gcc/testsuite/gcc.target/sh/pr64660-4.c	(revision 0)
@@ -0,0 +1,17 @@ 
+/* Check that atomic not ops are generated.  */
+/* { dg-do compile { target { atomic_model_hard_llcs_available } } }  */
+/* { dg-options "-dp -O2 -matomic-model=hard-llcs,strict" }  */
+/* { dg-final { scan-assembler-times "atomic_add" 12 } }  */
+/* { dg-final { scan-assembler-times "atomic_add_fetch" 4 } }  */
+/* { dg-final { scan-assembler-times "atomic_and" 6 } }  */
+/* { dg-final { scan-assembler-times "atomic_and_fetch" 2 } }  */
+/* { dg-final { scan-assembler-times "atomic_or" 6 } }  */
+/* { dg-final { scan-assembler-times "atomic_or_fetch" 2 } }  */
+/* { dg-final { scan-assembler-times "atomic_xor" 6 } }  */
+/* { dg-final { scan-assembler-times "atomic_xor_fetch" 2 } }  */
+/* { dg-final { scan-assembler-times "atomic_nand" 6 } }  */
+/* { dg-final { scan-assembler-times "atomic_nand_fetch" 2 } }  */
+/* { dg-final { scan-assembler-times "atomic_not" 12 } }  */
+/* { dg-final { scan-assembler-times "atomic_not_fetch" 4 } }  */
+
+#include "pr64660-0.h"
Index: gcc/testsuite/gcc.target/sh/pr64660-0.h
===================================================================
--- gcc/testsuite/gcc.target/sh/pr64660-0.h	(revision 0)
+++ gcc/testsuite/gcc.target/sh/pr64660-0.h	(revision 0)
@@ -0,0 +1,44 @@ 
+/* Check that the appropriate atomic insns are used if the result values
+   are unused.  */
+
+#define concat_1(x, y) x ## y
+#define concat(x, y) concat_1 (x, y)
+#define makefuncname(name) concat (concat (test_, __LINE__), name)
+
+#define emitfuncs(name,val)\
+  void makefuncname (_0) (char* mem)\
+  {\
+    name (mem, val, __ATOMIC_ACQ_REL);\
+  }\
+  void makefuncname (_1) (short* mem)\
+  {\
+    name (mem, val, __ATOMIC_ACQ_REL);\
+  }\
+  void makefuncname (_2) (int* mem)\
+  {\
+    name (mem, val, __ATOMIC_ACQ_REL);\
+  }\
+
+emitfuncs (__atomic_add_fetch, 1)
+emitfuncs (__atomic_fetch_add, 1)
+
+emitfuncs (__atomic_sub_fetch, 1)
+emitfuncs (__atomic_fetch_sub, 1)
+
+emitfuncs (__atomic_and_fetch, 1)
+emitfuncs (__atomic_fetch_and, 1)
+
+emitfuncs (__atomic_or_fetch, 1)
+emitfuncs (__atomic_fetch_or, 1)
+
+emitfuncs (__atomic_xor_fetch, 1)
+emitfuncs (__atomic_fetch_xor, 1)
+
+emitfuncs (__atomic_nand_fetch, 1)
+emitfuncs (__atomic_fetch_nand, 1)
+
+emitfuncs (__atomic_xor_fetch, -1)
+emitfuncs (__atomic_fetch_xor, -1)
+
+emitfuncs (__atomic_nand_fetch, -1)
+emitfuncs (__atomic_fetch_nand, -1)
Index: gcc/testsuite/gcc.target/sh/pr64660-1.c
===================================================================
--- gcc/testsuite/gcc.target/sh/pr64660-1.c	(revision 0)
+++ gcc/testsuite/gcc.target/sh/pr64660-1.c	(revision 0)
@@ -0,0 +1,12 @@ 
+/* Check that the appropriate atomic insns are used if the result values
+   are unused.  */
+/* { dg-do compile { target { atomic_model_soft_gusa_available } } }  */
+/* { dg-options "-dp -O2 -matomic-model=soft-gusa,strict" }  */
+/* { dg-final { scan-assembler-times "atomic_add_fetch" 12 } }  */
+/* { dg-final { scan-assembler-times "atomic_and_fetch" 6 } }  */
+/* { dg-final { scan-assembler-times "atomic_or_fetch" 6 } }  */
+/* { dg-final { scan-assembler-times "atomic_xor_fetch" 6 } }  */
+/* { dg-final { scan-assembler-times "atomic_nand_fetch" 6 } }  */
+/* { dg-final { scan-assembler-times "atomic_not_fetch" 12 } }  */
+
+#include "pr64660-0.h"
Index: gcc/config/sh/sync.md
===================================================================
--- gcc/config/sh/sync.md	(revision 220371)
+++ gcc/config/sh/sync.md	(working copy)
@@ -651,7 +651,7 @@ 
   DONE;
 })
 
-(define_insn "atomic_fetch_<fetchop_name>si_hard"
+(define_insn_and_split "atomic_fetch_<fetchop_name>si_hard"
   [(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))
@@ -671,10 +671,17 @@ 
 	 "	movco.l	r0,@%1"		"\n"
 	 "	bf	0b";
 }
+  "&& can_create_pseudo_p () && optimize
+   && sh_reg_dead_or_unused_after_insn (insn, REGNO (operands[0]))"
+  [(const_int 0)]
+{
+  emit_insn (gen_atomic_<fetchop_name>_fetchsi_hard (gen_reg_rtx (SImode),
+						     operands[1], operands[2]));
+}
   [(set_attr "length" "10")])
 
 ;; Combine pattern for xor (val, -1) / nand (val, -1).
-(define_insn "atomic_fetch_notsi_hard"
+(define_insn_and_split "atomic_fetch_notsi_hard"
   [(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))
@@ -690,9 +697,15 @@ 
 	 "	movco.l	r0,@%1"		"\n"
 	 "	bf	0b";
 }
+  "&& can_create_pseudo_p () && optimize
+   && sh_reg_dead_or_unused_after_insn (insn, REGNO (operands[0]))"
+  [(const_int 0)]
+{
+  emit_insn (gen_atomic_not_fetchsi_hard (gen_reg_rtx (SImode), operands[1]));
+}
   [(set_attr "length" "10")])
 
-(define_insn "atomic_fetch_<fetchop_name><mode>_hard"
+(define_insn_and_split "atomic_fetch_<fetchop_name><mode>_hard"
   [(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))
@@ -722,10 +735,45 @@ 
 	 "	movco.l	r0,@%3"			"\n"
 	 "	bf	0b";
 }
+  "&& can_create_pseudo_p () && optimize
+   && sh_reg_dead_or_unused_after_insn (insn, REGNO (operands[0]))"
+  [(const_int 0)]
+{
+  emit_insn (gen_atomic_<fetchop_name><mode>_hard (operands[1], operands[2]));
+}
   [(set_attr "length" "28")])
 
+(define_insn "atomic_<fetchop_name><mode>_hard"
+  [(set (mem:QIHI (match_operand:SI 0 "arith_reg_operand" "r"))
+	(unspec:QIHI
+	  [(FETCHOP:QIHI (mem:QIHI (match_dup 0))
+			 (match_operand:QIHI 1 "<fetchop_predicate_1>"
+					       "<fetchop_constraint_1_llcs>"))]
+	  UNSPEC_ATOMIC))
+   (set (reg:SI T_REG) (const_int 1))
+   (clobber (reg:SI R0_REG))
+   (clobber (match_scratch:SI 2 "=&r"))
+   (clobber (match_scratch:SI 3 "=0"))]
+  "TARGET_ATOMIC_HARD_LLCS"
+{
+  return "\r	mov	#-4,%2"			"\n"
+	 "	and	%0,%2"			"\n"
+	 "	xor	%2,%0"			"\n"
+	 "	add	r15,%0"			"\n"
+	 "	add	#-4,%0"			"\n"
+	 "0:	movli.l	@%2,r0"			"\n"
+	 "	mov.l	r0,@-r15"		"\n"
+	 "	mov.<bw>	@%0,r0"		"\n"
+	 "	<fetchop_name>	%1,r0"		"\n"
+	 "	mov.<bw>	r0,@%0"		"\n"
+	 "	mov.l	@r15+,r0"		"\n"
+	 "	movco.l	r0,@%2"			"\n"
+	 "	bf	0b";
+}
+  [(set_attr "length" "26")])
+
 ;; Combine pattern for xor (val, -1) / nand (val, -1).
-(define_insn "atomic_fetch_not<mode>_hard"
+(define_insn_and_split "atomic_fetch_not<mode>_hard"
   [(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))
@@ -750,9 +798,40 @@ 
 	 "	movco.l	r0,@%2"			"\n"
 	 "	bf	0b";
 }
+  "&& can_create_pseudo_p () && optimize
+   && sh_reg_dead_or_unused_after_insn (insn, REGNO (operands[0]))"
+  [(const_int 0)]
+{
+  emit_insn (gen_atomic_not<mode>_hard (operands[1]));
+}
   [(set_attr "length" "26")])
 
-(define_insn "atomic_fetch_<fetchop_name><mode>_soft_gusa"
+(define_insn "atomic_not<mode>_hard"
+  [(set (mem:QIHI (match_operand:SI 0 "arith_reg_operand" "r"))
+	(unspec:QIHI [(not:QIHI (mem:QIHI (match_dup 0)))] UNSPEC_ATOMIC))
+   (set (reg:SI T_REG) (const_int 1))
+   (clobber (reg:SI R0_REG))
+   (clobber (match_scratch:SI 1 "=&r"))
+   (clobber (match_scratch:SI 2 "=0"))]
+  "TARGET_ATOMIC_HARD_LLCS"
+{
+  return "\r	mov	#-4,%1"			"\n"
+	 "	and	%0,%1"			"\n"
+	 "	xor	%1,%0"			"\n"
+	 "	add	r15,%0"			"\n"
+	 "	add	#-4,%0"			"\n"
+	 "0:	movli.l	@%1,r0"			"\n"
+	 "	mov.l	r0,@-r15"		"\n"
+	 "	mov.<bw>	@%0,r0"		"\n"
+	 "	not	r0,r0"			"\n"
+	 "	mov.<bw>	r0,@%0"		"\n"
+	 "	mov.l	@r15+,r0"		"\n"
+	 "	movco.l	r0,@%1"			"\n"
+	 "	bf	0b";
+}
+  [(set_attr "length" "26")])
+
+(define_insn_and_split "atomic_fetch_<fetchop_name><mode>_soft_gusa"
   [(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))
@@ -777,10 +856,17 @@ 
 	 "	mov.<bwl>	%3,@%1"		"\n"
 	 "1:	mov	r1,r15";
 }
+  "&& can_create_pseudo_p () && optimize
+   && sh_reg_dead_or_unused_after_insn (insn, REGNO (operands[0]))"
+  [(const_int 0)]
+{
+  emit_insn (gen_atomic_<fetchop_name>_fetch<mode>_soft_gusa (
+		gen_reg_rtx (<MODE>mode), operands[1], operands[2]));
+}
   [(set_attr "length" "18")])
 
 ;; Combine pattern for xor (val, -1) / nand (val, -1).
-(define_insn "atomic_fetch_not<mode>_soft_gusa"
+(define_insn_and_split "atomic_fetch_not<mode>_soft_gusa"
   [(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))
@@ -799,9 +885,16 @@ 
 	 "	mov.<bwl>	%2,@%1"		"\n"
 	 "1:	mov	r1,r15";
 }
+  "&& can_create_pseudo_p () && optimize
+   && sh_reg_dead_or_unused_after_insn (insn, REGNO (operands[0]))"
+  [(const_int 0)]
+{
+  emit_insn (gen_atomic_not_fetch<mode>_soft_gusa (gen_reg_rtx (<MODE>mode),
+						   operands[1]));
+}
   [(set_attr "length" "16")])
 
-(define_insn "atomic_fetch_<fetchop_name><mode>_soft_tcb"
+(define_insn_and_split "atomic_fetch_<fetchop_name><mode>_soft_tcb"
   [(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))
@@ -827,10 +920,42 @@ 
 	 "1:	mov	#0,r0"			"\n"
 	 "	mov.l	r0,@(%O3,gbr)";
 }
+  "&& can_create_pseudo_p () && optimize
+   && sh_reg_dead_or_unused_after_insn (insn, REGNO (operands[0]))"
+  [(const_int 0)]
+{
+  emit_insn (gen_atomic_<fetchop_name><mode>_soft_tcb (
+					operands[1], operands[2], operands[3]));
+}
   [(set_attr "length" "20")])
 
+(define_insn "atomic_<fetchop_name><mode>_soft_tcb"
+  [(set (mem:QIHISI (match_operand:SI 0 "arith_reg_operand" "r"))
+	(unspec:QIHISI
+	  [(FETCHOP:QIHISI
+		(mem:QIHISI (match_dup 0))
+		(match_operand:QIHISI 1 "<fetchop_predicate_1>"
+					"<fetchop_constraint_1_tcb>"))]
+	  UNSPEC_ATOMIC))
+   (use (match_operand:SI 2 "gbr_displacement"))
+   (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.l	r0,@(%O2,gbr)"		"\n"
+	 "0:	mov.<bwl>	@%0,r0"		"\n"
+	 "	<fetchop_name>	%1,r0"		"\n"
+	 "	mov.<bwl>	r0,@%0"		"\n"
+	 "1:	mov	#0,r0"			"\n"
+	 "	mov.l	r0,@(%O2,gbr)";
+}
+  [(set_attr "length" "18")])
+
 ;; Combine pattern for xor (val, -1) / nand (val, -1).
-(define_insn "atomic_fetch_not<mode>_soft_tcb"
+(define_insn_and_split "atomic_fetch_not<mode>_soft_tcb"
   [(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))
@@ -851,9 +976,35 @@ 
 	 "1:	mov	#0,r0"			"\n"
 	 "	mov.l	r0,@(%O2,gbr)";
 }
+  "&& can_create_pseudo_p () && optimize
+   && sh_reg_dead_or_unused_after_insn (insn, REGNO (operands[0]))"
+  [(const_int 0)]
+{
+  emit_insn (gen_atomic_not<mode>_soft_tcb (operands[1], operands[2]));
+}
   [(set_attr "length" "20")])
 
-(define_insn "atomic_fetch_<fetchop_name><mode>_soft_imask"
+(define_insn "atomic_not<mode>_soft_tcb"
+  [(set (mem:QIHISI (match_operand:SI 0 "arith_reg_operand" "r"))
+	(unspec:QIHISI [(not:QIHISI (mem:QIHISI (match_dup 0)))] UNSPEC_ATOMIC))
+   (use (match_operand:SI 1 "gbr_displacement"))
+   (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.l	r0,@(%O1,gbr)"		"\n"
+	 "0:	mov.<bwl>	@%0,r0"		"\n"
+	 "	not	r0,r0"			"\n"
+	 "	mov.<bwl>	r0,@%0"		"\n"
+	 "1:	mov	#0,r0"			"\n"
+	 "	mov.l	r0,@(%O1,gbr)";
+}
+  [(set_attr "length" "18")])
+
+(define_insn_and_split "atomic_fetch_<fetchop_name><mode>_soft_imask"
   [(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))
@@ -877,10 +1028,17 @@ 
 	 "	mov.<bwl>	r0,@%1"		"\n"
 	 "	ldc	%3,sr";
 }
+  "&& can_create_pseudo_p () && optimize
+   && sh_reg_dead_or_unused_after_insn (insn, REGNO (operands[0]))"
+  [(const_int 0)]
+{
+  emit_insn (gen_atomic_<fetchop_name>_fetch<mode>_soft_imask (
+			gen_reg_rtx (<MODE>mode), operands[1], operands[2]));
+}
   [(set_attr "length" "18")])
 
 ;; Combine pattern for xor (val, -1) / nand (val, -1).
-(define_insn "atomic_fetch_not<mode>_soft_imask"
+(define_insn_and_split "atomic_fetch_not<mode>_soft_imask"
   [(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))
@@ -899,6 +1057,13 @@ 
 	 "	mov.<bwl>	r0,@%1"		"\n"
 	 "	ldc	%2,sr";
 }
+  "&& can_create_pseudo_p () && optimize
+   && sh_reg_dead_or_unused_after_insn (insn, REGNO (operands[0]))"
+  [(const_int 0)]
+{
+  emit_insn (gen_atomic_not_fetch<mode>_soft_imask (gen_reg_rtx (<MODE>mode),
+						    operands[1]));
+}
   [(set_attr "length" "18")])
 
 (define_expand "atomic_fetch_nand<mode>"
@@ -942,7 +1107,7 @@ 
   DONE;
 })
 
-(define_insn "atomic_fetch_nandsi_hard"
+(define_insn_and_split "atomic_fetch_nandsi_hard"
   [(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))
@@ -962,9 +1127,16 @@ 
 	 "	movco.l	r0,@%1"		"\n"
 	 "	bf	0b";
 }
+  "&& can_create_pseudo_p () && optimize
+   && sh_reg_dead_or_unused_after_insn (insn, REGNO (operands[0]))"
+  [(const_int 0)]
+{
+  emit_insn (gen_atomic_nand_fetchsi_hard (gen_reg_rtx (SImode), operands[1],
+					   operands[2]));
+}
   [(set_attr "length" "12")])
 
-(define_insn "atomic_fetch_nand<mode>_hard"
+(define_insn_and_split "atomic_fetch_nand<mode>_hard"
   [(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))
@@ -994,9 +1166,44 @@ 
 	 "	movco.l	r0,@%3"			"\n"
 	 "	bf	0b";
 }
+  "&& can_create_pseudo_p () && optimize
+   && sh_reg_dead_or_unused_after_insn (insn, REGNO (operands[0]))"
+  [(const_int 0)]
+{
+  emit_insn (gen_atomic_nand<mode>_hard (operands[1], operands[2]));
+}
   [(set_attr "length" "30")])
 
-(define_insn "atomic_fetch_nand<mode>_soft_gusa"
+(define_insn "atomic_nand<mode>_hard"
+  [(set (mem:QIHI (match_operand:SI 0 "arith_reg_operand" "r"))
+	(unspec:QIHI
+	  [(not:QIHI (and:QIHI (mem:QIHI (match_dup 0))
+		     (match_operand:QIHI 1 "logical_operand" "rK08")))]
+	  UNSPEC_ATOMIC))
+   (set (reg:SI T_REG) (const_int 1))
+   (clobber (reg:SI R0_REG))
+   (clobber (match_scratch:SI 2 "=&r"))
+   (clobber (match_scratch:SI 3 "=0"))]
+  "TARGET_ATOMIC_HARD_LLCS"
+{
+  return "\r	mov	#-4,%2"			"\n"
+	 "	and	%0,%2"			"\n"
+	 "	xor	%2,%0"			"\n"
+	 "	add	r15,%0"			"\n"
+	 "	add	#-4,%0"			"\n"
+	 "0:	movli.l	@%2,r0"			"\n"
+	 "	mov.l	r0,@-r15"		"\n"
+	 "	mov.<bw>	@%0,r0"		"\n"
+	 "	and	%1,r0"			"\n"
+	 "	not	r0,r0"			"\n"
+	 "	mov.<bw>	r0,@%0"		"\n"
+	 "	mov.l	@r15+,r0"		"\n"
+	 "	movco.l	r0,@%2"			"\n"
+	 "	bf	0b";
+}
+  [(set_attr "length" "28")])
+
+(define_insn_and_split "atomic_fetch_nand<mode>_soft_gusa"
   [(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))
@@ -1021,9 +1228,16 @@ 
 	 "	mov.<bwl>	%3,@%1"		"\n"
 	 "1:	mov	r1,r15";
 }
+  "&& can_create_pseudo_p () && optimize
+   && sh_reg_dead_or_unused_after_insn (insn, REGNO (operands[0]))"
+  [(const_int 0)]
+{
+  emit_insn (gen_atomic_nand_fetch<mode>_soft_gusa (gen_reg_rtx (<MODE>mode),
+						    operands[1], operands[2]));
+}
   [(set_attr "length" "20")])
 
-(define_insn "atomic_fetch_nand<mode>_soft_tcb"
+(define_insn_and_split "atomic_fetch_nand<mode>_soft_tcb"
   [(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))
@@ -1049,9 +1263,41 @@ 
 	 "1:	mov	#0,r0"			"\n"
 	 "	mov.l	r0,@(%O3,gbr)";
 }
+  "&& can_create_pseudo_p () && optimize
+   && sh_reg_dead_or_unused_after_insn (insn, REGNO (operands[0]))"
+  [(const_int 0)]
+{
+  emit_insn (gen_atomic_nand<mode>_soft_tcb (operands[1], operands[2],
+					     operands[3]));
+}
   [(set_attr "length" "22")])
 
-(define_insn "atomic_fetch_nand<mode>_soft_imask"
+(define_insn "atomic_nand<mode>_soft_tcb"
+  [(set (mem:QIHISI (match_operand:SI 0 "arith_reg_operand" "r"))
+	(unspec:QIHISI
+	  [(not:QIHISI
+	     (and:QIHISI (mem:QIHISI (match_dup 0))
+			 (match_operand:QIHISI 1 "logical_operand" "rK08")))]
+	  UNSPEC_ATOMIC))
+   (use (match_operand:SI 2 "gbr_displacement"))
+   (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"
+	 "	mov.l	r0,@(%O2,gbr)"		"\n"
+	 "0:	mov.<bwl>	@%0,r0"		"\n"
+	 "	and	%1,r0"			"\n"
+	 "	not	r0,r0"			"\n"
+	 "	mov.<bwl>	r0,@%0"		"\n"
+	 "1:	mov	#0,r0"			"\n"
+	 "	mov.l	r0,@(%O2,gbr)";
+}
+  [(set_attr "length" "20")])
+
+(define_insn_and_split "atomic_fetch_nand<mode>_soft_imask"
   [(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))
@@ -1075,6 +1321,13 @@ 
 	 "	mov.<bwl>	r0,@%1"		"\n"
 	 "	ldc	%3,sr";
 }
+  "&& can_create_pseudo_p () && optimize
+   && sh_reg_dead_or_unused_after_insn (insn, REGNO (operands[0]))"
+  [(const_int 0)]
+{
+  emit_insn (gen_atomic_nand_fetch<mode>_soft_imask (gen_reg_rtx (<MODE>mode),
+						     operands[1], operands[2]));
+}
   [(set_attr "length" "20")])
 
 ;;------------------------------------------------------------------------------
@@ -1160,7 +1413,7 @@ 
 }
   [(set_attr "length" "8")])
 
-(define_insn "atomic_<fetchop_name>_fetch<mode>_hard"
+(define_insn_and_split "atomic_<fetchop_name>_fetch<mode>_hard"
   [(set (match_operand:QIHI 0 "arith_reg_dest" "=&r")
 	(FETCHOP:QIHI
 	  (mem:QIHI (match_operand:SI 1 "arith_reg_operand" "r"))
@@ -1191,10 +1444,16 @@ 
 	 "	movco.l	r0,@%3"			"\n"
 	 "	bf	0b";
 }
+  "&& can_create_pseudo_p () && optimize
+   && sh_reg_dead_or_unused_after_insn (insn, REGNO (operands[0]))"
+  [(const_int 0)]
+{
+  emit_insn (gen_atomic_<fetchop_name><mode>_hard (operands[1], operands[2]));
+}
   [(set_attr "length" "28")])
 
 ;; Combine pattern for xor (val, -1) / nand (val, -1).
-(define_insn "atomic_not_fetch<mode>_hard"
+(define_insn_and_split "atomic_not_fetch<mode>_hard"
   [(set (match_operand:QIHI 0 "arith_reg_dest" "=&r")
 	(not:QIHI (mem:QIHI (match_operand:SI 1 "arith_reg_operand" "r"))))
    (set (mem:QIHI (match_dup 1))
@@ -1220,6 +1479,12 @@ 
 	 "	movco.l	r0,@%2"			"\n"
 	 "	bf	0b";
 }
+  "&& can_create_pseudo_p () && optimize
+   && sh_reg_dead_or_unused_after_insn (insn, REGNO (operands[0]))"
+  [(const_int 0)]
+{
+  emit_insn (gen_atomic_not<mode>_hard (operands[1]));
+}
   [(set_attr "length" "28")])
 
 (define_insn "atomic_<fetchop_name>_fetch<mode>_soft_gusa"
@@ -1268,7 +1533,7 @@ 
 }
   [(set_attr "length" "16")])
 
-(define_insn "atomic_<fetchop_name>_fetch<mode>_soft_tcb"
+(define_insn_and_split "atomic_<fetchop_name>_fetch<mode>_soft_tcb"
   [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&r")
 	(FETCHOP:QIHISI
 	  (mem:QIHISI (match_operand:SI 1 "arith_reg_operand" "r"))
@@ -1294,10 +1559,17 @@ 
 	 "	mov	#0,r0"			"\n"
 	 "	mov.l	r0,@(%O3,gbr)";
 }
+  "&& can_create_pseudo_p () && optimize
+   && sh_reg_dead_or_unused_after_insn (insn, REGNO (operands[0]))"
+  [(const_int 0)]
+{
+  emit_insn (gen_atomic_<fetchop_name><mode>_soft_tcb (
+				operands[1], operands[2], operands[3]));
+}
   [(set_attr "length" "20")])
 
 ;; Combine pattern for xor (val, -1) / nand (val, -1).
-(define_insn "atomic_not_fetch<mode>_soft_tcb"
+(define_insn_and_split "atomic_not_fetch<mode>_soft_tcb"
   [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&r")
 	(not:QIHISI (mem:QIHISI (match_operand:SI 1 "arith_reg_operand" "r"))))
    (set (mem:QIHISI (match_dup 1))
@@ -1318,6 +1590,12 @@ 
 	 "	mov	#0,r0"			"\n"
 	 "	mov.l	r0,@(%O2,gbr)";
 }
+  "&& can_create_pseudo_p () && optimize
+   && sh_reg_dead_or_unused_after_insn (insn, REGNO (operands[0]))"
+  [(const_int 0)]
+{
+  emit_insn (gen_atomic_not<mode>_soft_tcb (operands[1], operands[2]));
+}
   [(set_attr "length" "20")])
 
 (define_insn "atomic_<fetchop_name>_fetch<mode>_soft_imask"
@@ -1426,7 +1704,7 @@ 
 }
   [(set_attr "length" "10")])
 
-(define_insn "atomic_nand_fetch<mode>_hard"
+(define_insn_and_split "atomic_nand_fetch<mode>_hard"
   [(set (match_operand:QIHI 0 "arith_reg_dest" "=&r")
 	(not:QIHI
 	  (and:QIHI (mem:QIHI (match_operand:SI 1 "arith_reg_operand" "r"))
@@ -1456,6 +1734,12 @@ 
 	 "	movco.l	r0,@%3"			"\n"
 	 "	bf	0b";
 }
+  "&& can_create_pseudo_p () && optimize
+   && sh_reg_dead_or_unused_after_insn (insn, REGNO (operands[0]))"
+  [(const_int 0)]
+{
+  emit_insn (gen_atomic_nand<mode>_hard (operands[1], operands[2]));
+}
   [(set_attr "length" "28")])
 
 (define_insn "atomic_nand_fetch<mode>_soft_gusa"
@@ -1483,7 +1767,7 @@ 
 }
   [(set_attr "length" "18")])
 
-(define_insn "atomic_nand_fetch<mode>_soft_tcb"
+(define_insn_and_split "atomic_nand_fetch<mode>_soft_tcb"
   [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&r")
 	(not:QIHISI (and:QIHISI
 	  (mem:QIHISI (match_operand:SI 1 "arith_reg_operand" "r"))
@@ -1509,6 +1793,13 @@ 
 	 "1:	mov	#0,r0"			"\n"
 	 "	mov.l	r0,@(%O3,gbr)";
 }
+  "&& can_create_pseudo_p () && optimize
+   && sh_reg_dead_or_unused_after_insn (insn, REGNO (operands[0]))"
+  [(const_int 0)]
+{
+  emit_insn (gen_atomic_nand<mode>_soft_tcb (operands[1], operands[2],
+					     operands[3]));
+}
   [(set_attr "length" "22")])
 
 (define_insn "atomic_nand_fetch<mode>_soft_imask"