diff options
Diffstat (limited to 'gcc/config/mips/sync.md')
-rw-r--r-- | gcc/config/mips/sync.md | 107 |
1 files changed, 105 insertions, 2 deletions
diff --git a/gcc/config/mips/sync.md b/gcc/config/mips/sync.md index 1b4097e..604aefa 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")]) |