diff options
Diffstat (limited to 'recipes-devtools/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99384.patch')
-rw-r--r-- | recipes-devtools/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99384.patch | 1202 |
1 files changed, 1202 insertions, 0 deletions
diff --git a/recipes-devtools/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99384.patch b/recipes-devtools/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99384.patch new file mode 100644 index 0000000000..89c04a8949 --- /dev/null +++ b/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")]) ++ + |