Commit 01c196ea by Tom de Vries Committed by Maxim Kuvyrkov

2012-06-19 Tom de Vries <vries@codesourcery.com>

	    Maxim Kuvyrkov  <maxim@codesourcery.com>

	* config/mips/mips.c (mips_emit_pre_atomic_barrier_p,)
	(mips_emit_post_atomic_barrier_p): New static functions.
	(mips_process_sync_loop): Use them.  Emit sync memory barriers in
	accordance with memory model semantics.  Add return of CMP result for
	compare_and_swap.
	* config/mips/mips.md: Update comment.
	(sync_cmp): New attribute.
	(sync_memmodel): New attribute replacing sync_release_barrier.
	* config/mips/sync.md (UNSPEC_ATOMIC_COMPARE_AND_SWAP,)
	(UNSPEC_ATOMIC_EXCHANGE, UNSPEC_ATOMIC_FETCH_OP): New constants.
	(sync_lock_test_and_set, test_and_set_12): Update.
	(atomic_compare_and_swap, atomic_exchange, atomic_exchange_llsc,)
	(atomic_fetch_add, atomic_fetch_add_llsc): New patterns.

Co-Authored-By: Maxim Kuvyrkov <maxim@codesourcery.com>

From-SVN: r188803
parent e98f6824
2012-06-19 Tom de Vries <vries@codesourcery.com>
Maxim Kuvyrkov <maxim@codesourcery.com>
* config/mips/mips.c (mips_emit_pre_atomic_barrier_p,)
(mips_emit_post_atomic_barrier_p): New static functions.
(mips_process_sync_loop): Use them. Emit sync memory barriers in
accordance with memory model semantics. Add return of CMP result for
compare_and_swap.
* config/mips/mips.md: Update comment.
(sync_cmp): New attribute.
(sync_memmodel): New attribute replacing sync_release_barrier.
* config/mips/sync.md (UNSPEC_ATOMIC_COMPARE_AND_SWAP,)
(UNSPEC_ATOMIC_EXCHANGE, UNSPEC_ATOMIC_FETCH_OP): New constants.
(sync_lock_test_and_set, test_and_set_12): Update.
(atomic_compare_and_swap, atomic_exchange, atomic_exchange_llsc,)
(atomic_fetch_add, atomic_fetch_add_llsc): New patterns.
2012-06-19 Joseph Myers <joseph@codesourcery.com> 2012-06-19 Joseph Myers <joseph@codesourcery.com>
* config/rs6000/spe.md (*mov_si<mode>_e500_subreg0): Rename to * config/rs6000/spe.md (*mov_si<mode>_e500_subreg0): Rename to
......
...@@ -11976,6 +11976,45 @@ mips_sync_insn2_template (enum attr_sync_insn2 type) ...@@ -11976,6 +11976,45 @@ mips_sync_insn2_template (enum attr_sync_insn2 type)
gcc_unreachable (); gcc_unreachable ();
} }
/* Subroutines of the mips_process_sync_loop.
Emit barriers as needed for the memory MODEL. */
static bool
mips_emit_pre_atomic_barrier_p (enum memmodel model)
{
switch (model)
{
case MEMMODEL_RELAXED:
case MEMMODEL_CONSUME:
case MEMMODEL_ACQUIRE:
return false;
case MEMMODEL_RELEASE:
case MEMMODEL_ACQ_REL:
case MEMMODEL_SEQ_CST:
return true;
default:
gcc_unreachable ();
}
}
static bool
mips_emit_post_atomic_barrier_p (enum memmodel model)
{
switch (model)
{
case MEMMODEL_RELAXED:
case MEMMODEL_CONSUME:
case MEMMODEL_RELEASE:
return false;
case MEMMODEL_ACQUIRE:
case MEMMODEL_ACQ_REL:
case MEMMODEL_SEQ_CST:
return true;
default:
gcc_unreachable ();
}
}
/* OPERANDS are the operands to a sync loop instruction and INDEX is /* OPERANDS are the operands to a sync loop instruction and INDEX is
the value of the one of the sync_* attributes. Return the operand the value of the one of the sync_* attributes. Return the operand
referred to by the attribute, or DEFAULT_VALUE if the insn doesn't referred to by the attribute, or DEFAULT_VALUE if the insn doesn't
...@@ -11996,11 +12035,13 @@ static void ...@@ -11996,11 +12035,13 @@ static void
mips_process_sync_loop (rtx insn, rtx *operands) mips_process_sync_loop (rtx insn, rtx *operands)
{ {
rtx at, mem, oldval, newval, inclusive_mask, exclusive_mask; rtx at, mem, oldval, newval, inclusive_mask, exclusive_mask;
rtx required_oldval, insn1_op2, tmp1, tmp2, tmp3; rtx required_oldval, insn1_op2, tmp1, tmp2, tmp3, cmp;
unsigned int tmp3_insn; unsigned int tmp3_insn;
enum attr_sync_insn1 insn1; enum attr_sync_insn1 insn1;
enum attr_sync_insn2 insn2; enum attr_sync_insn2 insn2;
bool is_64bit_p; bool is_64bit_p;
int memmodel_attr;
enum memmodel model;
/* Read an operand from the sync_WHAT attribute and store it in /* Read an operand from the sync_WHAT attribute and store it in
variable WHAT. DEFAULT is the default value if no attribute variable WHAT. DEFAULT is the default value if no attribute
...@@ -12017,6 +12058,7 @@ mips_process_sync_loop (rtx insn, rtx *operands) ...@@ -12017,6 +12058,7 @@ mips_process_sync_loop (rtx insn, rtx *operands)
/* Read the other attributes. */ /* Read the other attributes. */
at = gen_rtx_REG (GET_MODE (mem), AT_REGNUM); at = gen_rtx_REG (GET_MODE (mem), AT_REGNUM);
READ_OPERAND (oldval, at); READ_OPERAND (oldval, at);
READ_OPERAND (cmp, 0);
READ_OPERAND (newval, at); READ_OPERAND (newval, at);
READ_OPERAND (inclusive_mask, 0); READ_OPERAND (inclusive_mask, 0);
READ_OPERAND (exclusive_mask, 0); READ_OPERAND (exclusive_mask, 0);
...@@ -12025,10 +12067,23 @@ mips_process_sync_loop (rtx insn, rtx *operands) ...@@ -12025,10 +12067,23 @@ mips_process_sync_loop (rtx insn, rtx *operands)
insn1 = get_attr_sync_insn1 (insn); insn1 = get_attr_sync_insn1 (insn);
insn2 = get_attr_sync_insn2 (insn); insn2 = get_attr_sync_insn2 (insn);
memmodel_attr = get_attr_sync_memmodel (insn);
switch (memmodel_attr)
{
case 10:
model = MEMMODEL_ACQ_REL;
break;
case 11:
model = MEMMODEL_ACQUIRE;
break;
default:
model = INTVAL (operands[memmodel_attr]);
}
mips_multi_start (); mips_multi_start ();
/* Output the release side of the memory barrier. */ /* Output the release side of the memory barrier. */
if (get_attr_sync_release_barrier (insn) == SYNC_RELEASE_BARRIER_YES) if (mips_emit_pre_atomic_barrier_p (model))
{ {
if (required_oldval == 0 && TARGET_OCTEON) if (required_oldval == 0 && TARGET_OCTEON)
{ {
...@@ -12066,6 +12121,10 @@ mips_process_sync_loop (rtx insn, rtx *operands) ...@@ -12066,6 +12121,10 @@ mips_process_sync_loop (rtx insn, rtx *operands)
tmp1 = at; tmp1 = at;
} }
mips_multi_add_insn ("bne\t%0,%z1,2f", tmp1, required_oldval, NULL); mips_multi_add_insn ("bne\t%0,%z1,2f", tmp1, required_oldval, NULL);
/* CMP = 0 [delay slot]. */
if (cmp)
mips_multi_add_insn ("li\t%0,0", cmp, NULL);
} }
/* $TMP1 = OLDVAL & EXCLUSIVE_MASK. */ /* $TMP1 = OLDVAL & EXCLUSIVE_MASK. */
...@@ -12129,11 +12188,15 @@ mips_process_sync_loop (rtx insn, rtx *operands) ...@@ -12129,11 +12188,15 @@ mips_process_sync_loop (rtx insn, rtx *operands)
mips_multi_copy_insn (tmp3_insn); mips_multi_copy_insn (tmp3_insn);
mips_multi_set_operand (mips_multi_last_index (), 0, newval); mips_multi_set_operand (mips_multi_last_index (), 0, newval);
} }
else else if (!(required_oldval && cmp))
mips_multi_add_insn ("nop", NULL); mips_multi_add_insn ("nop", NULL);
/* CMP = 1 -- either standalone or in a delay slot. */
if (required_oldval && cmp)
mips_multi_add_insn ("li\t%0,1", cmp, NULL);
/* Output the acquire side of the memory barrier. */ /* Output the acquire side of the memory barrier. */
if (TARGET_SYNC_AFTER_SC) if (TARGET_SYNC_AFTER_SC && mips_emit_post_atomic_barrier_p (model))
mips_multi_add_insn ("sync", NULL); mips_multi_add_insn ("sync", NULL);
/* Output the exit label, if needed. */ /* Output the exit label, if needed. */
......
...@@ -349,13 +349,15 @@ ...@@ -349,13 +349,15 @@
;; if (RELEASE_BARRIER == YES) sync ;; if (RELEASE_BARRIER == YES) sync
;; 1: OLDVAL = *MEM ;; 1: OLDVAL = *MEM
;; if ((OLDVAL & INCLUSIVE_MASK) != REQUIRED_OLDVAL) goto 2 ;; if ((OLDVAL & INCLUSIVE_MASK) != REQUIRED_OLDVAL) goto 2
;; CMP = 0 [delay slot]
;; $TMP1 = OLDVAL & EXCLUSIVE_MASK ;; $TMP1 = OLDVAL & EXCLUSIVE_MASK
;; $TMP2 = INSN1 (OLDVAL, INSN1_OP2) ;; $TMP2 = INSN1 (OLDVAL, INSN1_OP2)
;; $TMP3 = INSN2 ($TMP2, INCLUSIVE_MASK) ;; $TMP3 = INSN2 ($TMP2, INCLUSIVE_MASK)
;; $AT |= $TMP1 | $TMP3 ;; $AT |= $TMP1 | $TMP3
;; if (!commit (*MEM = $AT)) goto 1. ;; if (!commit (*MEM = $AT)) goto 1.
;; if (INSN1 != MOVE && INSN1 != LI) NEWVAL = $TMP3 [delay slot] ;; if (INSN1 != MOVE && INSN1 != LI) NEWVAL = $TMP3 [delay slot]
;; sync ;; CMP = 1
;; if (ACQUIRE_BARRIER == YES) sync
;; 2: ;; 2:
;; ;;
;; where "$" values are temporaries and where the other values are ;; where "$" values are temporaries and where the other values are
...@@ -364,6 +366,7 @@ ...@@ -364,6 +366,7 @@
;; specified, the following values are used instead: ;; specified, the following values are used instead:
;; ;;
;; - OLDVAL: $AT ;; - OLDVAL: $AT
;; - CMP: NONE
;; - NEWVAL: $AT ;; - NEWVAL: $AT
;; - INCLUSIVE_MASK: -1 ;; - INCLUSIVE_MASK: -1
;; - REQUIRED_OLDVAL: OLDVAL & INCLUSIVE_MASK ;; - REQUIRED_OLDVAL: OLDVAL & INCLUSIVE_MASK
...@@ -375,6 +378,7 @@ ...@@ -375,6 +378,7 @@
;; but the gen* programs don't yet support that. ;; but the gen* programs don't yet support that.
(define_attr "sync_mem" "none,0,1,2,3,4,5" (const_string "none")) (define_attr "sync_mem" "none,0,1,2,3,4,5" (const_string "none"))
(define_attr "sync_oldval" "none,0,1,2,3,4,5" (const_string "none")) (define_attr "sync_oldval" "none,0,1,2,3,4,5" (const_string "none"))
(define_attr "sync_cmp" "none,0,1,2,3,4,5" (const_string "none"))
(define_attr "sync_newval" "none,0,1,2,3,4,5" (const_string "none")) (define_attr "sync_newval" "none,0,1,2,3,4,5" (const_string "none"))
(define_attr "sync_inclusive_mask" "none,0,1,2,3,4,5" (const_string "none")) (define_attr "sync_inclusive_mask" "none,0,1,2,3,4,5" (const_string "none"))
(define_attr "sync_exclusive_mask" "none,0,1,2,3,4,5" (const_string "none")) (define_attr "sync_exclusive_mask" "none,0,1,2,3,4,5" (const_string "none"))
...@@ -384,8 +388,11 @@ ...@@ -384,8 +388,11 @@
(const_string "move")) (const_string "move"))
(define_attr "sync_insn2" "nop,and,xor,not" (define_attr "sync_insn2" "nop,and,xor,not"
(const_string "nop")) (const_string "nop"))
(define_attr "sync_release_barrier" "yes,no" ;; Memory model specifier.
(const_string "yes")) ;; "0"-"9" values specify the operand that stores the memory model value.
;; "10" specifies MEMMODEL_ACQ_REL,
;; "11" specifies MEMMODEL_ACQUIRE.
(define_attr "sync_memmodel" "" (const_int 10))
;; Length of instruction in bytes. ;; Length of instruction in bytes.
(define_attr "length" "" (define_attr "length" ""
......
...@@ -29,6 +29,9 @@ ...@@ -29,6 +29,9 @@
UNSPEC_SYNC_EXCHANGE UNSPEC_SYNC_EXCHANGE
UNSPEC_SYNC_EXCHANGE_12 UNSPEC_SYNC_EXCHANGE_12
UNSPEC_MEMORY_BARRIER UNSPEC_MEMORY_BARRIER
UNSPEC_ATOMIC_COMPARE_AND_SWAP
UNSPEC_ATOMIC_EXCHANGE
UNSPEC_ATOMIC_FETCH_OP
]) ])
;; Atomic fetch bitwise operations. ;; Atomic fetch bitwise operations.
...@@ -54,6 +57,7 @@ ...@@ -54,6 +57,7 @@
"GENERATE_SYNC" "GENERATE_SYNC"
{ return mips_output_sync (); }) { return mips_output_sync (); })
;; Can be removed in favor of atomic_compare_and_swap below.
(define_insn "sync_compare_and_swap<mode>" (define_insn "sync_compare_and_swap<mode>"
[(set (match_operand:GPR 0 "register_operand" "=&d,&d") [(set (match_operand:GPR 0 "register_operand" "=&d,&d")
(match_operand:GPR 1 "memory_operand" "+R,R")) (match_operand:GPR 1 "memory_operand" "+R,R"))
...@@ -368,6 +372,7 @@ ...@@ -368,6 +372,7 @@
(set_attr "sync_mem" "0") (set_attr "sync_mem" "0")
(set_attr "sync_insn1_op2" "1")]) (set_attr "sync_insn1_op2" "1")])
;; Can be removed in favor of atomic_fetch_add below.
(define_insn "sync_old_add<mode>" (define_insn "sync_old_add<mode>"
[(set (match_operand:GPR 0 "register_operand" "=&d,&d") [(set (match_operand:GPR 0 "register_operand" "=&d,&d")
(match_operand:GPR 1 "memory_operand" "+R,R")) (match_operand:GPR 1 "memory_operand" "+R,R"))
...@@ -521,7 +526,7 @@ ...@@ -521,7 +526,7 @@
UNSPEC_SYNC_EXCHANGE))] UNSPEC_SYNC_EXCHANGE))]
"GENERATE_LL_SC" "GENERATE_LL_SC"
{ return mips_output_sync_loop (insn, operands); } { return mips_output_sync_loop (insn, operands); }
[(set_attr "sync_release_barrier" "no") [(set_attr "sync_memmodel" "11")
(set_attr "sync_insn1" "li,move") (set_attr "sync_insn1" "li,move")
(set_attr "sync_oldval" "0") (set_attr "sync_oldval" "0")
(set_attr "sync_mem" "1") (set_attr "sync_mem" "1")
...@@ -550,7 +555,7 @@ ...@@ -550,7 +555,7 @@
UNSPEC_SYNC_EXCHANGE_12))] UNSPEC_SYNC_EXCHANGE_12))]
"GENERATE_LL_SC" "GENERATE_LL_SC"
{ return mips_output_sync_loop (insn, operands); } { return mips_output_sync_loop (insn, operands); }
[(set_attr "sync_release_barrier" "no") [(set_attr "sync_memmodel" "11")
(set_attr "sync_oldval" "0") (set_attr "sync_oldval" "0")
(set_attr "sync_mem" "1") (set_attr "sync_mem" "1")
;; Unused, but needed to give the number of operands expected by ;; Unused, but needed to give the number of operands expected by
...@@ -558,3 +563,101 @@ ...@@ -558,3 +563,101 @@
(set_attr "sync_inclusive_mask" "2") (set_attr "sync_inclusive_mask" "2")
(set_attr "sync_exclusive_mask" "3") (set_attr "sync_exclusive_mask" "3")
(set_attr "sync_insn1_op2" "4")]) (set_attr "sync_insn1_op2" "4")])
(define_insn "atomic_compare_and_swap<mode>"
[(set (match_operand:GPR 0 "register_operand" "=&d,&d")
;; Logically this unspec is an "eq" operator, but we need to obscure
;; reads and writes from/to memory with an unspec to prevent
;; optimizations on shared memory locations. Otherwise, comparison in
;; { mem = 2; if (atomic_cmp_swap(mem,...) == 2) ...; }
;; would be optimized away. In addition to that we need to use
;; unspec_volatile, not just plain unspec -- for the sake of other
;; threads -- to make sure we don't remove the entirety of the pattern
;; just because current thread doesn't observe any effect from it.
;; TODO: the obscuring unspec can be relaxed for permissive memory
;; models.
;; Same applies to other atomic_* patterns.
(unspec_volatile:GPR [(match_operand:GPR 2 "memory_operand" "+R,R")
(match_operand:GPR 3 "reg_or_0_operand" "dJ,dJ")]
UNSPEC_ATOMIC_COMPARE_AND_SWAP))
(set (match_operand:GPR 1 "register_operand" "=&d,&d")
(unspec_volatile:GPR [(match_dup 2)]
UNSPEC_ATOMIC_COMPARE_AND_SWAP))
(set (match_dup 2)
(unspec_volatile:GPR [(match_dup 2)
(match_dup 3)
(match_operand:GPR 4 "arith_operand" "I,d")]
UNSPEC_ATOMIC_COMPARE_AND_SWAP))
(unspec_volatile:GPR [(match_operand:SI 5 "const_int_operand")
(match_operand:SI 6 "const_int_operand")
(match_operand:SI 7 "const_int_operand")]
UNSPEC_ATOMIC_COMPARE_AND_SWAP)]
"GENERATE_LL_SC"
{ return mips_output_sync_loop (insn, operands); }
[(set_attr "sync_insn1" "li,move")
(set_attr "sync_oldval" "1")
(set_attr "sync_cmp" "0")
(set_attr "sync_mem" "2")
(set_attr "sync_required_oldval" "3")
(set_attr "sync_insn1_op2" "4")
(set_attr "sync_memmodel" "6")])
(define_expand "atomic_exchange<mode>"
[(match_operand:GPR 0 "register_operand")
(match_operand:GPR 1 "memory_operand")
(match_operand:GPR 2 "arith_operand")
(match_operand:SI 3 "const_int_operand")]
"GENERATE_LL_SC"
{
emit_insn (gen_atomic_exchange<mode>_llsc (operands[0], operands[1],
operands[2], operands[3]));
DONE;
})
(define_insn "atomic_exchange<mode>_llsc"
[(set (match_operand:GPR 0 "register_operand" "=&d,&d")
(unspec_volatile:GPR [(match_operand:GPR 1 "memory_operand" "+R,R")]
UNSPEC_ATOMIC_EXCHANGE))
(set (match_dup 1)
(unspec_volatile:GPR [(match_operand:GPR 2 "arith_operand" "I,d")]
UNSPEC_ATOMIC_EXCHANGE))
(unspec_volatile:GPR [(match_operand:SI 3 "const_int_operand")]
UNSPEC_ATOMIC_EXCHANGE)]
"GENERATE_LL_SC"
{ return mips_output_sync_loop (insn, operands); }
[(set_attr "sync_insn1" "li,move")
(set_attr "sync_oldval" "0")
(set_attr "sync_mem" "1")
(set_attr "sync_insn1_op2" "2")
(set_attr "sync_memmodel" "3")])
(define_expand "atomic_fetch_add<mode>"
[(match_operand:GPR 0 "register_operand")
(match_operand:GPR 1 "memory_operand")
(match_operand:GPR 2 "arith_operand")
(match_operand:SI 3 "const_int_operand")]
"GENERATE_LL_SC"
{
emit_insn (gen_atomic_fetch_add<mode>_llsc (operands[0], operands[1],
operands[2], operands[3]));
DONE;
})
(define_insn "atomic_fetch_add<mode>_llsc"
[(set (match_operand:GPR 0 "register_operand" "=&d,&d")
(unspec_volatile:GPR [(match_operand:GPR 1 "memory_operand" "+R,R")]
UNSPEC_ATOMIC_FETCH_OP))
(set (match_dup 1)
(unspec_volatile:GPR
[(plus:GPR (match_dup 1)
(match_operand:GPR 2 "arith_operand" "I,d"))]
UNSPEC_ATOMIC_FETCH_OP))
(unspec_volatile:GPR [(match_operand:SI 3 "const_int_operand")]
UNSPEC_ATOMIC_FETCH_OP)]
"GENERATE_LL_SC"
{ return mips_output_sync_loop (insn, operands); }
[(set_attr "sync_insn1" "addiu,addu")
(set_attr "sync_oldval" "0")
(set_attr "sync_mem" "1")
(set_attr "sync_insn1_op2" "2")
(set_attr "sync_memmodel" "3")])
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment