gcc/ChangeLog: * config/loongarch/sync.md: Add atomic_cas_value_exchange_and_7<mode> and fix atomic_exchange<mode>.
gcc/testsuite/ChangeLog: * gcc.target/loongarch/sync-1.c: New test. --- gcc/config/loongarch/sync.md | 27 ++++- gcc/testsuite/gcc.target/loongarch/sync-1.c | 104 ++++++++++++++++++++ 2 files changed, 129 insertions(+), 2 deletions(-) create mode 100644 gcc/testsuite/gcc.target/loongarch/sync-1.c diff --git a/gcc/config/loongarch/sync.md b/gcc/config/loongarch/sync.md index 0c4f1983e..8a8e6247b 100644 --- a/gcc/config/loongarch/sync.md +++ b/gcc/config/loongarch/sync.md @@ -448,6 +448,29 @@ } [(set (attr "length") (const_int 32))]) +(define_insn "atomic_cas_value_exchange_and_7_<mode>" + [(set (match_operand:GPR 0 "register_operand" "=&r") + (match_operand:GPR 1 "memory_operand" "+ZC")) + (set (match_dup 1) + (unspec_volatile:GPR [(match_operand:GPR 2 "reg_or_0_operand" "rJ") + (match_operand:GPR 3 "reg_or_0_operand" "rJ") + (match_operand:GPR 4 "reg_or_0_operand" "rJ") + (match_operand:GPR 5 "reg_or_0_operand" "rJ") + (match_operand:SI 6 "const_int_operand")] ;; model + UNSPEC_SYNC_EXCHANGE)) + (clobber (match_scratch:GPR 7 "=&r"))] + "" +{ + return "%G6\\n\\t" + "1:\\n\\t" + "ll.<amo>\\t%0,%1\\n\\t" + "and\\t%7,%0,%z3\\n\\t" + "or%i5\\t%7,%7,%5\\n\\t" + "sc.<amo>\\t%7,%1\\n\\t" + "beqz\\t%7,1b\\n\\t"; +} + [(set (attr "length") (const_int 20))]) + (define_expand "atomic_exchange<mode>" [(set (match_operand:SHORT 0 "register_operand") (unspec_volatile:SHORT @@ -459,9 +482,9 @@ "" { union loongarch_gen_fn_ptrs generator; - generator.fn_7 = gen_atomic_cas_value_cmp_and_7_si; + generator.fn_7 = gen_atomic_cas_value_exchange_and_7_si; loongarch_expand_atomic_qihi (generator, operands[0], operands[1], - operands[1], operands[2], operands[3]); + const0_rtx, operands[2], operands[3]); DONE; }) diff --git a/gcc/testsuite/gcc.target/loongarch/sync-1.c b/gcc/testsuite/gcc.target/loongarch/sync-1.c new file mode 100644 index 000000000..cebed6a9b --- /dev/null +++ b/gcc/testsuite/gcc.target/loongarch/sync-1.c @@ -0,0 +1,104 @@ +/* Test __sync_test_and_set in atomic_exchange */ +/* { dg-do run } */ +/* { dg-options "-lpthread -std=c11" } */ + +#include <pthread.h> +#include <sched.h> +#include <stdatomic.h> +#include <stdlib.h> + +#define NR_THREAD 16 +#define NR_DATA 1000 +#define ITER_COUNT 10000 + +static int _data[NR_DATA]; +static char _lock; +static int _overcnt; + +static inline void proc_yield(int cnt) +{ + __asm__ __volatile__("":::"memory"); +} + +static void unlock() +{ + return atomic_store_explicit(&_lock, 0, memory_order_seq_cst); +} + +static int trylock() +{ + return atomic_exchange_explicit(&_lock, 1, memory_order_acquire) == 0; +} + +static void lockslow() +{ + for (int i = 0;; i++) { + if (i < 10) + proc_yield(i); + else + sched_yield(); + if (atomic_load_explicit(&_lock, memory_order_relaxed) == 0 + && atomic_exchange_explicit(&_lock, 1, memory_order_acquire) == 0) + return; + } +} + +static void lock() +{ + if (trylock()) + return; + lockslow(); +} + +static void checkeq(int a, int b) +{ + if (a != b) + __builtin_abort(); +} + +static void adddata() +{ + int i, v; + lock(); + v = _data[0]; + for (i = 0; i < NR_DATA; i++) { + checkeq(_data[i], v); + _data[i]++; + } + unlock(); +} + +static void backoff() +{ + int i, data[NR_DATA] = {0}; + for (i = 0; i < NR_DATA; i++) { + data[i]++; + checkeq(data[i], 1); + } +} + +static void *write_mutex_thread(void *unused) +{ + int i; + for (i = 0; i < ITER_COUNT; i++) { + adddata(); + backoff(); + } + atomic_fetch_add(&_overcnt, 1); +} + +int main() +{ + int cnt; + + pthread_t threads[NR_THREAD]; + for (int i = 0; i < NR_THREAD; i++) + pthread_create(&threads[i], 0, write_mutex_thread, NULL); + for (int i = 0; i < NR_THREAD; i++) + pthread_detach(threads[i]); + while(cnt != NR_THREAD) { + sched_yield(); + cnt = atomic_load(&_overcnt); + } + return 0; +} -- 2.34.3