123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199 |
- /*
- * Copyright (c) 1991-1994 by Xerox Corporation. All rights reserved.
- * Copyright (c) 1996-1999 by Silicon Graphics. All rights reserved.
- * Copyright (c) 1999-2003 by Hewlett-Packard Company. All rights reserved.
- *
- *
- * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
- * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
- *
- * Permission is hereby granted to use or copy this program
- * for any purpose, provided the above notices are retained on all copies.
- * Permission to modify the code and to distribute modified code is granted,
- * provided the above notices are retained, and a notice that the code was
- * modified is included with the above copyright notice.
- *
- */
- #include "../test_and_set_t_is_ao_t.h"
- #include "../standard_ao_double_t.h"
- #ifndef AO_UNIPROCESSOR
- AO_INLINE void
- AO_nop_write(void)
- {
- __asm__ __volatile__("dmb st" : : : "memory");
- }
- # define AO_HAVE_nop_write
- #endif
- /* TODO: Adjust version check on fixing double-wide AO support in GCC. */
- #if __GNUC__ >= 4
- AO_INLINE AO_double_t
- AO_double_load(const volatile AO_double_t *addr)
- {
- AO_double_t result;
- int status;
- /* Note that STXP cannot be discarded because LD[A]XP is not */
- /* single-copy atomic (unlike LDREXD for 32-bit ARM). */
- do {
- __asm__ __volatile__("//AO_double_load\n"
- " ldxp %0, %1, %3\n"
- " stxp %w2, %0, %1, %3"
- : "=&r" (result.AO_val1), "=&r" (result.AO_val2), "=&r" (status)
- : "Q" (*addr));
- } while (AO_EXPECT_FALSE(status));
- return result;
- }
- # define AO_HAVE_double_load
- AO_INLINE AO_double_t
- AO_double_load_acquire(const volatile AO_double_t *addr)
- {
- AO_double_t result;
- int status;
- do {
- __asm__ __volatile__("//AO_double_load_acquire\n"
- " ldaxp %0, %1, %3\n"
- " stxp %w2, %0, %1, %3"
- : "=&r" (result.AO_val1), "=&r" (result.AO_val2), "=&r" (status)
- : "Q" (*addr));
- } while (AO_EXPECT_FALSE(status));
- return result;
- }
- # define AO_HAVE_double_load_acquire
- AO_INLINE void
- AO_double_store(volatile AO_double_t *addr, AO_double_t value)
- {
- AO_double_t old_val;
- int status;
- do {
- __asm__ __volatile__("//AO_double_store\n"
- " ldxp %0, %1, %3\n"
- " stxp %w2, %4, %5, %3"
- : "=&r" (old_val.AO_val1), "=&r" (old_val.AO_val2), "=&r" (status),
- "=Q" (*addr)
- : "r" (value.AO_val1), "r" (value.AO_val2));
- /* Compared to the arm.h implementation, the 'cc' (flags) are not */
- /* clobbered because A64 has no concept of conditional execution. */
- } while (AO_EXPECT_FALSE(status));
- }
- # define AO_HAVE_double_store
- AO_INLINE void
- AO_double_store_release(volatile AO_double_t *addr, AO_double_t value)
- {
- AO_double_t old_val;
- int status;
- do {
- __asm__ __volatile__("//AO_double_store_release\n"
- " ldxp %0, %1, %3\n"
- " stlxp %w2, %4, %5, %3"
- : "=&r" (old_val.AO_val1), "=&r" (old_val.AO_val2), "=&r" (status),
- "=Q" (*addr)
- : "r" (value.AO_val1), "r" (value.AO_val2));
- } while (AO_EXPECT_FALSE(status));
- }
- # define AO_HAVE_double_store_release
- AO_INLINE int
- AO_double_compare_and_swap(volatile AO_double_t *addr,
- AO_double_t old_val, AO_double_t new_val)
- {
- AO_double_t tmp;
- int result = 1;
- do {
- __asm__ __volatile__("//AO_double_compare_and_swap\n"
- " ldxp %0, %1, %2\n"
- : "=&r" (tmp.AO_val1), "=&r" (tmp.AO_val2)
- : "Q" (*addr));
- if (tmp.AO_val1 != old_val.AO_val1 || tmp.AO_val2 != old_val.AO_val2)
- break;
- __asm__ __volatile__(
- " stxp %w0, %2, %3, %1\n"
- : "=&r" (result), "=Q" (*addr)
- : "r" (new_val.AO_val1), "r" (new_val.AO_val2));
- } while (AO_EXPECT_FALSE(result));
- return !result;
- }
- # define AO_HAVE_double_compare_and_swap
- AO_INLINE int
- AO_double_compare_and_swap_acquire(volatile AO_double_t *addr,
- AO_double_t old_val, AO_double_t new_val)
- {
- AO_double_t tmp;
- int result = 1;
- do {
- __asm__ __volatile__("//AO_double_compare_and_swap_acquire\n"
- " ldaxp %0, %1, %2\n"
- : "=&r" (tmp.AO_val1), "=&r" (tmp.AO_val2)
- : "Q" (*addr));
- if (tmp.AO_val1 != old_val.AO_val1 || tmp.AO_val2 != old_val.AO_val2)
- break;
- __asm__ __volatile__(
- " stxp %w0, %2, %3, %1\n"
- : "=&r" (result), "=Q" (*addr)
- : "r" (new_val.AO_val1), "r" (new_val.AO_val2));
- } while (AO_EXPECT_FALSE(result));
- return !result;
- }
- # define AO_HAVE_double_compare_and_swap_acquire
- AO_INLINE int
- AO_double_compare_and_swap_release(volatile AO_double_t *addr,
- AO_double_t old_val, AO_double_t new_val)
- {
- AO_double_t tmp;
- int result = 1;
- do {
- __asm__ __volatile__("//AO_double_compare_and_swap_release\n"
- " ldxp %0, %1, %2\n"
- : "=&r" (tmp.AO_val1), "=&r" (tmp.AO_val2)
- : "Q" (*addr));
- if (tmp.AO_val1 != old_val.AO_val1 || tmp.AO_val2 != old_val.AO_val2)
- break;
- __asm__ __volatile__(
- " stlxp %w0, %2, %3, %1\n"
- : "=&r" (result), "=Q" (*addr)
- : "r" (new_val.AO_val1), "r" (new_val.AO_val2));
- } while (AO_EXPECT_FALSE(result));
- return !result;
- }
- # define AO_HAVE_double_compare_and_swap_release
- AO_INLINE int
- AO_double_compare_and_swap_full(volatile AO_double_t *addr,
- AO_double_t old_val, AO_double_t new_val)
- {
- AO_double_t tmp;
- int result = 1;
- do {
- __asm__ __volatile__("//AO_double_compare_and_swap_full\n"
- " ldaxp %0, %1, %2\n"
- : "=&r" (tmp.AO_val1), "=&r" (tmp.AO_val2)
- : "Q" (*addr));
- if (tmp.AO_val1 != old_val.AO_val1 || tmp.AO_val2 != old_val.AO_val2)
- break;
- __asm__ __volatile__(
- " stlxp %w0, %2, %3, %1\n"
- : "=&r" (result), "=Q" (*addr)
- : "r" (new_val.AO_val1), "r" (new_val.AO_val2));
- } while (AO_EXPECT_FALSE(result));
- return !result;
- }
- # define AO_HAVE_double_compare_and_swap_full
- #endif /* __GNUC__ >= 4 */
- #include "generic.h"
|