aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXi Ruoyao <xry111@xry111.site>2025-03-01 11:46:57 +0800
committerLulu Cheng <chenglulu@loongson.cn>2025-08-18 09:09:38 +0800
commit534276f1e5889f2ce5b5238e68b395a92a79761b (patch)
tree09cb6e7edb307483c68685312497231ebf230b2c
parent54a3853e5f1c73784d49e05272692697e95e2769 (diff)
downloadgcc-534276f1e5889f2ce5b5238e68b395a92a79761b.zip
gcc-534276f1e5889f2ce5b5238e68b395a92a79761b.tar.gz
gcc-534276f1e5889f2ce5b5238e68b395a92a79761b.tar.bz2
LoongArch: Implement 16-byte atomic add, sub, and, or, xor, and nand with sc.q
gcc/ChangeLog: * config/loongarch/sync.md (UNSPEC_TI_FETCH_ADD): New unspec. (UNSPEC_TI_FETCH_SUB): Likewise. (UNSPEC_TI_FETCH_AND): Likewise. (UNSPEC_TI_FETCH_XOR): Likewise. (UNSPEC_TI_FETCH_OR): Likewise. (UNSPEC_TI_FETCH_NAND_MASK_INVERTED): Likewise. (ALL_SC): New define_mode_iterator. (_scq): New define_mode_attr. (atomic_fetch_nand<mode>): Accept ALL_SC instead of only GPR. (UNSPEC_TI_FETCH_DIRECT): New define_int_iterator. (UNSPEC_TI_FETCH): New define_int_iterator. (amop_ti_fetch): New define_int_attr. (size_ti_fetch): New define_int_attr. (atomic_fetch_<amop_ti_fetch>ti_scq): New define_insn. (atomic_fetch_<amop_ti_fetch>ti): New define_expand.
-rw-r--r--gcc/config/loongarch/sync.md117
1 files changed, 111 insertions, 6 deletions
diff --git a/gcc/config/loongarch/sync.md b/gcc/config/loongarch/sync.md
index 2624bbf..2ee400e 100644
--- a/gcc/config/loongarch/sync.md
+++ b/gcc/config/loongarch/sync.md
@@ -30,6 +30,13 @@
UNSPEC_ATOMIC_STORE
UNSPEC_ATOMIC_LOAD
UNSPEC_MEMORY_BARRIER
+
+ UNSPEC_TI_FETCH_ADD
+ UNSPEC_TI_FETCH_SUB
+ UNSPEC_TI_FETCH_AND
+ UNSPEC_TI_FETCH_XOR
+ UNSPEC_TI_FETCH_OR
+ UNSPEC_TI_FETCH_NAND_MASK_INVERTED
])
(define_code_iterator any_atomic [plus ior xor and])
@@ -323,11 +330,13 @@
}
[(set (attr "length") (const_int 16))])
+(define_mode_iterator ALL_SC [GPR (TI "TARGET_64BIT && ISA_HAS_SCQ")])
+(define_mode_attr _scq [(SI "") (DI "") (TI "_scq")])
(define_expand "atomic_fetch_nand<mode>"
- [(match_operand:GPR 0 "register_operand")
- (match_operand:GPR 1 "memory_operand")
- (match_operand:GPR 2 "reg_or_0_operand")
- (match_operand:SI 3 "const_int_operand")]
+ [(match_operand:ALL_SC 0 "register_operand")
+ (match_operand:ALL_SC 1 "memory_operand")
+ (match_operand:ALL_SC 2 "reg_or_0_operand")
+ (match_operand:SI 3 "const_int_operand")]
""
{
/* ~(atom & mask) = (~mask) | (~atom), so we can hoist
@@ -339,8 +348,9 @@
NULL_RTX, false));
emit_insn (
- gen_atomic_fetch_nand_mask_inverted<mode> (operands[0], operands[1],
- inverted_mask));
+ gen_atomic_fetch_nand_mask_inverted<mode><_scq> (operands[0],
+ operands[1],
+ inverted_mask));
DONE;
})
@@ -880,6 +890,101 @@
DONE;
})
+(define_int_iterator UNSPEC_TI_FETCH_DIRECT
+ [UNSPEC_TI_FETCH_ADD
+ UNSPEC_TI_FETCH_SUB
+ UNSPEC_TI_FETCH_AND
+ UNSPEC_TI_FETCH_XOR
+ UNSPEC_TI_FETCH_OR])
+(define_int_iterator UNSPEC_TI_FETCH
+ [UNSPEC_TI_FETCH_DIRECT UNSPEC_TI_FETCH_NAND_MASK_INVERTED])
+(define_int_attr amop_ti_fetch
+ [(UNSPEC_TI_FETCH_ADD "add")
+ (UNSPEC_TI_FETCH_SUB "sub")
+ (UNSPEC_TI_FETCH_AND "and")
+ (UNSPEC_TI_FETCH_XOR "xor")
+ (UNSPEC_TI_FETCH_OR "or")
+ (UNSPEC_TI_FETCH_NAND_MASK_INVERTED "nand_mask_inverted")])
+(define_int_attr size_ti_fetch
+ [(UNSPEC_TI_FETCH_ADD "36")
+ (UNSPEC_TI_FETCH_SUB "36")
+ (UNSPEC_TI_FETCH_AND "28")
+ (UNSPEC_TI_FETCH_XOR "28")
+ (UNSPEC_TI_FETCH_OR "28")
+ (UNSPEC_TI_FETCH_NAND_MASK_INVERTED "28")])
+
+(define_insn "atomic_fetch_<amop_ti_fetch>ti_scq"
+ [(set (match_operand:TI 0 "register_operand" "=&r")
+ (match_operand:TI 1 "memory_operand" "+ZB"))
+ (set (match_dup 1)
+ (unspec_volatile:TI
+ [(match_dup 0)
+ (match_operand:TI 2 "reg_or_0_operand" "rJ")]
+ UNSPEC_TI_FETCH))
+ (clobber (match_scratch:DI 3 "=&r"))
+ (clobber (match_scratch:DI 4 "=&r"))]
+ "TARGET_64BIT && ISA_HAS_SCQ"
+{
+ output_asm_insn ("1:", operands);
+ output_asm_insn ("ll.d\t%0,%1", operands);
+ if (!ISA_HAS_LD_SEQ_SA)
+ output_asm_insn ("dbar\t0x700", operands);
+ output_asm_insn ("ld.d\t%t0,%b1,8", operands);
+
+ switch (<UNSPEC_TI_FETCH>)
+ {
+ case UNSPEC_TI_FETCH_AND:
+ case UNSPEC_TI_FETCH_OR:
+ case UNSPEC_TI_FETCH_XOR:
+ output_asm_insn ("<amop_ti_fetch>\t%3,%0,%z2", operands);
+ output_asm_insn ("<amop_ti_fetch>\t%4,%t0,%t2", operands);
+ break;
+ case UNSPEC_TI_FETCH_NAND_MASK_INVERTED:
+ output_asm_insn ("orn\t%3,%z2,%0", operands);
+ output_asm_insn ("orn\t%4,%t2,%t0", operands);
+ break;
+ case UNSPEC_TI_FETCH_ADD:
+ case UNSPEC_TI_FETCH_SUB:
+ output_asm_insn ("<amop_ti_fetch>.d\t%3,%0,%z2", operands);
+
+ /* Generate carry bit. */
+ output_asm_insn (
+ <UNSPEC_TI_FETCH> == UNSPEC_TI_FETCH_ADD ? "sltu\t%4,%3,%0"
+ : "sltu\t%4,%0,%3",
+ operands);
+
+ output_asm_insn ("<amop_ti_fetch>.d\t%4,%t0,%4", operands);
+ output_asm_insn ("<amop_ti_fetch>.d\t%4,%4,%t2", operands);
+ break;
+ default:
+ gcc_unreachable ();
+ }
+
+ output_asm_insn ("sc.q\t%3,%4,%1", operands);
+ output_asm_insn ("beqz\t%3,1b", operands);
+
+ return "";
+}
+ [(set_attr "length" "<size_ti_fetch>")])
+
+(define_expand "atomic_fetch_<amop_ti_fetch>ti"
+ [(set (match_operand:TI 0 "register_operand" "=&r")
+ (match_operand:TI 1 "memory_operand" "+ZB"))
+ (set (match_dup 1)
+ (unspec_volatile:TI
+ [(match_dup 0)
+ (match_operand:TI 2 "reg_or_0_operand" "rJ")]
+ UNSPEC_TI_FETCH_DIRECT))
+ (match_operand:SI 3 "const_int_operand")] ;; model
+ "TARGET_64BIT && ISA_HAS_SCQ"
+{
+ /* Model is ignored as sc.q implies a full barrier. */
+ emit_insn (gen_atomic_fetch_<amop_ti_fetch>ti_scq (operands[0],
+ operands[1],
+ operands[2]));
+ DONE;
+})
+
(define_insn "atomic_fetch_add<mode>_short"
[(set (match_operand:SHORT 0 "register_operand" "=&r")
(match_operand:SHORT 1 "memory_operand" "+ZB"))