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.
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"