aboutsummaryrefslogtreecommitdiffstats
path: root/toolchain-layer/recipes-devtools/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99384.patch
diff options
context:
space:
mode:
Diffstat (limited to 'toolchain-layer/recipes-devtools/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99384.patch')
-rw-r--r--toolchain-layer/recipes-devtools/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99384.patch1202
1 files changed, 1202 insertions, 0 deletions
diff --git a/toolchain-layer/recipes-devtools/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99384.patch b/toolchain-layer/recipes-devtools/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99384.patch
new file mode 100644
index 0000000000..89c04a8949
--- /dev/null
+++ b/toolchain-layer/recipes-devtools/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99384.patch
@@ -0,0 +1,1202 @@
+ 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.
+
+2010-09-09 Andrew Stubbs <ams@codesourcery.com>
+
+ Backport from mainline:
+
+ 2010-08-25 Tejas Belagod <tejas.belagod@arm.com>
+ * config/arm/iterators.md (VU, SE, V_widen_l): New.
+ (V_unpack, US): New.
+
+=== modified file 'gcc/config/arm/arm-protos.h'
+--- old/gcc/config/arm/arm-protos.h 2010-08-24 13:15:54 +0000
++++ new/gcc/config/arm/arm-protos.h 2010-09-09 15:03:00 +0000
+@@ -148,6 +148,11 @@
+ extern void arm_set_return_address (rtx, rtx);
+ extern int arm_eliminable_register (rtx);
+ extern const char *arm_output_shift(rtx *, int);
++extern void arm_expand_sync (enum machine_mode, struct arm_sync_generator *,
++ rtx, rtx, rtx, rtx);
++extern const char *arm_output_memory_barrier (rtx *);
++extern const char *arm_output_sync_insn (rtx, rtx *);
++extern unsigned int arm_sync_loop_insns (rtx , rtx *);
+
+ extern bool arm_output_addr_const_extra (FILE *, rtx);
+
+
+=== modified file 'gcc/config/arm/arm.c'
+--- old/gcc/config/arm/arm.c 2010-09-01 13:29:58 +0000
++++ new/gcc/config/arm/arm.c 2010-09-09 15:03:00 +0000
+@@ -605,6 +605,7 @@
+ #define FL_NEON (1 << 20) /* Neon instructions. */
+ #define FL_ARCH7EM (1 << 21) /* Instructions present in the ARMv7E-M
+ architecture. */
++#define FL_ARCH7 (1 << 22) /* Architecture 7. */
+
+ #define FL_IWMMXT (1 << 29) /* XScale v2 or "Intel Wireless MMX technology". */
+
+@@ -625,7 +626,7 @@
+ #define FL_FOR_ARCH6ZK FL_FOR_ARCH6K
+ #define FL_FOR_ARCH6T2 (FL_FOR_ARCH6 | FL_THUMB2)
+ #define FL_FOR_ARCH6M (FL_FOR_ARCH6 & ~FL_NOTM)
+-#define FL_FOR_ARCH7 (FL_FOR_ARCH6T2 &~ FL_NOTM)
++#define FL_FOR_ARCH7 ((FL_FOR_ARCH6T2 & ~FL_NOTM) | FL_ARCH7)
+ #define FL_FOR_ARCH7A (FL_FOR_ARCH7 | FL_NOTM | FL_ARCH6K)
+ #define FL_FOR_ARCH7R (FL_FOR_ARCH7A | FL_DIV)
+ #define FL_FOR_ARCH7M (FL_FOR_ARCH7 | FL_DIV)
+@@ -663,6 +664,9 @@
+ /* Nonzero if this chip supports the ARM 6K extensions. */
+ int arm_arch6k = 0;
+
++/* Nonzero if this chip supports the ARM 7 extensions. */
++int arm_arch7 = 0;
++
+ /* Nonzero if instructions not present in the 'M' profile can be used. */
+ int arm_arch_notm = 0;
+
+@@ -1634,6 +1638,7 @@
+ arm_arch6 = (insn_flags & FL_ARCH6) != 0;
+ arm_arch6k = (insn_flags & FL_ARCH6K) != 0;
+ arm_arch_notm = (insn_flags & FL_NOTM) != 0;
++ arm_arch7 = (insn_flags & FL_ARCH7) != 0;
+ arm_arch7em = (insn_flags & FL_ARCH7EM) != 0;
+ arm_arch_thumb2 = (insn_flags & FL_THUMB2) != 0;
+ arm_arch_xscale = (insn_flags & FL_XSCALE) != 0;
+@@ -16561,6 +16566,17 @@
+ }
+ return;
+
++ case 'C':
++ {
++ rtx addr;
++
++ gcc_assert (GET_CODE (x) == MEM);
++ addr = XEXP (x, 0);
++ gcc_assert (GET_CODE (addr) == REG);
++ asm_fprintf (stream, "[%r]", REGNO (addr));
++ }
++ return;
++
+ /* Translate an S register number into a D register number and element index. */
+ case 'y':
+ {
+@@ -22763,4 +22779,372 @@
+ is_packed);
+ }
+
++/* Legitimize a memory reference for sync primitive implemented using
++ ldrex / strex. We currently force the form of the reference to be
++ indirect without offset. We do not yet support the indirect offset
++ addressing supported by some ARM targets for these
++ instructions. */
++static rtx
++arm_legitimize_sync_memory (rtx memory)
++{
++ rtx addr = force_reg (Pmode, XEXP (memory, 0));
++ rtx legitimate_memory = gen_rtx_MEM (GET_MODE (memory), addr);
++
++ set_mem_alias_set (legitimate_memory, ALIAS_SET_MEMORY_BARRIER);
++ MEM_VOLATILE_P (legitimate_memory) = MEM_VOLATILE_P (memory);
++ return legitimate_memory;
++}
++
++/* An instruction emitter. */
++typedef void (* emit_f) (int label, const char *, rtx *);
++
++/* An instruction emitter that emits via the conventional
++ output_asm_insn. */
++static void
++arm_emit (int label ATTRIBUTE_UNUSED, const char *pattern, rtx *operands)
++{
++ output_asm_insn (pattern, operands);
++}
++
++/* Count the number of emitted synchronization instructions. */
++static unsigned arm_insn_count;
++
++/* An emitter that counts emitted instructions but does not actually
++ emit instruction into the the instruction stream. */
++static void
++arm_count (int label,
++ const char *pattern ATTRIBUTE_UNUSED,
++ rtx *operands ATTRIBUTE_UNUSED)
++{
++ if (! label)
++ ++ arm_insn_count;
++}
++
++/* Construct a pattern using conventional output formatting and feed
++ it to output_asm_insn. Provides a mechanism to construct the
++ output pattern on the fly. Note the hard limit on the pattern
++ buffer size. */
++static void
++arm_output_asm_insn (emit_f emit, int label, rtx *operands,
++ const char *pattern, ...)
++{
++ va_list ap;
++ char buffer[256];
++
++ va_start (ap, pattern);
++ vsprintf (buffer, pattern, ap);
++ va_end (ap);
++ emit (label, buffer, operands);
++}
++
++/* Emit the memory barrier instruction, if any, provided by this
++ target to a specified emitter. */
++static void
++arm_process_output_memory_barrier (emit_f emit, rtx *operands)
++{
++ if (TARGET_HAVE_DMB)
++ {
++ /* Note we issue a system level barrier. We should consider
++ issuing a inner shareabilty zone barrier here instead, ie.
++ "DMB ISH". */
++ emit (0, "dmb\tsy", operands);
++ return;
++ }
++
++ if (TARGET_HAVE_DMB_MCR)
++ {
++ emit (0, "mcr\tp15, 0, r0, c7, c10, 5", operands);
++ return;
++ }
++
++ gcc_unreachable ();
++}
++
++/* Emit the memory barrier instruction, if any, provided by this
++ target. */
++const char *
++arm_output_memory_barrier (rtx *operands)
++{
++ arm_process_output_memory_barrier (arm_emit, operands);
++ return "";
++}
++
++/* Helper to figure out the instruction suffix required on ldrex/strex
++ for operations on an object of the specified mode. */
++static const char *
++arm_ldrex_suffix (enum machine_mode mode)
++{
++ switch (mode)
++ {
++ case QImode: return "b";
++ case HImode: return "h";
++ case SImode: return "";
++ case DImode: return "d";
++ default:
++ gcc_unreachable ();
++ }
++ return "";
++}
++
++/* Emit an ldrex{b,h,d, } instruction appropriate for the specified
++ mode. */
++static void
++arm_output_ldrex (emit_f emit,
++ enum machine_mode mode,
++ rtx target,
++ rtx memory)
++{
++ const char *suffix = arm_ldrex_suffix (mode);
++ rtx operands[2];
++
++ operands[0] = target;
++ operands[1] = memory;
++ arm_output_asm_insn (emit, 0, operands, "ldrex%s\t%%0, %%C1", suffix);
++}
++
++/* Emit a strex{b,h,d, } instruction appropriate for the specified
++ mode. */
++static void
++arm_output_strex (emit_f emit,
++ enum machine_mode mode,
++ const char *cc,
++ rtx result,
++ rtx value,
++ rtx memory)
++{
++ const char *suffix = arm_ldrex_suffix (mode);
++ rtx operands[3];
++
++ operands[0] = result;
++ operands[1] = value;
++ operands[2] = memory;
++ arm_output_asm_insn (emit, 0, operands, "strex%s%s\t%%0, %%1, %%C2", suffix,
++ cc);
++}
++
++/* Helper to emit a two operand instruction. */
++static void
++arm_output_op2 (emit_f emit, const char *mnemonic, rtx d, rtx s)
++{
++ rtx operands[2];
++
++ operands[0] = d;
++ operands[1] = s;
++ arm_output_asm_insn (emit, 0, operands, "%s\t%%0, %%1", mnemonic);
++}
++
++/* Helper to emit a three operand instruction. */
++static void
++arm_output_op3 (emit_f emit, const char *mnemonic, rtx d, rtx a, rtx b)
++{
++ rtx operands[3];
++
++ operands[0] = d;
++ operands[1] = a;
++ operands[2] = b;
++ arm_output_asm_insn (emit, 0, operands, "%s\t%%0, %%1, %%2", mnemonic);
++}
++
++/* Emit a load store exclusive synchronization loop.
++
++ do
++ old_value = [mem]
++ if old_value != required_value
++ break;
++ t1 = sync_op (old_value, new_value)
++ [mem] = t1, t2 = [0|1]
++ while ! t2
++
++ Note:
++ t1 == t2 is not permitted
++ t1 == old_value is permitted
++
++ required_value:
++
++ RTX register or const_int representing the required old_value for
++ the modify to continue, if NULL no comparsion is performed. */
++static void
++arm_output_sync_loop (emit_f emit,
++ enum machine_mode mode,
++ rtx old_value,
++ rtx memory,
++ rtx required_value,
++ rtx new_value,
++ rtx t1,
++ rtx t2,
++ enum attr_sync_op sync_op,
++ int early_barrier_required)
++{
++ rtx operands[1];
++
++ gcc_assert (t1 != t2);
++
++ if (early_barrier_required)
++ arm_process_output_memory_barrier (emit, NULL);
++
++ arm_output_asm_insn (emit, 1, operands, "%sLSYT%%=:", LOCAL_LABEL_PREFIX);
++
++ arm_output_ldrex (emit, mode, old_value, memory);
++
++ if (required_value)
++ {
++ rtx operands[2];
++
++ operands[0] = old_value;
++ operands[1] = required_value;
++ arm_output_asm_insn (emit, 0, operands, "cmp\t%%0, %%1");
++ arm_output_asm_insn (emit, 0, operands, "bne\t%sLSYB%%=", LOCAL_LABEL_PREFIX);
++ }
++
++ switch (sync_op)
++ {
++ case SYNC_OP_ADD:
++ arm_output_op3 (emit, "add", t1, old_value, new_value);
++ break;
++
++ case SYNC_OP_SUB:
++ arm_output_op3 (emit, "sub", t1, old_value, new_value);
++ break;
++
++ case SYNC_OP_IOR:
++ arm_output_op3 (emit, "orr", t1, old_value, new_value);
++ break;
++
++ case SYNC_OP_XOR:
++ arm_output_op3 (emit, "eor", t1, old_value, new_value);
++ break;
++
++ case SYNC_OP_AND:
++ arm_output_op3 (emit,"and", t1, old_value, new_value);
++ break;
++
++ case SYNC_OP_NAND:
++ arm_output_op3 (emit, "and", t1, old_value, new_value);
++ arm_output_op2 (emit, "mvn", t1, t1);
++ break;
++
++ case SYNC_OP_NONE:
++ t1 = new_value;
++ break;
++ }
++
++ arm_output_strex (emit, mode, "", t2, t1, memory);
++ operands[0] = t2;
++ arm_output_asm_insn (emit, 0, operands, "teq\t%%0, #0");
++ arm_output_asm_insn (emit, 0, operands, "bne\t%sLSYT%%=", LOCAL_LABEL_PREFIX);
++
++ arm_process_output_memory_barrier (emit, NULL);
++ arm_output_asm_insn (emit, 1, operands, "%sLSYB%%=:", LOCAL_LABEL_PREFIX);
++}
++
++static rtx
++arm_get_sync_operand (rtx *operands, int index, rtx default_value)
++{
++ if (index > 0)
++ default_value = operands[index - 1];
++
++ return default_value;
++}
++
++#define FETCH_SYNC_OPERAND(NAME, DEFAULT) \
++ arm_get_sync_operand (operands, (int) get_attr_sync_##NAME (insn), DEFAULT);
++
++/* Extract the operands for a synchroniztion instruction from the
++ instructions attributes and emit the instruction. */
++static void
++arm_process_output_sync_insn (emit_f emit, rtx insn, rtx *operands)
++{
++ rtx result, memory, required_value, new_value, t1, t2;
++ int early_barrier;
++ enum machine_mode mode;
++ enum attr_sync_op sync_op;
++
++ result = FETCH_SYNC_OPERAND(result, 0);
++ memory = FETCH_SYNC_OPERAND(memory, 0);
++ required_value = FETCH_SYNC_OPERAND(required_value, 0);
++ new_value = FETCH_SYNC_OPERAND(new_value, 0);
++ t1 = FETCH_SYNC_OPERAND(t1, 0);
++ t2 = FETCH_SYNC_OPERAND(t2, 0);
++ early_barrier =
++ get_attr_sync_release_barrier (insn) == SYNC_RELEASE_BARRIER_YES;
++ sync_op = get_attr_sync_op (insn);
++ mode = GET_MODE (memory);
++
++ arm_output_sync_loop (emit, mode, result, memory, required_value,
++ new_value, t1, t2, sync_op, early_barrier);
++}
++
++/* Emit a synchronization instruction loop. */
++const char *
++arm_output_sync_insn (rtx insn, rtx *operands)
++{
++ arm_process_output_sync_insn (arm_emit, insn, operands);
++ return "";
++}
++
++/* Count the number of machine instruction that will be emitted for a
++ synchronization instruction. Note that the emitter used does not
++ emit instructions, it just counts instructions being carefull not
++ to count labels. */
++unsigned int
++arm_sync_loop_insns (rtx insn, rtx *operands)
++{
++ arm_insn_count = 0;
++ arm_process_output_sync_insn (arm_count, insn, operands);
++ return arm_insn_count;
++}
++
++/* Helper to call a target sync instruction generator, dealing with
++ the variation in operands required by the different generators. */
++static rtx
++arm_call_generator (struct arm_sync_generator *generator, rtx old_value,
++ rtx memory, rtx required_value, rtx new_value)
++{
++ switch (generator->op)
++ {
++ case arm_sync_generator_omn:
++ gcc_assert (! required_value);
++ return generator->u.omn (old_value, memory, new_value);
++
++ case arm_sync_generator_omrn:
++ gcc_assert (required_value);
++ return generator->u.omrn (old_value, memory, required_value, new_value);
++ }
++
++ return NULL;
++}
++
++/* Expand a synchronization loop. The synchronization loop is expanded
++ as an opaque block of instructions in order to ensure that we do
++ not subsequently get extraneous memory accesses inserted within the
++ critical region. The exclusive access property of ldrex/strex is
++ only guaranteed in there are no intervening memory accesses. */
++void
++arm_expand_sync (enum machine_mode mode,
++ struct arm_sync_generator *generator,
++ rtx target, rtx memory, rtx required_value, rtx new_value)
++{
++ if (target == NULL)
++ target = gen_reg_rtx (mode);
++
++ memory = arm_legitimize_sync_memory (memory);
++ if (mode != SImode)
++ {
++ rtx load_temp = gen_reg_rtx (SImode);
++
++ if (required_value)
++ required_value = convert_modes (SImode, mode, required_value, true);
++
++ new_value = convert_modes (SImode, mode, new_value, true);
++ emit_insn (arm_call_generator (generator, load_temp, memory,
++ required_value, new_value));
++ emit_move_insn (target, gen_lowpart (mode, load_temp));
++ }
++ else
++ {
++ emit_insn (arm_call_generator (generator, target, memory, required_value,
++ new_value));
++ }
++}
++
+ #include "gt-arm.h"
+
+=== modified file 'gcc/config/arm/arm.h'
+--- old/gcc/config/arm/arm.h 2010-09-01 13:29:58 +0000
++++ new/gcc/config/arm/arm.h 2010-09-09 15:03:00 +0000
+@@ -128,6 +128,24 @@
+ /* The processor for which instructions should be scheduled. */
+ extern enum processor_type arm_tune;
+
++enum arm_sync_generator_tag
++ {
++ arm_sync_generator_omn,
++ arm_sync_generator_omrn
++ };
++
++/* Wrapper to pass around a polymorphic pointer to a sync instruction
++ generator and. */
++struct arm_sync_generator
++{
++ enum arm_sync_generator_tag op;
++ union
++ {
++ rtx (* omn) (rtx, rtx, rtx);
++ rtx (* omrn) (rtx, rtx, rtx, rtx);
++ } u;
++};
++
+ typedef enum arm_cond_code
+ {
+ ARM_EQ = 0, ARM_NE, ARM_CS, ARM_CC, ARM_MI, ARM_PL, ARM_VS, ARM_VC,
+@@ -272,6 +290,20 @@
+ for Thumb-2. */
+ #define TARGET_UNIFIED_ASM TARGET_THUMB2
+
++/* Nonzero if this chip provides the DMB instruction. */
++#define TARGET_HAVE_DMB (arm_arch7)
++
++/* Nonzero if this chip implements a memory barrier via CP15. */
++#define TARGET_HAVE_DMB_MCR (arm_arch6k && ! TARGET_HAVE_DMB)
++
++/* Nonzero if this chip implements a memory barrier instruction. */
++#define TARGET_HAVE_MEMORY_BARRIER (TARGET_HAVE_DMB || TARGET_HAVE_DMB_MCR)
++
++/* Nonzero if this chip supports ldrex and strex */
++#define TARGET_HAVE_LDREX ((arm_arch6 && TARGET_ARM) || arm_arch7)
++
++/* Nonzero if this chip supports ldrex{bhd} and strex{bhd}. */
++#define TARGET_HAVE_LDREXBHD ((arm_arch6k && TARGET_ARM) || arm_arch7)
+
+ /* True iff the full BPABI is being used. If TARGET_BPABI is true,
+ then TARGET_AAPCS_BASED must be true -- but the converse does not
+@@ -405,6 +437,12 @@
+ /* Nonzero if this chip supports the ARM Architecture 6 extensions. */
+ extern int arm_arch6;
+
++/* Nonzero if this chip supports the ARM Architecture 6k extensions. */
++extern int arm_arch6k;
++
++/* Nonzero if this chip supports the ARM Architecture 7 extensions. */
++extern int arm_arch7;
++
+ /* Nonzero if instructions not present in the 'M' profile can be used. */
+ extern int arm_arch_notm;
+
+
+=== modified file 'gcc/config/arm/arm.md'
+--- old/gcc/config/arm/arm.md 2010-09-09 14:11:34 +0000
++++ new/gcc/config/arm/arm.md 2010-09-09 15:03:00 +0000
+@@ -103,6 +103,7 @@
+ (UNSPEC_RBIT 26) ; rbit operation.
+ (UNSPEC_SYMBOL_OFFSET 27) ; The offset of the start of the symbol from
+ ; another symbolic address.
++ (UNSPEC_MEMORY_BARRIER 28) ; Represent a memory barrier.
+ ]
+ )
+
+@@ -139,6 +140,11 @@
+ (VUNSPEC_ALIGN32 16) ; Used to force 32-byte alignment.
+ (VUNSPEC_EH_RETURN 20); Use to override the return address for exception
+ ; handling.
++ (VUNSPEC_SYNC_COMPARE_AND_SWAP 21) ; Represent an atomic compare swap.
++ (VUNSPEC_SYNC_LOCK 22) ; Represent a sync_lock_test_and_set.
++ (VUNSPEC_SYNC_OP 23) ; Represent a sync_<op>
++ (VUNSPEC_SYNC_NEW_OP 24) ; Represent a sync_new_<op>
++ (VUNSPEC_SYNC_OLD_OP 25) ; Represent a sync_old_<op>
+ ]
+ )
+
+@@ -163,8 +169,21 @@
+ (define_attr "fpu" "none,fpa,fpe2,fpe3,maverick,vfp"
+ (const (symbol_ref "arm_fpu_attr")))
+
++(define_attr "sync_result" "none,0,1,2,3,4,5" (const_string "none"))
++(define_attr "sync_memory" "none,0,1,2,3,4,5" (const_string "none"))
++(define_attr "sync_required_value" "none,0,1,2,3,4,5" (const_string "none"))
++(define_attr "sync_new_value" "none,0,1,2,3,4,5" (const_string "none"))
++(define_attr "sync_t1" "none,0,1,2,3,4,5" (const_string "none"))
++(define_attr "sync_t2" "none,0,1,2,3,4,5" (const_string "none"))
++(define_attr "sync_release_barrier" "yes,no" (const_string "yes"))
++(define_attr "sync_op" "none,add,sub,ior,xor,and,nand"
++ (const_string "none"))
++
+ ; LENGTH of an instruction (in bytes)
+-(define_attr "length" "" (const_int 4))
++(define_attr "length" ""
++ (cond [(not (eq_attr "sync_memory" "none"))
++ (symbol_ref "arm_sync_loop_insns (insn, operands) * 4")
++ ] (const_int 4)))
+
+ ; POOL_RANGE is how far away from a constant pool entry that this insn
+ ; can be placed. If the distance is zero, then this insn will never
+@@ -11530,4 +11549,5 @@
+ (include "thumb2.md")
+ ;; Neon patterns
+ (include "neon.md")
+-
++;; Synchronization Primitives
++(include "sync.md")
+
+=== added file 'gcc/config/arm/sync.md'
+--- old/gcc/config/arm/sync.md 1970-01-01 00:00:00 +0000
++++ new/gcc/config/arm/sync.md 2010-09-09 15:03:00 +0000
+@@ -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")])
++
+