- /* The return value is semi-phony. */
- /* 'tas' sets bit 7 while the return */
- /* value pretends bit 0 was set */
- __asm__ __volatile__(
- "tas %1@; sne %0; negb %0"
- : "=d" (oldval)
- : "a" (addr) : "memory");
- return oldval;
- }
-# define GC_TEST_AND_SET_DEFINED
-# endif
-#endif
-# if defined(POWERPC)
- inline static int GC_test_and_set(volatile unsigned int *addr) {
- int oldval;
- int temp = 1; /* locked value */
-
- __asm__ __volatile__(
- "1:\tlwarx %0,0,%3\n" /* load and reserve */
- "\tcmpwi %0, 0\n" /* if load is */
- "\tbne 2f\n" /* non-zero, return already set */
- "\tstwcx. %2,0,%1\n" /* else store conditional */
- "\tbne- 1b\n" /* retry if lost reservation */
- "\tsync\n" /* import barrier */
- "2:\t\n" /* oldval is zero if we set */
- : "=&r"(oldval), "=p"(addr)
- : "r"(temp), "1"(addr)
- : "cr0","memory");
- return oldval;
- }
-# define GC_TEST_AND_SET_DEFINED
- inline static void GC_clear(volatile unsigned int *addr) {
- __asm__ __volatile__("lwsync" : : : "memory");
- *(addr) = 0;
- }
-# define GC_CLEAR_DEFINED
-# endif
-# if defined(ALPHA)
- inline static int GC_test_and_set(volatile unsigned int * addr)
- {
- unsigned long oldvalue;
- unsigned long temp;
-
- __asm__ __volatile__(
- "1: ldl_l %0,%1\n"
- " and %0,%3,%2\n"
- " bne %2,2f\n"
- " xor %0,%3,%0\n"
- " stl_c %0,%1\n"
-# ifdef __ELF__
- " beq %0,3f\n"
-# else
- " beq %0,1b\n"
-# endif
- " mb\n"
- "2:\n"
-# ifdef __ELF__
- ".section .text2,\"ax\"\n"
- "3: br 1b\n"
- ".previous"
-# endif
- :"=&r" (temp), "=m" (*addr), "=&r" (oldvalue)
- :"Ir" (1), "m" (*addr)
- :"memory");
-
- return oldvalue;
- }
-# define GC_TEST_AND_SET_DEFINED
- inline static void GC_clear(volatile unsigned int *addr) {
- __asm__ __volatile__("mb" : : : "memory");
- *(addr) = 0;
- }
-# define GC_CLEAR_DEFINED
-# endif /* ALPHA */
-# ifdef ARM32
- inline static int GC_test_and_set(volatile unsigned int *addr) {
- int oldval;
- /* SWP on ARM is very similar to XCHG on x86. */
- /* The first operand is the result, the second the value */
- /* to be stored. Both registers must be different from addr. */
- /* Make the address operand an early clobber output so it */
- /* doesn't overlap with the other operands. The early clobber*/
- /* on oldval is neccessary to prevent the compiler allocating */
- /* them to the same register if they are both unused. */
- __asm__ __volatile__("swp %0, %2, [%3]"
- : "=&r"(oldval), "=&r"(addr)
- : "r"(1), "1"(addr)
- : "memory");
- return oldval;
- }
-# define GC_TEST_AND_SET_DEFINED
-# endif /* ARM32 */
-# ifdef CRIS
- inline static int GC_test_and_set(volatile unsigned int *addr) {
- /* Ripped from linuxthreads/sysdeps/cris/pt-machine.h. */
- /* Included with Hans-Peter Nilsson's permission. */
- register unsigned long int ret;
-
- /* Note the use of a dummy output of *addr to expose the write.
- * The memory barrier is to stop *other* writes being moved past
- * this code.
- */
- __asm__ __volatile__("clearf\n"
- "0:\n\t"
- "movu.b [%2],%0\n\t"
- "ax\n\t"
- "move.b %3,[%2]\n\t"
- "bwf 0b\n\t"
- "clearf"
- : "=&r" (ret), "=m" (*addr)
- : "r" (addr), "r" ((int) 1), "m" (*addr)
- : "memory");
- return ret;
- }
-# define GC_TEST_AND_SET_DEFINED
-# endif /* CRIS */
-# ifdef S390
- inline static int GC_test_and_set(volatile unsigned int *addr) {
- int ret;
- __asm__ __volatile__ (
- " l %0,0(%2)\n"
- "0: cs %0,%1,0(%2)\n"
- " jl 0b"
- : "=&d" (ret)
- : "d" (1), "a" (addr)
- : "cc", "memory");
- return ret;
- }
-# endif
-# endif /* __GNUC__ */
-# if (defined(ALPHA) && !defined(__GNUC__))
-# ifndef OSF1
- --> We currently assume that if gcc is not used, we are
- --> running under Tru64.
-# endif
-# include <machine/builtins.h>
-# include <c_asm.h>
-# define GC_test_and_set(addr) __ATOMIC_EXCH_LONG(addr, 1)
-# define GC_TEST_AND_SET_DEFINED
-# define GC_clear(addr) { asm("mb"); *(volatile unsigned *)addr = 0; }
-# define GC_CLEAR_DEFINED
-# endif
-# if defined(MSWIN32)
-# define GC_test_and_set(addr) InterlockedExchange((LPLONG)addr,1)
-# define GC_TEST_AND_SET_DEFINED
-# endif
-# ifdef MIPS
-# ifdef LINUX
-# include <sys/tas.h>
-# define GC_test_and_set(addr) _test_and_set((int *) addr,1)
-# define GC_TEST_AND_SET_DEFINED
-# elif __mips < 3 || !(defined (_ABIN32) || defined(_ABI64)) \
- || !defined(_COMPILER_VERSION) || _COMPILER_VERSION < 700
-# ifdef __GNUC__
-# define GC_test_and_set(addr) _test_and_set((void *)addr,1)
-# else
-# define GC_test_and_set(addr) test_and_set((void *)addr,1)
-# endif
-# else
-# include <sgidefs.h>
-# include <mutex.h>
-# define GC_test_and_set(addr) __test_and_set32((void *)addr,1)
-# define GC_clear(addr) __lock_release(addr);
-# define GC_CLEAR_DEFINED
-# endif
-# define GC_TEST_AND_SET_DEFINED
-# endif /* MIPS */
-# if defined(_AIX)
-# include <sys/atomic_op.h>
-# if (defined(_POWER) || defined(_POWERPC))
-# if defined(__GNUC__)
- inline static void GC_memsync() {
- __asm__ __volatile__ ("sync" : : : "memory");
- }
-# else
-# ifndef inline
-# define inline __inline
-# endif
-# pragma mc_func GC_memsync { \
- "7c0004ac" /* sync (same opcode used for dcs)*/ \
- }
-# endif
-# else
-# error dont know how to memsync
-# endif
- inline static int GC_test_and_set(volatile unsigned int * addr) {
- int oldvalue = 0;
- if (compare_and_swap((void *)addr, &oldvalue, 1)) {
- GC_memsync();
- return 0;
- } else return 1;
- }
-# define GC_TEST_AND_SET_DEFINED
- inline static void GC_clear(volatile unsigned int *addr) {
- GC_memsync();
- *(addr) = 0;
- }
-# define GC_CLEAR_DEFINED
-
-# endif
-# if 0 /* defined(HP_PA) */
- /* The official recommendation seems to be to not use ldcw from */
- /* user mode. Since multithreaded incremental collection doesn't */
- /* work anyway on HP_PA, this shouldn't be a major loss. */
-
- /* "set" means 0 and "clear" means 1 here. */
-# define GC_test_and_set(addr) !GC_test_and_clear(addr);
-# define GC_TEST_AND_SET_DEFINED
-# define GC_clear(addr) GC_noop1((word)(addr)); *(volatile unsigned int *)addr = 1;
- /* The above needs a memory barrier! */
-# define GC_CLEAR_DEFINED