2010-10-22 Julian Brown Backport from mainline: 2010-10-18 Marcus Shawcroft gcc/testsuite/ * gcc.target/arm/synchronize.c: Permit dmb or mcr in assembler scan. 2010-10-14 Julian Brown Backport from mainline: 2010-08-18 Marcus Shawcroft gcc/ * 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-02 Marcus Shawcroft gcc/ * config/arm/predicates.md (arm_sync_memory_operand): New. * config/arm/sync.md (arm_sync_compare_and_swapsi): Change predicate to arm_sync_memory_operand and constraint to Q. (arm_sync_compare_and_swap): Likewise. (arm_sync_compare_and_swap): Likewise. (arm_sync_lock_test_and_setsi): Likewise. (arm_sync_lock_test_and_set): Likewise. (arm_sync_new_si): Likewise. (arm_sync_new_nandsi): Likewise. (arm_sync_new_): Likewise. (arm_sync_new_nand): Likewise. (arm_sync_old_si): Likewise. (arm_sync_old_nandsi): Likewise. (arm_sync_old_): Likewise. (arm_sync_old_nand): Likewise. 2010-09-13 Marcus Shawcroft gcc/ * config/arm/arm.md: (define_attr "conds"): Update comment. * config/arm/sync.md (arm_sync_compare_and_swapsi): Change conds attribute to clob. (arm_sync_compare_and_swapsi): Likewise. (arm_sync_compare_and_swap): Likewise. (arm_sync_lock_test_and_setsi): Likewise. (arm_sync_lock_test_and_set): Likewise. (arm_sync_new_si): Likewise. (arm_sync_new_nandsi): Likewise. (arm_sync_new_): Likewise. (arm_sync_new_nand): Likewise. (arm_sync_old_si): Likewise. (arm_sync_old_nandsi): Likewise. (arm_sync_old_): Likewise. (arm_sync_old_nand): Likewise. 2010-09-13 Marcus Shawcroft gcc/testsuite/ * gcc.target/arm/sync-1.c: New. Backport from FSF: gcc/ 2010-08-18 Marcus Shawcroft * 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. gcc/ 2010-09-02 Marcus Shawcroft * config/arm/predicates.md (arm_sync_memory_operand): New. * config/arm/sync.md (arm_sync_compare_and_swapsi): Change predicate to arm_sync_memory_operand and constraint to Q. (arm_sync_compare_and_swap): Likewise. (arm_sync_compare_and_swap): Likewise. (arm_sync_lock_test_and_setsi): Likewise. (arm_sync_lock_test_and_set): Likewise. (arm_sync_new_si): Likewise. (arm_sync_new_nandsi): Likewise. (arm_sync_new_): Likewise. (arm_sync_new_nand): Likewise. (arm_sync_old_si): Likewise. (arm_sync_old_nandsi): Likewise. (arm_sync_old_): Likewise. (arm_sync_old_nand): Likewise. === modified file 'gcc/config/arm/arm-protos.h' Index: gcc-4.5/gcc/config/arm/arm-protos.h =================================================================== --- gcc-4.5.orig/gcc/config/arm/arm-protos.h +++ gcc-4.5/gcc/config/arm/arm-protos.h @@ -151,6 +151,11 @@ extern const char *vfp_output_fstmd (rtx 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); Index: gcc-4.5/gcc/config/arm/arm.c =================================================================== --- gcc-4.5.orig/gcc/config/arm/arm.c +++ gcc-4.5/gcc/config/arm/arm.c @@ -602,6 +602,7 @@ static int thumb_call_reg_needed; #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". */ @@ -626,7 +627,7 @@ static int thumb_call_reg_needed; #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) @@ -664,6 +665,9 @@ int arm_arch6 = 0; /* 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; @@ -1602,6 +1606,7 @@ arm_override_options (void) 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; @@ -16562,6 +16567,17 @@ arm_print_operand (FILE *stream, rtx x, } 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': { @@ -22793,4 +22809,372 @@ arm_builtin_support_vector_misalignment 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" Index: gcc-4.5/gcc/config/arm/arm.h =================================================================== --- gcc-4.5.orig/gcc/config/arm/arm.h +++ gcc-4.5/gcc/config/arm/arm.h @@ -128,6 +128,24 @@ enum target_cpus /* 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 @@ extern void (*arm_lang_output_object_att 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 @@ extern int arm_arch5e; /* 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; Index: gcc-4.5/gcc/config/arm/arm.md =================================================================== --- gcc-4.5.orig/gcc/config/arm/arm.md +++ gcc-4.5/gcc/config/arm/arm.md @@ -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_ + (VUNSPEC_SYNC_NEW_OP 24) ; Represent a sync_new_ + (VUNSPEC_SYNC_OLD_OP 25) ; Represent a sync_old_ ] ) @@ -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 @@ -11549,4 +11568,5 @@ (include "thumb2.md") ;; Neon patterns (include "neon.md") - +;; Synchronization Primitives +(include "sync.md") Index: gcc-4.5/gcc/config/arm/predicates.md =================================================================== --- gcc-4.5.orig/gcc/config/arm/predicates.md +++ gcc-4.5/gcc/config/arm/predicates.md @@ -573,6 +573,11 @@ (and (match_test "TARGET_32BIT") (match_operand 0 "arm_di_operand")))) +;; True if the operand is memory reference suitable for a ldrex/strex. +(define_predicate "arm_sync_memory_operand" + (and (match_operand 0 "memory_operand") + (match_code "reg" "0"))) + ;; Predicates for parallel expanders based on mode. (define_special_predicate "vect_par_constant_high" (match_code "parallel") Index: gcc-4.5/gcc/testsuite/gcc.target/arm/synchronize.c =================================================================== --- gcc-4.5.orig/gcc/testsuite/gcc.target/arm/synchronize.c +++ gcc-4.5/gcc/testsuite/gcc.target/arm/synchronize.c @@ -1,4 +1,4 @@ -/* { dg-final { scan-assembler "__sync_synchronize" { target arm*-*-linux-*eabi } } } */ +/* { dg-final { scan-assembler "__sync_synchronize|dmb|mcr" { target arm*-*-linux-*eabi } } } */ void *foo (void) {