We can just shift the mask and fill the other bits with 0 (for ior/xor)
or 1 (for and), and use an am*.w instruction to perform the atomic
operation, instead of using a LL-SC loop.
gcc/ChangeLog:
* config/loongarch/sync.md (UNSPEC_COMPARE_AND_SWAP_AND):
Remove.
(UNSPEC_COMPARE_AND_SWAP_XOR): Remove.
(UNSPEC_COMPARE_AND_SWAP_OR): Remove.
(atomic_test_and_set): Rename to ...
(atomic_fetch_<any_bitwise:amop><SHORT:mode>): ... this, and
adapt the expansion to use it for any bitwise operations and any
val, instead of just ior 1.
(atomic_test_and_set): New define_expand.
---
gcc/config/loongarch/sync.md | 177 +++++++----------------------------
1 file changed, 34 insertions(+), 143 deletions(-)
diff --git a/gcc/config/loongarch/sync.md b/gcc/config/loongarch/sync.md
index b3666c0c992..b6acfff3a61 100644
--- a/gcc/config/loongarch/sync.md
+++ b/gcc/config/loongarch/sync.md
@@ -24,9 +24,6 @@ (define_c_enum "unspec" [
UNSPEC_COMPARE_AND_SWAP_AMCAS
UNSPEC_COMPARE_AND_SWAP_ADD
UNSPEC_COMPARE_AND_SWAP_SUB
- UNSPEC_COMPARE_AND_SWAP_AND
- UNSPEC_COMPARE_AND_SWAP_XOR
- UNSPEC_COMPARE_AND_SWAP_OR
UNSPEC_COMPARE_AND_SWAP_NAND
UNSPEC_SYNC_OLD_OP
UNSPEC_SYNC_EXCHANGE
@@ -343,17 +340,18 @@ (define_expand "atomic_compare_and_swap<mode>"
DONE;
})
-(define_expand "atomic_test_and_set"
- [(match_operand:QI 0 "register_operand" "") ;; bool output
- (match_operand:QI 1 "memory_operand" "+ZB") ;; memory
- (match_operand:SI 2 "const_int_operand" "")] ;; model
+(define_expand "atomic_fetch_<amop><mode>"
+ [(match_operand:SHORT 0 "register_operand" "") ;; output
+ (any_bitwise (match_operand:SHORT 1 "memory_operand" "+ZB") ;; memory
+ (match_operand:SHORT 2 "reg_or_0_operand" "rJ")) ;; val
+ (match_operand:SI 3 "const_int_operand" "")] ;;
model
""
{
- /* We have no QImode atomics, so use the address LSBs to form a mask,
- then use an aligned SImode atomic. */
+ /* We have no QI/HImode bitwise atomics, so use the address LSBs to form
+ a mask, then use an aligned SImode atomic. */
rtx result = operands[0];
rtx mem = operands[1];
- rtx model = operands[2];
+ rtx model = operands[3];
rtx addr = force_reg (Pmode, XEXP (mem, 0));
rtx mask = gen_int_mode (-4, Pmode);
rtx aligned_addr = gen_reg_rtx (Pmode);
@@ -367,7 +365,8 @@ (define_expand "atomic_test_and_set"
set_mem_alias_set (aligned_mem, 0);
rtx tmp = gen_reg_rtx (SImode);
- emit_move_insn (tmp, GEN_INT (1));
+ emit_move_insn (tmp, simplify_gen_unary (ZERO_EXTEND, SImode,
+ operands[2], <MODE>mode));
/* Note that we have defined SHIFT_COUNT_TRUNCATED to 1, so we don't need
to mask addr with 0b11 here. */
@@ -378,14 +377,37 @@ (define_expand "atomic_test_and_set"
rtx word = gen_reg_rtx (SImode);
emit_move_insn (word, gen_rtx_ASHIFT (SImode, tmp, shmt));
+ if (<is_and>)
+ {
+ /* word = word | ~(mode_mask << shmt) */
+ rtx tmp = force_reg (SImode,
+ gen_int_mode (GET_MODE_MASK (<MODE>mode),
+ SImode));
+ emit_move_insn (tmp, gen_rtx_ASHIFT (SImode, tmp, shmt));
+ emit_move_insn (word, gen_rtx_IOR (SImode, gen_rtx_NOT (SImode, tmp),
+ word));
+ }
+
tmp = gen_reg_rtx (SImode);
- emit_insn (gen_atomic_fetch_orsi (tmp, aligned_mem, word, model));
+ emit_insn (gen_atomic_fetch_<amop>si (tmp, aligned_mem, word, model));
emit_move_insn (gen_lowpart (SImode, result),
gen_rtx_LSHIFTRT (SImode, tmp, shmt));
DONE;
})
+(define_expand "atomic_test_and_set"
+ [(match_operand:QI 0 "register_operand" "") ;; bool output
+ (match_operand:QI 1 "memory_operand" "+ZB") ;; memory
+ (match_operand:SI 2 "const_int_operand" "")] ;; model
+ ""
+{
+ rtx one = force_reg (QImode, gen_int_mode (1, QImode));
+ emit_insn (gen_atomic_fetch_orqi (operands[0], operands[1], one,
+ operands[2]));
+ DONE;
+})
+
(define_insn "atomic_cas_value_cmp_and_7_<mode>"
[(set (match_operand:GPR 0 "register_operand" "=&r")
(match_operand:GPR 1 "memory_operand" "+ZC"))
@@ -524,83 +546,6 @@ (define_insn "atomic_cas_value_sub_7_<mode>"
}
[(set (attr "length") (const_int 28))])
-(define_insn "atomic_cas_value_and_7_<mode>"
- [(set (match_operand:GPR 0 "register_operand" "=&r")
;; res
- (match_operand:GPR 1 "memory_operand" "+ZC"))
- (set (match_dup 1)
- (unspec_volatile:GPR [(match_operand:GPR 2 "reg_or_0_operand" "rJ")
;; mask
- (match_operand:GPR 3 "reg_or_0_operand" "rJ")
;; inverted_mask
- (match_operand:GPR 4 "reg_or_0_operand" "rJ")
;; old val
- (match_operand:GPR 5 "reg_or_0_operand" "rJ")
;; new val
- (match_operand:SI 6 "const_int_operand")]
;; model
- UNSPEC_COMPARE_AND_SWAP_AND))
- (clobber (match_scratch:GPR 7 "=&r"))
- (clobber (match_scratch:GPR 8 "=&r"))]
- ""
-{
- return "1:\\n\\t"
- "ll.<size>\\t%0,%1\\n\\t"
- "and\\t%7,%0,%3\\n\\t"
- "and\\t%8,%0,%z5\\n\\t"
- "and\\t%8,%8,%z2\\n\\t"
- "or%i8\\t%7,%7,%8\\n\\t"
- "sc.<size>\\t%7,%1\\n\\t"
- "beq\\t$zero,%7,1b";
-}
- [(set (attr "length") (const_int 28))])
-
-(define_insn "atomic_cas_value_xor_7_<mode>"
- [(set (match_operand:GPR 0 "register_operand" "=&r")
;; res
- (match_operand:GPR 1 "memory_operand" "+ZC"))
- (set (match_dup 1)
- (unspec_volatile:GPR [(match_operand:GPR 2 "reg_or_0_operand" "rJ")
;; mask
- (match_operand:GPR 3 "reg_or_0_operand" "rJ")
;; inverted_mask
- (match_operand:GPR 4 "reg_or_0_operand" "rJ")
;; old val
- (match_operand:GPR 5 "reg_or_0_operand" "rJ")
;; new val
- (match_operand:SI 6 "const_int_operand")]
;; model
- UNSPEC_COMPARE_AND_SWAP_XOR))
- (clobber (match_scratch:GPR 7 "=&r"))
- (clobber (match_scratch:GPR 8 "=&r"))]
- ""
-{
- return "1:\\n\\t"
- "ll.<size>\\t%0,%1\\n\\t"
- "and\\t%7,%0,%3\\n\\t"
- "xor\\t%8,%0,%z5\\n\\t"
- "and\\t%8,%8,%z2\\n\\t"
- "or%i8\\t%7,%7,%8\\n\\t"
- "sc.<size>\\t%7,%1\\n\\t"
- "beq\\t$zero,%7,1b";
-}
-
- [(set (attr "length") (const_int 28))])
-
-(define_insn "atomic_cas_value_or_7_<mode>"
- [(set (match_operand:GPR 0 "register_operand" "=&r")
;; res
- (match_operand:GPR 1 "memory_operand" "+ZC"))
- (set (match_dup 1)
- (unspec_volatile:GPR [(match_operand:GPR 2 "reg_or_0_operand" "rJ")
;; mask
- (match_operand:GPR 3 "reg_or_0_operand" "rJ")
;; inverted_mask
- (match_operand:GPR 4 "reg_or_0_operand" "rJ")
;; old val
- (match_operand:GPR 5 "reg_or_0_operand" "rJ")
;; new val
- (match_operand:SI 6 "const_int_operand")]
;; model
- UNSPEC_COMPARE_AND_SWAP_OR))
- (clobber (match_scratch:GPR 7 "=&r"))
- (clobber (match_scratch:GPR 8 "=&r"))]
- ""
-{
- return "1:\\n\\t"
- "ll.<size>\\t%0,%1\\n\\t"
- "and\\t%7,%0,%3\\n\\t"
- "or\\t%8,%0,%z5\\n\\t"
- "and\\t%8,%8,%z2\\n\\t"
- "or%i8\\t%7,%7,%8\\n\\t"
- "sc.<size>\\t%7,%1\\n\\t"
- "beq\\t$zero,%7,1b";
-}
-
- [(set (attr "length") (const_int 28))])
-
(define_insn "atomic_cas_value_nand_7_<mode>"
[(set (match_operand:GPR 0 "register_operand" "=&r")
;; res
(match_operand:GPR 1 "memory_operand" "+ZC"))
@@ -725,60 +670,6 @@ (define_expand "atomic_fetch_sub<mode>"
DONE;
})
-(define_expand "atomic_fetch_and<mode>"
- [(set (match_operand:SHORT 0 "register_operand" "=&r")
- (match_operand:SHORT 1 "memory_operand" "+ZB"))
- (set (match_dup 1)
- (unspec_volatile:SHORT
- [(and:SHORT (match_dup 1)
- (match_operand:SHORT 2 "reg_or_0_operand" "rJ"))
- (match_operand:SI 3 "const_int_operand")] ;; model
- UNSPEC_SYNC_OLD_OP))]
- ""
-{
- union loongarch_gen_fn_ptrs generator;
- generator.fn_7 = gen_atomic_cas_value_and_7_si;
- loongarch_expand_atomic_qihi (generator, operands[0], operands[1],
- operands[1], operands[2], operands[3]);
- DONE;
-})
-
-(define_expand "atomic_fetch_xor<mode>"
- [(set (match_operand:SHORT 0 "register_operand" "=&r")
- (match_operand:SHORT 1 "memory_operand" "+ZB"))
- (set (match_dup 1)
- (unspec_volatile:SHORT
- [(xor:SHORT (match_dup 1)
- (match_operand:SHORT 2 "reg_or_0_operand" "rJ"))
- (match_operand:SI 3 "const_int_operand")] ;; model
- UNSPEC_SYNC_OLD_OP))]
- ""
-{
- union loongarch_gen_fn_ptrs generator;
- generator.fn_7 = gen_atomic_cas_value_xor_7_si;
- loongarch_expand_atomic_qihi (generator, operands[0], operands[1],
- operands[1], operands[2], operands[3]);
- DONE;
-})
-
-(define_expand "atomic_fetch_or<mode>"
- [(set (match_operand:SHORT 0 "register_operand" "=&r")
- (match_operand:SHORT 1 "memory_operand" "+ZB"))
- (set (match_dup 1)
- (unspec_volatile:SHORT
- [(ior:SHORT (match_dup 1)
- (match_operand:SHORT 2 "reg_or_0_operand" "rJ"))
- (match_operand:SI 3 "const_int_operand")] ;; model
- UNSPEC_SYNC_OLD_OP))]
- ""
-{
- union loongarch_gen_fn_ptrs generator;
- generator.fn_7 = gen_atomic_cas_value_or_7_si;
- loongarch_expand_atomic_qihi (generator, operands[0], operands[1],
- operands[1], operands[2], operands[3]);
- DONE;
-})
-
(define_expand "atomic_fetch_nand<mode>"
[(set (match_operand:SHORT 0 "register_operand" "=&r")
(match_operand:SHORT 1 "memory_operand" "+ZB"))
--
2.48.1