summaryrefslogtreecommitdiff
path: root/gcc/config/arm/sync.md
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/config/arm/sync.md')
-rw-r--r--gcc/config/arm/sync.md602
1 files changed, 602 insertions, 0 deletions
diff --git a/gcc/config/arm/sync.md b/gcc/config/arm/sync.md
new file mode 100644
index 000000000..689a235c1
--- /dev/null
+++ b/gcc/config/arm/sync.md
@@ -0,0 +1,602 @@
+;; 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_code_attr sync_clobber [(ior "=&r")
+ (and "=&r")
+ (xor "X")
+ (plus "X")
+ (minus "X")])
+
+(define_code_attr sync_t2_reqd [(ior "4")
+ (and "4")
+ (xor "*")
+ (plus "*")
+ (minus "*")])
+
+(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 "arm_sync_memory_operand" "+Q")
+ (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))
+ (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 "conds" "clob")
+ (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 "arm_sync_memory_operand" "+Q")
+ (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))
+ (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 "conds" "clob")
+ (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 "arm_sync_memory_operand" "+Q"))
+ (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" "clob")
+ (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 "arm_sync_memory_operand" "+Q")))
+ (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" "clob")
+ (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 "arm_sync_memory_operand" "+Q")
+ (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" "clob")
+ (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 "arm_sync_memory_operand" "+Q")
+ (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" "clob")
+ (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 "arm_sync_memory_operand" "+Q"))
+ (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" "clob")
+ (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 "arm_sync_memory_operand" "+Q"))
+ (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" "clob")
+ (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 "arm_sync_memory_operand" "+Q")
+ (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 "<sync_clobber>"))]
+ "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" "<sync_t2_reqd>")
+ (set_attr "sync_op" "<sync_optab>")
+ (set_attr "conds" "clob")
+ (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 "arm_sync_memory_operand" "+Q")
+ (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" "clob")
+ (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 "arm_sync_memory_operand" "+Q"))
+ (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 "<sync_clobber>"))]
+ "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" "<sync_t2_reqd>")
+ (set_attr "sync_op" "<sync_optab>")
+ (set_attr "conds" "clob")
+ (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 "arm_sync_memory_operand" "+Q"))
+ (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" "clob")
+ (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")])
+