summaryrefslogtreecommitdiff
path: root/gcc/config/mips/sync.md
diff options
context:
space:
mode:
authormkuvyrkov <mkuvyrkov@138bc75d-0d04-0410-961f-82ee72b054a4>2012-06-20 00:57:23 +0000
committermkuvyrkov <mkuvyrkov@138bc75d-0d04-0410-961f-82ee72b054a4>2012-06-20 00:57:23 +0000
commit39a8c5eaded1e5771a941c56a49ca0a5e9c5eca0 (patch)
treecc80416977299664a93d282bbcace60a7d765062 /gcc/config/mips/sync.md
parentd0c24bc90505bf4409fed3622482b24d23dfc596 (diff)
downloadgcc-39a8c5eaded1e5771a941c56a49ca0a5e9c5eca0.tar.gz
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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@188803 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/config/mips/sync.md')
-rw-r--r--gcc/config/mips/sync.md107
1 files changed, 105 insertions, 2 deletions
diff --git a/gcc/config/mips/sync.md b/gcc/config/mips/sync.md
index 1b4097ec225..604aefa3d0e 100644
--- a/gcc/config/mips/sync.md
+++ b/gcc/config/mips/sync.md
@@ -29,6 +29,9 @@
UNSPEC_SYNC_EXCHANGE
UNSPEC_SYNC_EXCHANGE_12
UNSPEC_MEMORY_BARRIER
+ UNSPEC_ATOMIC_COMPARE_AND_SWAP
+ UNSPEC_ATOMIC_EXCHANGE
+ UNSPEC_ATOMIC_FETCH_OP
])
;; Atomic fetch bitwise operations.
@@ -54,6 +57,7 @@
"GENERATE_SYNC"
{ return mips_output_sync (); })
+;; Can be removed in favor of atomic_compare_and_swap below.
(define_insn "sync_compare_and_swap<mode>"
[(set (match_operand:GPR 0 "register_operand" "=&d,&d")
(match_operand:GPR 1 "memory_operand" "+R,R"))
@@ -368,6 +372,7 @@
(set_attr "sync_mem" "0")
(set_attr "sync_insn1_op2" "1")])
+;; Can be removed in favor of atomic_fetch_add below.
(define_insn "sync_old_add<mode>"
[(set (match_operand:GPR 0 "register_operand" "=&d,&d")
(match_operand:GPR 1 "memory_operand" "+R,R"))
@@ -521,7 +526,7 @@
UNSPEC_SYNC_EXCHANGE))]
"GENERATE_LL_SC"
{ 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_oldval" "0")
(set_attr "sync_mem" "1")
@@ -550,7 +555,7 @@
UNSPEC_SYNC_EXCHANGE_12))]
"GENERATE_LL_SC"
{ 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_mem" "1")
;; Unused, but needed to give the number of operands expected by
@@ -558,3 +563,101 @@
(set_attr "sync_inclusive_mask" "2")
(set_attr "sync_exclusive_mask" "3")
(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")])