summaryrefslogtreecommitdiff
path: root/libpthread/nptl/sysdeps/unix/sysv/linux/arm/bits/atomic.h
diff options
context:
space:
mode:
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.h114
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__ */