=== modified file 'gcc/config/arm/arm.c' --- gcc/config/arm/arm.c 2010-11-11 11:50:33 +0000 +++ gcc/config/arm/arm.c 2010-11-26 19:25:32 +0000 @@ -23084,10 +23084,46 @@ 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); + if (t2 != NULL) + { + 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); + } + else + { + /* Use old_value for the return value because for some operations + the old_value can easily be restored. This saves one register. */ + arm_output_strex (emit, mode, "", old_value, t1, memory); + operands[0] = old_value; + arm_output_asm_insn (emit, 0, operands, "teq\t%%0, #0"); + arm_output_asm_insn (emit, 0, operands, "bne\t%sLSYT%%=", + LOCAL_LABEL_PREFIX); + + switch (sync_op) + { + case SYNC_OP_ADD: + arm_output_op3 (emit, "sub", old_value, t1, new_value); + break; + + case SYNC_OP_SUB: + arm_output_op3 (emit, "add", old_value, t1, new_value); + break; + + case SYNC_OP_XOR: + arm_output_op3 (emit, "eor", old_value, t1, new_value); + break; + + case SYNC_OP_NONE: + arm_output_op2 (emit, "mov", old_value, required_value); + break; + + default: + break; + } + } arm_process_output_memory_barrier (emit, NULL); arm_output_asm_insn (emit, 1, operands, "%sLSYB%%=:", LOCAL_LABEL_PREFIX); === modified file 'gcc/config/arm/sync.md' --- gcc/config/arm/sync.md 2010-09-13 15:39:11 +0000 +++ gcc/config/arm/sync.md 2010-11-26 19:25:32 +0000 @@ -103,6 +103,17 @@ (plus "add") (minus "sub")]) +;; Those operations are reversible. +(define_code_iterator rev_syncop [plus minus xor]) +(define_code_attr sync_rev_optab [(xor "xor") + (plus "add") + (minus "sub")]) + +;; Those operations are non-reversible. +(define_code_iterator nrev_syncop [ior and]) +(define_code_attr sync_nrev_optab [(ior "ior") + (and "and")]) + (define_expand "sync_si" [(match_operand:SI 0 "memory_operand") (match_operand:SI 1 "s_register_operand") @@ -286,7 +297,6 @@ 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)) ] @@ -299,7 +309,6 @@ (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" "clob") (set_attr "predicable" "no")]) @@ -313,7 +322,6 @@ 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)) ] @@ -326,7 +334,6 @@ (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" "clob") (set_attr "predicable" "no")]) @@ -475,9 +482,33 @@ (set_attr "conds" "clob") (set_attr "predicable" "no")]) -(define_insn "arm_sync_old_si" - [(set (match_operand:SI 0 "s_register_operand" "=&r") - (unspec_volatile:SI [(syncop:SI +(define_insn "arm_sync_old_si" + [(set (match_operand:SI 0 "s_register_operand" "=&r") + (unspec_volatile:SI [(rev_syncop:SI + (match_operand:SI 1 "arm_sync_memory_operand" "+Q") + (match_operand:SI 2 "s_register_operand" "r")) + ] + VUNSPEC_SYNC_OLD_OP)) + (set (match_dup 1) + (unspec_volatile:SI [(match_dup 1) (match_dup 2)] + VUNSPEC_SYNC_OLD_OP)) + (clobber (reg:CC CC_REGNUM)) + (clobber (match_scratch:SI 3 "=&r"))] + "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_op" "") + (set_attr "conds" "clob") + (set_attr "predicable" "no")]) + +(define_insn "arm_sync_old_si" + [(set (match_operand:SI 0 "s_register_operand" "=&r") + (unspec_volatile:SI [(nrev_syncop:SI (match_operand:SI 1 "arm_sync_memory_operand" "+Q") (match_operand:SI 2 "s_register_operand" "r")) ] @@ -527,9 +558,34 @@ (set_attr "conds" "clob") (set_attr "predicable" "no")]) -(define_insn "arm_sync_old_" - [(set (match_operand:SI 0 "s_register_operand" "=&r") - (unspec_volatile:SI [(syncop:SI +(define_insn "arm_sync_old_" + [(set (match_operand:SI 0 "s_register_operand" "=&r") + (unspec_volatile:SI [(rev_syncop:SI + (zero_extend:SI + (match_operand:NARROW 1 "arm_sync_memory_operand" "+Q")) + (match_operand:SI 2 "s_register_operand" "r")) + ] + VUNSPEC_SYNC_OLD_OP)) + (set (match_dup 1) + (unspec_volatile:NARROW [(match_dup 1) (match_dup 2)] + VUNSPEC_SYNC_OLD_OP)) + (clobber (reg:CC CC_REGNUM)) + (clobber (match_scratch:SI 3 "=&r"))] + "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_op" "") + (set_attr "conds" "clob") + (set_attr "predicable" "no")]) + +(define_insn "arm_sync_old_" + [(set (match_operand:SI 0 "s_register_operand" "=&r") + (unspec_volatile:SI [(nrev_syncop:SI (zero_extend:SI (match_operand:NARROW 1 "arm_sync_memory_operand" "+Q")) (match_operand:SI 2 "s_register_operand" "r"))