diff options
Diffstat (limited to 'libpthread/nptl/sysdeps/unix/sysv/linux/arm/bits/atomic.h')
-rw-r--r-- | libpthread/nptl/sysdeps/unix/sysv/linux/arm/bits/atomic.h | 114 |
1 files changed, 50 insertions, 64 deletions
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/bits/atomic.h b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/bits/atomic.h index 49a935a52..b0586ea1e 100644 --- a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/bits/atomic.h +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/bits/atomic.h @@ -37,61 +37,21 @@ typedef uintmax_t uatomic_max_t; void __arm_link_error (void); -#ifdef __thumb__ - -/* Note that to allow efficient implementation the arguemtns are reversed - relative to atomic_exchange_acq. */ -int __thumb_swpb (int newvalue, void *mem) - attribute_hidden; -unsigned int __thumb_swp (unsigned int newvalue, void *mem) - attribute_hidden; -unsigned int __thumb_cmpxchg (unsigned int oldval, unsigned int newval, void *mem) - attribute_hidden; - -#define atomic_exchange_acq(mem, newvalue) \ - ({ __typeof (*mem) result; \ - if (sizeof (*mem) == 1) \ - result = __thumb_swpb (newvalue, mem); \ - else if (sizeof (*mem) == 4) \ - result = __thumb_swp (newvalue, mem); \ - else \ - { \ - result = 0; \ - abort (); \ - } \ - result; }) - -#define __arch_compare_and_exchange_val_8_acq(mem, newval, oldval) \ - ({ __arm_link_error (); oldval; }) - -#define __arch_compare_and_exchange_val_16_acq(mem, newval, oldval) \ - ({ __arm_link_error (); oldval; }) - -#define __arch_compare_and_exchange_val_32_acq(mem, newval, oldval) \ - ((__typeof (oldval)) __thumb_cmpxchg (oldval, newval, mem)) - -#define __arch_compare_and_exchange_val_64_acq(mem, newval, oldval) \ - ({ __arm_link_error (); oldval; }) - +#ifdef __thumb2__ +#define atomic_full_barrier() \ + __asm__ __volatile__ \ + ("movw\tip, #0x0fa0\n\t" \ + "movt\tip, #0xffff\n\t" \ + "blx\tip" \ + : : : "ip", "lr", "cc", "memory"); #else -/* ARM mode. */ - -#define atomic_exchange_acq(mem, newvalue) \ - ({ __typeof (*mem) _xchg_result; \ - if (sizeof (*mem) == 1) \ - __asm__ __volatile__ ("swpb %0, %1, [%2]" \ - : "=&r,&r" (_xchg_result) \ - : "r,0" (newvalue), "r,r" (mem) : "memory"); \ - else if (sizeof (*mem) == 4) \ - __asm__ __volatile__ ("swp %0, %1, [%2]" \ - : "=&r,&r" (_xchg_result) \ - : "r,0" (newvalue), "r,r" (mem) : "memory"); \ - else \ - { \ - _xchg_result = 0; \ - abort (); \ - } \ - _xchg_result; }) +#define atomic_full_barrier() \ + __asm__ __volatile__ \ + ("mov\tip, #0xffff0fff\n\t" \ + "mov\tlr, pc\n\t" \ + "add\tpc, ip, #(0xffff0fa0 - 0xffff0fff)" \ + : : : "ip", "lr", "cc", "memory"); +#endif /* Atomic compare and exchange. This sequence relies on the kernel to provide a compare and exchange operation which is atomic on the @@ -108,6 +68,9 @@ unsigned int __thumb_cmpxchg (unsigned int oldval, unsigned int newval, void *me specify one to work around GCC PR rtl-optimization/21223. Otherwise it may cause a_oldval or a_tmp to be moved to a different register. */ +#ifdef __thumb2__ +/* Thumb-2 has ldrex/strex. However it does not have barrier instructions, + so we still need to use the kernel helper. */ #define __arch_compare_and_exchange_val_32_acq(mem, newval, oldval) \ ({ register __typeof (oldval) a_oldval asm ("r0"); \ register __typeof (oldval) a_newval asm ("r1") = (newval); \ @@ -115,22 +78,45 @@ unsigned int __thumb_cmpxchg (unsigned int oldval, unsigned int newval, void *me register __typeof (oldval) a_tmp asm ("r3"); \ register __typeof (oldval) a_oldval2 asm ("r4") = (oldval); \ __asm__ __volatile__ \ - ("0:\tldr\t%1,[%3]\n\t" \ - "cmp\t%1, %4\n\t" \ + ("0:\tldr\t%[tmp],[%[ptr]]\n\t" \ + "cmp\t%[tmp], %[old2]\n\t" \ "bne\t1f\n\t" \ - "mov\t%0, %4\n\t" \ - "mov\t%1, #0xffff0fff\n\t" \ + "mov\t%[old], %[old2]\n\t" \ + "movw\t%[tmp], #0x0fc0\n\t" \ + "movt\t%[tmp], #0xffff\n\t" \ + "blx\t%[tmp]\n\t" \ + "bcc\t0b\n\t" \ + "mov\t%[tmp], %[old2]\n\t" \ + "1:" \ + : [old] "=&r" (a_oldval), [tmp] "=&r" (a_tmp) \ + : [new] "r" (a_newval), [ptr] "r" (a_ptr), \ + [old2] "r" (a_oldval2) \ + : "ip", "lr", "cc", "memory"); \ + a_tmp; }) +#else +#define __arch_compare_and_exchange_val_32_acq(mem, newval, oldval) \ + ({ register __typeof (oldval) a_oldval asm ("r0"); \ + register __typeof (oldval) a_newval asm ("r1") = (newval); \ + register __typeof (mem) a_ptr asm ("r2") = (mem); \ + register __typeof (oldval) a_tmp asm ("r3"); \ + register __typeof (oldval) a_oldval2 asm ("r4") = (oldval); \ + __asm__ __volatile__ \ + ("0:\tldr\t%[tmp],[%[ptr]]\n\t" \ + "cmp\t%[tmp], %[old2]\n\t" \ + "bne\t1f\n\t" \ + "mov\t%[old], %[old2]\n\t" \ + "mov\t%[tmp], #0xffff0fff\n\t" \ "mov\tlr, pc\n\t" \ - "add\tpc, %1, #(0xffff0fc0 - 0xffff0fff)\n\t" \ + "add\tpc, %[tmp], #(0xffff0fc0 - 0xffff0fff)\n\t" \ "bcc\t0b\n\t" \ - "mov\t%1, %4\n\t" \ + "mov\t%[tmp], %[old2]\n\t" \ "1:" \ - : "=&r" (a_oldval), "=&r" (a_tmp) \ - : "r" (a_newval), "r" (a_ptr), "r" (a_oldval2) \ + : [old] "=&r" (a_oldval), [tmp] "=&r" (a_tmp) \ + : [new] "r" (a_newval), [ptr] "r" (a_ptr), \ + [old2] "r" (a_oldval2) \ : "ip", "lr", "cc", "memory"); \ a_tmp; }) +#endif #define __arch_compare_and_exchange_val_64_acq(mem, newval, oldval) \ ({ __arm_link_error (); oldval; }) - -#endif /* __thumb__ */ |