summaryrefslogtreecommitdiff
path: root/gcc/config/arm/sync.md
diff options
context:
space:
mode:
authorramana <ramana@138bc75d-0d04-0410-961f-82ee72b054a4>2010-08-18 08:25:33 +0000
committerramana <ramana@138bc75d-0d04-0410-961f-82ee72b054a4>2010-08-18 08:25:33 +0000
commit06df6b178d3f0777243244b847004e5c1292e3f0 (patch)
treeabb90a18a297a681918852c397794998d5918643 /gcc/config/arm/sync.md
parent2cda520abcf9bcadf20415fb5566b9030495aa71 (diff)
downloadgcc-06df6b178d3f0777243244b847004e5c1292e3f0.tar.gz
For Marcus - Implement sync primitives inline for ARM.
2010-08-18 Marcus Shawcroft <marcus.shawcroft@arm.com> * config/arm/arm-protos.h (arm_expand_sync): New. (arm_output_memory_barrier, arm_output_sync_insn): New. (arm_sync_loop_insns): New. * config/arm/arm.c (FL_ARCH7): New. (FL_FOR_ARCH7): Include FL_ARCH7. (arm_arch7): New. (arm_print_operand): Support %C markup. (arm_legitimize_sync_memory): New. (arm_emit, arm_insn_count, arm_count, arm_output_asm_insn): New. (arm_process_output_memory_barrier, arm_output_memory_barrier): New. (arm_ldrex_suffix, arm_output_ldrex, arm_output_strex): New. (arm_output_op2, arm_output_op3, arm_output_sync_loop): New. (arm_get_sync_operand, FETCH_SYNC_OPERAND): New. (arm_process_output_sync_insn, arm_output_sync_insn): New. (arm_sync_loop_insns,arm_call_generator, arm_expand_sync): New. * config/arm/arm.h (struct arm_sync_generator): New. (TARGET_HAVE_DMB, TARGET_HAVE_DMB_MCR): New. (TARGET_HAVE_MEMORY_BARRIER): New. (TARGET_HAVE_LDREX, TARGET_HAVE_LDREXBHD): New. * config/arm/arm.md: Include sync.md. (UNSPEC_MEMORY_BARRIER): New. (VUNSPEC_SYNC_COMPARE_AND_SWAP, VUNSPEC_SYNC_LOCK): New. (VUNSPEC_SYNC_OP):New. (VUNSPEC_SYNC_NEW_OP, VUNSPEC_SYNC_OLD_OP): New. (sync_result, sync_memory, sync_required_value): New attributes. (sync_new_value, sync_t1, sync_t2): Likewise. (sync_release_barrier, sync_op): Likewise. (length): Add logic to length attribute defintion to call arm_sync_loop_insns when appropriate. * config/arm/sync.md: New file. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@163327 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/config/arm/sync.md')
-rw-r--r--gcc/config/arm/sync.md594
1 files changed, 594 insertions, 0 deletions
diff --git a/gcc/config/arm/sync.md b/gcc/config/arm/sync.md
new file mode 100644
index 00000000000..7fd38d75484
--- /dev/null
+++ b/gcc/config/arm/sync.md
@@ -0,0 +1,594 @@
+;; Machine description for ARM processor synchronization primitives.
+;; Copyright (C) 2010 Free Software Foundation, Inc.
+;; Written by Marcus Shawcroft (marcus.shawcroft@arm.com)
+;;
+;; This file is part of GCC.
+;;
+;; GCC is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; GCC is distributed in the hope that it will be useful, but
+;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+;; General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with GCC; see the file COPYING3. If not see
+;; <http://www.gnu.org/licenses/>. */
+
+;; ARMV6 introduced ldrex and strex instruction. These instruction
+;; access SI width data. In order to implement synchronization
+;; primitives for the narrower QI and HI modes we insert appropriate
+;; AND/OR sequences into the synchronization loop to mask out the
+;; relevant component of an SI access.
+
+(define_expand "memory_barrier"
+ [(set (match_dup 0)
+ (unspec:BLK [(match_dup 0)] UNSPEC_MEMORY_BARRIER))]
+ "TARGET_HAVE_MEMORY_BARRIER"
+{
+ operands[0] = gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (Pmode));
+ MEM_VOLATILE_P (operands[0]) = 1;
+})
+
+(define_expand "sync_compare_and_swapsi"
+ [(set (match_operand:SI 0 "s_register_operand")
+ (unspec_volatile:SI [(match_operand:SI 1 "memory_operand")
+ (match_operand:SI 2 "s_register_operand")
+ (match_operand:SI 3 "s_register_operand")]
+ VUNSPEC_SYNC_COMPARE_AND_SWAP))]
+ "TARGET_HAVE_LDREX && TARGET_HAVE_MEMORY_BARRIER"
+ {
+ struct arm_sync_generator generator;
+ generator.op = arm_sync_generator_omrn;
+ generator.u.omrn = gen_arm_sync_compare_and_swapsi;
+ arm_expand_sync (SImode, &generator, operands[0], operands[1], operands[2],
+ operands[3]);
+ DONE;
+ })
+
+(define_mode_iterator NARROW [QI HI])
+
+(define_expand "sync_compare_and_swap<mode>"
+ [(set (match_operand:NARROW 0 "s_register_operand")
+ (unspec_volatile:NARROW [(match_operand:NARROW 1 "memory_operand")
+ (match_operand:NARROW 2 "s_register_operand")
+ (match_operand:NARROW 3 "s_register_operand")]
+ VUNSPEC_SYNC_COMPARE_AND_SWAP))]
+ "TARGET_HAVE_LDREXBHD && TARGET_HAVE_MEMORY_BARRIER"
+ {
+ struct arm_sync_generator generator;
+ generator.op = arm_sync_generator_omrn;
+ generator.u.omrn = gen_arm_sync_compare_and_swap<mode>;
+ arm_expand_sync (<MODE>mode, &generator, operands[0], operands[1],
+ operands[2], operands[3]);
+ DONE;
+ })
+
+(define_expand "sync_lock_test_and_setsi"
+ [(match_operand:SI 0 "s_register_operand")
+ (match_operand:SI 1 "memory_operand")
+ (match_operand:SI 2 "s_register_operand")]
+ "TARGET_HAVE_LDREX && TARGET_HAVE_MEMORY_BARRIER"
+ {
+ struct arm_sync_generator generator;
+ generator.op = arm_sync_generator_omn;
+ generator.u.omn = gen_arm_sync_lock_test_and_setsi;
+ arm_expand_sync (SImode, &generator, operands[0], operands[1], NULL,
+ operands[2]);
+ DONE;
+ })
+
+(define_expand "sync_lock_test_and_set<mode>"
+ [(match_operand:NARROW 0 "s_register_operand")
+ (match_operand:NARROW 1 "memory_operand")
+ (match_operand:NARROW 2 "s_register_operand")]
+ "TARGET_HAVE_LDREXBHD && TARGET_HAVE_MEMORY_BARRIER"
+ {
+ struct arm_sync_generator generator;
+ generator.op = arm_sync_generator_omn;
+ generator.u.omn = gen_arm_sync_lock_test_and_set<mode>;
+ arm_expand_sync (<MODE>mode, &generator, operands[0], operands[1], NULL,
+ operands[2]);
+ DONE;
+ })
+
+(define_code_iterator syncop [plus minus ior xor and])
+
+(define_code_attr sync_optab [(ior "ior")
+ (xor "xor")
+ (and "and")
+ (plus "add")
+ (minus "sub")])
+
+(define_expand "sync_<sync_optab>si"
+ [(match_operand:SI 0 "memory_operand")
+ (match_operand:SI 1 "s_register_operand")
+ (syncop:SI (match_dup 0) (match_dup 1))]
+ "TARGET_HAVE_LDREX && TARGET_HAVE_MEMORY_BARRIER"
+ {
+ struct arm_sync_generator generator;
+ generator.op = arm_sync_generator_omn;
+ generator.u.omn = gen_arm_sync_new_<sync_optab>si;
+ arm_expand_sync (SImode, &generator, NULL, operands[0], NULL, operands[1]);
+ DONE;
+ })
+
+(define_expand "sync_nandsi"
+ [(match_operand:SI 0 "memory_operand")
+ (match_operand:SI 1 "s_register_operand")
+ (not:SI (and:SI (match_dup 0) (match_dup 1)))]
+ "TARGET_HAVE_LDREX && TARGET_HAVE_MEMORY_BARRIER"
+ {
+ struct arm_sync_generator generator;
+ generator.op = arm_sync_generator_omn;
+ generator.u.omn = gen_arm_sync_new_nandsi;
+ arm_expand_sync (SImode, &generator, NULL, operands[0], NULL, operands[1]);
+ DONE;
+ })
+
+(define_expand "sync_<sync_optab><mode>"
+ [(match_operand:NARROW 0 "memory_operand")
+ (match_operand:NARROW 1 "s_register_operand")
+ (syncop:NARROW (match_dup 0) (match_dup 1))]
+ "TARGET_HAVE_LDREXBHD && TARGET_HAVE_MEMORY_BARRIER"
+ {
+ struct arm_sync_generator generator;
+ generator.op = arm_sync_generator_omn;
+ generator.u.omn = gen_arm_sync_new_<sync_optab><mode>;
+ arm_expand_sync (<MODE>mode, &generator, NULL, operands[0], NULL,
+ operands[1]);
+ DONE;
+ })
+
+(define_expand "sync_nand<mode>"
+ [(match_operand:NARROW 0 "memory_operand")
+ (match_operand:NARROW 1 "s_register_operand")
+ (not:NARROW (and:NARROW (match_dup 0) (match_dup 1)))]
+ "TARGET_HAVE_LDREXBHD && TARGET_HAVE_MEMORY_BARRIER"
+ {
+ struct arm_sync_generator generator;
+ generator.op = arm_sync_generator_omn;
+ generator.u.omn = gen_arm_sync_new_nand<mode>;
+ arm_expand_sync (<MODE>mode, &generator, NULL, operands[0], NULL,
+ operands[1]);
+ DONE;
+ })
+
+(define_expand "sync_new_<sync_optab>si"
+ [(match_operand:SI 0 "s_register_operand")
+ (match_operand:SI 1 "memory_operand")
+ (match_operand:SI 2 "s_register_operand")
+ (syncop:SI (match_dup 1) (match_dup 2))]
+ "TARGET_HAVE_LDREX && TARGET_HAVE_MEMORY_BARRIER"
+ {
+ struct arm_sync_generator generator;
+ generator.op = arm_sync_generator_omn;
+ generator.u.omn = gen_arm_sync_new_<sync_optab>si;
+ arm_expand_sync (SImode, &generator, operands[0], operands[1], NULL,
+ operands[2]);
+ DONE;
+ })
+
+(define_expand "sync_new_nandsi"
+ [(match_operand:SI 0 "s_register_operand")
+ (match_operand:SI 1 "memory_operand")
+ (match_operand:SI 2 "s_register_operand")
+ (not:SI (and:SI (match_dup 1) (match_dup 2)))]
+ "TARGET_HAVE_LDREX && TARGET_HAVE_MEMORY_BARRIER"
+ {
+ struct arm_sync_generator generator;
+ generator.op = arm_sync_generator_omn;
+ generator.u.omn = gen_arm_sync_new_nandsi;
+ arm_expand_sync (SImode, &generator, operands[0], operands[1], NULL,
+ operands[2]);
+ DONE;
+ })
+
+(define_expand "sync_new_<sync_optab><mode>"
+ [(match_operand:NARROW 0 "s_register_operand")
+ (match_operand:NARROW 1 "memory_operand")
+ (match_operand:NARROW 2 "s_register_operand")
+ (syncop:NARROW (match_dup 1) (match_dup 2))]
+ "TARGET_HAVE_LDREXBHD && TARGET_HAVE_MEMORY_BARRIER"
+ {
+ struct arm_sync_generator generator;
+ generator.op = arm_sync_generator_omn;
+ generator.u.omn = gen_arm_sync_new_<sync_optab><mode>;
+ arm_expand_sync (<MODE>mode, &generator, operands[0], operands[1],
+ NULL, operands[2]);
+ DONE;
+ })
+
+(define_expand "sync_new_nand<mode>"
+ [(match_operand:NARROW 0 "s_register_operand")
+ (match_operand:NARROW 1 "memory_operand")
+ (match_operand:NARROW 2 "s_register_operand")
+ (not:NARROW (and:NARROW (match_dup 1) (match_dup 2)))]
+ "TARGET_HAVE_LDREXBHD && TARGET_HAVE_MEMORY_BARRIER"
+ {
+ struct arm_sync_generator generator;
+ generator.op = arm_sync_generator_omn;
+ generator.u.omn = gen_arm_sync_new_nand<mode>;
+ arm_expand_sync (<MODE>mode, &generator, operands[0], operands[1],
+ NULL, operands[2]);
+ DONE;
+ });
+
+(define_expand "sync_old_<sync_optab>si"
+ [(match_operand:SI 0 "s_register_operand")
+ (match_operand:SI 1 "memory_operand")
+ (match_operand:SI 2 "s_register_operand")
+ (syncop:SI (match_dup 1) (match_dup 2))]
+ "TARGET_HAVE_LDREX && TARGET_HAVE_MEMORY_BARRIER"
+ {
+ struct arm_sync_generator generator;
+ generator.op = arm_sync_generator_omn;
+ generator.u.omn = gen_arm_sync_old_<sync_optab>si;
+ arm_expand_sync (SImode, &generator, operands[0], operands[1], NULL,
+ operands[2]);
+ DONE;
+ })
+
+(define_expand "sync_old_nandsi"
+ [(match_operand:SI 0 "s_register_operand")
+ (match_operand:SI 1 "memory_operand")
+ (match_operand:SI 2 "s_register_operand")
+ (not:SI (and:SI (match_dup 1) (match_dup 2)))]
+ "TARGET_HAVE_LDREX && TARGET_HAVE_MEMORY_BARRIER"
+ {
+ struct arm_sync_generator generator;
+ generator.op = arm_sync_generator_omn;
+ generator.u.omn = gen_arm_sync_old_nandsi;
+ arm_expand_sync (SImode, &generator, operands[0], operands[1], NULL,
+ operands[2]);
+ DONE;
+ })
+
+(define_expand "sync_old_<sync_optab><mode>"
+ [(match_operand:NARROW 0 "s_register_operand")
+ (match_operand:NARROW 1 "memory_operand")
+ (match_operand:NARROW 2 "s_register_operand")
+ (syncop:NARROW (match_dup 1) (match_dup 2))]
+ "TARGET_HAVE_LDREXBHD && TARGET_HAVE_MEMORY_BARRIER"
+ {
+ struct arm_sync_generator generator;
+ generator.op = arm_sync_generator_omn;
+ generator.u.omn = gen_arm_sync_old_<sync_optab><mode>;
+ arm_expand_sync (<MODE>mode, &generator, operands[0], operands[1],
+ NULL, operands[2]);
+ DONE;
+ })
+
+(define_expand "sync_old_nand<mode>"
+ [(match_operand:NARROW 0 "s_register_operand")
+ (match_operand:NARROW 1 "memory_operand")
+ (match_operand:NARROW 2 "s_register_operand")
+ (not:NARROW (and:NARROW (match_dup 1) (match_dup 2)))]
+ "TARGET_HAVE_LDREXBHD && TARGET_HAVE_MEMORY_BARRIER"
+ {
+ struct arm_sync_generator generator;
+ generator.op = arm_sync_generator_omn;
+ generator.u.omn = gen_arm_sync_old_nand<mode>;
+ arm_expand_sync (<MODE>mode, &generator, operands[0], operands[1],
+ NULL, operands[2]);
+ DONE;
+ })
+
+(define_insn "arm_sync_compare_and_swapsi"
+ [(set (match_operand:SI 0 "s_register_operand" "=&r")
+ (unspec_volatile:SI
+ [(match_operand:SI 1 "memory_operand" "+m")
+ (match_operand:SI 2 "s_register_operand" "r")
+ (match_operand:SI 3 "s_register_operand" "r")]
+ VUNSPEC_SYNC_COMPARE_AND_SWAP))
+ (set (match_dup 1) (unspec_volatile:SI [(match_dup 2)]
+ VUNSPEC_SYNC_COMPARE_AND_SWAP))
+ (clobber:SI (match_scratch:SI 4 "=&r"))
+ (set (reg:CC CC_REGNUM) (unspec_volatile:CC [(match_dup 1)]
+ VUNSPEC_SYNC_COMPARE_AND_SWAP))
+ ]
+ "TARGET_HAVE_LDREX && TARGET_HAVE_MEMORY_BARRIER"
+ {
+ return arm_output_sync_insn (insn, operands);
+ }
+ [(set_attr "sync_result" "0")
+ (set_attr "sync_memory" "1")
+ (set_attr "sync_required_value" "2")
+ (set_attr "sync_new_value" "3")
+ (set_attr "sync_t1" "0")
+ (set_attr "sync_t2" "4")
+ (set_attr "conds" "nocond")
+ (set_attr "predicable" "no")])
+
+(define_insn "arm_sync_compare_and_swap<mode>"
+ [(set (match_operand:SI 0 "s_register_operand" "=&r")
+ (zero_extend:SI
+ (unspec_volatile:NARROW
+ [(match_operand:NARROW 1 "memory_operand" "+m")
+ (match_operand:SI 2 "s_register_operand" "r")
+ (match_operand:SI 3 "s_register_operand" "r")]
+ VUNSPEC_SYNC_COMPARE_AND_SWAP)))
+ (set (match_dup 1) (unspec_volatile:NARROW [(match_dup 2)]
+ VUNSPEC_SYNC_COMPARE_AND_SWAP))
+ (clobber:SI (match_scratch:SI 4 "=&r"))
+ (set (reg:CC CC_REGNUM) (unspec_volatile:CC [(match_dup 1)]
+ VUNSPEC_SYNC_COMPARE_AND_SWAP))
+ ]
+ "TARGET_HAVE_LDREXBHD && TARGET_HAVE_MEMORY_BARRIER"
+ {
+ return arm_output_sync_insn (insn, operands);
+ }
+ [(set_attr "sync_result" "0")
+ (set_attr "sync_memory" "1")
+ (set_attr "sync_required_value" "2")
+ (set_attr "sync_new_value" "3")
+ (set_attr "sync_t1" "0")
+ (set_attr "sync_t2" "4")
+ (set_attr "conds" "nocond")
+ (set_attr "predicable" "no")])
+
+(define_insn "arm_sync_lock_test_and_setsi"
+ [(set (match_operand:SI 0 "s_register_operand" "=&r")
+ (match_operand:SI 1 "memory_operand" "+m"))
+ (set (match_dup 1)
+ (unspec_volatile:SI [(match_operand:SI 2 "s_register_operand" "r")]
+ VUNSPEC_SYNC_LOCK))
+ (clobber (reg:CC CC_REGNUM))
+ (clobber (match_scratch:SI 3 "=&r"))]
+ "TARGET_HAVE_LDREX && TARGET_HAVE_MEMORY_BARRIER"
+ {
+ return arm_output_sync_insn (insn, operands);
+ }
+ [(set_attr "sync_release_barrier" "no")
+ (set_attr "sync_result" "0")
+ (set_attr "sync_memory" "1")
+ (set_attr "sync_new_value" "2")
+ (set_attr "sync_t1" "0")
+ (set_attr "sync_t2" "3")
+ (set_attr "conds" "nocond")
+ (set_attr "predicable" "no")])
+
+(define_insn "arm_sync_lock_test_and_set<mode>"
+ [(set (match_operand:SI 0 "s_register_operand" "=&r")
+ (zero_extend:SI (match_operand:NARROW 1 "memory_operand" "+m")))
+ (set (match_dup 1)
+ (unspec_volatile:NARROW [(match_operand:SI 2 "s_register_operand" "r")]
+ VUNSPEC_SYNC_LOCK))
+ (clobber (reg:CC CC_REGNUM))
+ (clobber (match_scratch:SI 3 "=&r"))]
+ "TARGET_HAVE_LDREX && TARGET_HAVE_MEMORY_BARRIER"
+ {
+ return arm_output_sync_insn (insn, operands);
+ }
+ [(set_attr "sync_release_barrier" "no")
+ (set_attr "sync_result" "0")
+ (set_attr "sync_memory" "1")
+ (set_attr "sync_new_value" "2")
+ (set_attr "sync_t1" "0")
+ (set_attr "sync_t2" "3")
+ (set_attr "conds" "nocond")
+ (set_attr "predicable" "no")])
+
+(define_insn "arm_sync_new_<sync_optab>si"
+ [(set (match_operand:SI 0 "s_register_operand" "=&r")
+ (unspec_volatile:SI [(syncop:SI
+ (match_operand:SI 1 "memory_operand" "+m")
+ (match_operand:SI 2 "s_register_operand" "r"))
+ ]
+ VUNSPEC_SYNC_NEW_OP))
+ (set (match_dup 1)
+ (unspec_volatile:SI [(match_dup 1) (match_dup 2)]
+ VUNSPEC_SYNC_NEW_OP))
+ (clobber (reg:CC CC_REGNUM))
+ (clobber (match_scratch:SI 3 "=&r"))]
+ "TARGET_HAVE_LDREX && TARGET_HAVE_MEMORY_BARRIER"
+ {
+ return arm_output_sync_insn (insn, operands);
+ }
+ [(set_attr "sync_result" "0")
+ (set_attr "sync_memory" "1")
+ (set_attr "sync_new_value" "2")
+ (set_attr "sync_t1" "0")
+ (set_attr "sync_t2" "3")
+ (set_attr "sync_op" "<sync_optab>")
+ (set_attr "conds" "nocond")
+ (set_attr "predicable" "no")])
+
+(define_insn "arm_sync_new_nandsi"
+ [(set (match_operand:SI 0 "s_register_operand" "=&r")
+ (unspec_volatile:SI [(not:SI (and:SI
+ (match_operand:SI 1 "memory_operand" "+m")
+ (match_operand:SI 2 "s_register_operand" "r")))
+ ]
+ VUNSPEC_SYNC_NEW_OP))
+ (set (match_dup 1)
+ (unspec_volatile:SI [(match_dup 1) (match_dup 2)]
+ VUNSPEC_SYNC_NEW_OP))
+ (clobber (reg:CC CC_REGNUM))
+ (clobber (match_scratch:SI 3 "=&r"))]
+ "TARGET_HAVE_LDREX && TARGET_HAVE_MEMORY_BARRIER"
+ {
+ return arm_output_sync_insn (insn, operands);
+ }
+ [(set_attr "sync_result" "0")
+ (set_attr "sync_memory" "1")
+ (set_attr "sync_new_value" "2")
+ (set_attr "sync_t1" "0")
+ (set_attr "sync_t2" "3")
+ (set_attr "sync_op" "nand")
+ (set_attr "conds" "nocond")
+ (set_attr "predicable" "no")])
+
+(define_insn "arm_sync_new_<sync_optab><mode>"
+ [(set (match_operand:SI 0 "s_register_operand" "=&r")
+ (unspec_volatile:SI [(syncop:SI
+ (zero_extend:SI
+ (match_operand:NARROW 1 "memory_operand" "+m"))
+ (match_operand:SI 2 "s_register_operand" "r"))
+ ]
+ VUNSPEC_SYNC_NEW_OP))
+ (set (match_dup 1)
+ (unspec_volatile:NARROW [(match_dup 1) (match_dup 2)]
+ VUNSPEC_SYNC_NEW_OP))
+ (clobber (reg:CC CC_REGNUM))
+ (clobber (match_scratch:SI 3 "=&r"))]
+ "TARGET_HAVE_LDREXBHD && TARGET_HAVE_MEMORY_BARRIER"
+ {
+ return arm_output_sync_insn (insn, operands);
+ }
+ [(set_attr "sync_result" "0")
+ (set_attr "sync_memory" "1")
+ (set_attr "sync_new_value" "2")
+ (set_attr "sync_t1" "0")
+ (set_attr "sync_t2" "3")
+ (set_attr "sync_op" "<sync_optab>")
+ (set_attr "conds" "nocond")
+ (set_attr "predicable" "no")])
+
+(define_insn "arm_sync_new_nand<mode>"
+ [(set (match_operand:SI 0 "s_register_operand" "=&r")
+ (unspec_volatile:SI
+ [(not:SI
+ (and:SI
+ (zero_extend:SI
+ (match_operand:NARROW 1 "memory_operand" "+m"))
+ (match_operand:SI 2 "s_register_operand" "r")))
+ ] VUNSPEC_SYNC_NEW_OP))
+ (set (match_dup 1)
+ (unspec_volatile:NARROW [(match_dup 1) (match_dup 2)]
+ VUNSPEC_SYNC_NEW_OP))
+ (clobber (reg:CC CC_REGNUM))
+ (clobber (match_scratch:SI 3 "=&r"))]
+ "TARGET_HAVE_LDREX && TARGET_HAVE_MEMORY_BARRIER"
+ {
+ return arm_output_sync_insn (insn, operands);
+ }
+ [(set_attr "sync_result" "0")
+ (set_attr "sync_memory" "1")
+ (set_attr "sync_new_value" "2")
+ (set_attr "sync_t1" "0")
+ (set_attr "sync_t2" "3")
+ (set_attr "sync_op" "nand")
+ (set_attr "conds" "nocond")
+ (set_attr "predicable" "no")])
+
+(define_insn "arm_sync_old_<sync_optab>si"
+ [(set (match_operand:SI 0 "s_register_operand" "=&r")
+ (unspec_volatile:SI [(syncop:SI
+ (match_operand:SI 1 "memory_operand" "+m")
+ (match_operand:SI 2 "s_register_operand" "r"))
+ ]
+ VUNSPEC_SYNC_OLD_OP))
+ (set (match_dup 1)
+ (unspec_volatile:SI [(match_dup 1) (match_dup 2)]
+ VUNSPEC_SYNC_OLD_OP))
+ (clobber (reg:CC CC_REGNUM))
+ (clobber (match_scratch:SI 3 "=&r"))
+ (clobber (match_scratch:SI 4 "=&r"))]
+ "TARGET_HAVE_LDREX && TARGET_HAVE_MEMORY_BARRIER"
+ {
+ return arm_output_sync_insn (insn, operands);
+ }
+ [(set_attr "sync_result" "0")
+ (set_attr "sync_memory" "1")
+ (set_attr "sync_new_value" "2")
+ (set_attr "sync_t1" "3")
+ (set_attr "sync_t2" "4")
+ (set_attr "sync_op" "<sync_optab>")
+ (set_attr "conds" "nocond")
+ (set_attr "predicable" "no")])
+
+(define_insn "arm_sync_old_nandsi"
+ [(set (match_operand:SI 0 "s_register_operand" "=&r")
+ (unspec_volatile:SI [(not:SI (and:SI
+ (match_operand:SI 1 "memory_operand" "+m")
+ (match_operand:SI 2 "s_register_operand" "r")))
+ ]
+ VUNSPEC_SYNC_OLD_OP))
+ (set (match_dup 1)
+ (unspec_volatile:SI [(match_dup 1) (match_dup 2)]
+ VUNSPEC_SYNC_OLD_OP))
+ (clobber (reg:CC CC_REGNUM))
+ (clobber (match_scratch:SI 3 "=&r"))
+ (clobber (match_scratch:SI 4 "=&r"))]
+ "TARGET_HAVE_LDREX && TARGET_HAVE_MEMORY_BARRIER"
+ {
+ return arm_output_sync_insn (insn, operands);
+ }
+ [(set_attr "sync_result" "0")
+ (set_attr "sync_memory" "1")
+ (set_attr "sync_new_value" "2")
+ (set_attr "sync_t1" "3")
+ (set_attr "sync_t2" "4")
+ (set_attr "sync_op" "nand")
+ (set_attr "conds" "nocond")
+ (set_attr "predicable" "no")])
+
+(define_insn "arm_sync_old_<sync_optab><mode>"
+ [(set (match_operand:SI 0 "s_register_operand" "=&r")
+ (unspec_volatile:SI [(syncop:SI
+ (zero_extend:SI
+ (match_operand:NARROW 1 "memory_operand" "+m"))
+ (match_operand:SI 2 "s_register_operand" "r"))
+ ]
+ VUNSPEC_SYNC_OLD_OP))
+ (set (match_dup 1)
+ (unspec_volatile:NARROW [(match_dup 1) (match_dup 2)]
+ VUNSPEC_SYNC_OLD_OP))
+ (clobber (reg:CC CC_REGNUM))
+ (clobber (match_scratch:SI 3 "=&r"))
+ (clobber (match_scratch:SI 4 "=&r"))]
+ "TARGET_HAVE_LDREXBHD && TARGET_HAVE_MEMORY_BARRIER"
+ {
+ return arm_output_sync_insn (insn, operands);
+ }
+ [(set_attr "sync_result" "0")
+ (set_attr "sync_memory" "1")
+ (set_attr "sync_new_value" "2")
+ (set_attr "sync_t1" "3")
+ (set_attr "sync_t2" "4")
+ (set_attr "sync_op" "<sync_optab>")
+ (set_attr "conds" "nocond")
+ (set_attr "predicable" "no")])
+
+(define_insn "arm_sync_old_nand<mode>"
+ [(set (match_operand:SI 0 "s_register_operand" "=&r")
+ (unspec_volatile:SI [(not:SI (and:SI
+ (zero_extend:SI
+ (match_operand:NARROW 1 "memory_operand" "+m"))
+ (match_operand:SI 2 "s_register_operand" "r")))
+ ]
+ VUNSPEC_SYNC_OLD_OP))
+ (set (match_dup 1)
+ (unspec_volatile:NARROW [(match_dup 1) (match_dup 2)]
+ VUNSPEC_SYNC_OLD_OP))
+ (clobber (reg:CC CC_REGNUM))
+ (clobber (match_scratch:SI 3 "=&r"))
+ (clobber (match_scratch:SI 4 "=&r"))]
+ "TARGET_HAVE_LDREXBHD && TARGET_HAVE_MEMORY_BARRIER"
+ {
+ return arm_output_sync_insn (insn, operands);
+ }
+ [(set_attr "sync_result" "0")
+ (set_attr "sync_memory" "1")
+ (set_attr "sync_new_value" "2")
+ (set_attr "sync_t1" "3")
+ (set_attr "sync_t2" "4")
+ (set_attr "sync_op" "nand")
+ (set_attr "conds" "nocond")
+ (set_attr "predicable" "no")])
+
+(define_insn "*memory_barrier"
+ [(set (match_operand:BLK 0 "" "")
+ (unspec:BLK [(match_dup 0)] UNSPEC_MEMORY_BARRIER))]
+ "TARGET_HAVE_MEMORY_BARRIER"
+ {
+ return arm_output_memory_barrier (operands);
+ }
+ [(set_attr "length" "4")
+ (set_attr "conds" "unconditional")
+ (set_attr "predicable" "no")])
+