Author: ian
Date: Mon Feb 10 00:05:04 2020
New Revision: 357709
URL: https://svnweb.freebsd.org/changeset/base/357709

Log:
  Implement atomic_testandclear_{32,int,long} for 32-bit arm.  Also, replace
  the existing implementation of atomic_testandset with the same new algorithm,
  which uses fewer instructions and fewer registers.

Modified:
  head/sys/arm/include/atomic-v6.h

Modified: head/sys/arm/include/atomic-v6.h
==============================================================================
--- head/sys/arm/include/atomic-v6.h    Sun Feb  9 22:40:05 2020        
(r357708)
+++ head/sys/arm/include/atomic-v6.h    Mon Feb 10 00:05:04 2020        
(r357709)
@@ -858,23 +858,75 @@ atomic_store_rel_long(volatile u_long *p, u_long v)
 }
 
 static __inline int
-atomic_testandset_32(volatile uint32_t *p, u_int v)
+atomic_testandclear_32(volatile uint32_t *ptr, u_int bit)
 {
-       uint32_t tmp, tmp2, res, mask;
+       int newv, oldv, result;
 
-       mask = 1u << (v & 0x1f);
-       tmp = tmp2 = 0;
        __asm __volatile(
-       "1:     ldrex   %0, [%4]        \n"
-       "       orr     %1, %0, %3      \n"
-       "       strex   %2, %1, [%4]    \n"
-       "       cmp     %2, #0          \n"
-       "       it      ne              \n"
-       "       bne     1b              \n"
-       : "=&r" (res), "=&r" (tmp), "=&r" (tmp2)
-       : "r" (mask), "r" (p)
-       : "cc", "memory");
-       return ((res & mask) != 0);
+           "   mov     ip, #1                                  \n"
+           "   lsl     ip, ip, %[bit]                          \n"
+           /*  Done with %[bit] as input, reuse below as output. */
+           "1:                                                 \n"
+           "   ldrex   %[oldv], [%[ptr]]                       \n"
+           "   bic     %[newv], %[oldv], ip                    \n"
+           "   strex   %[bit], %[newv], [%[ptr]]               \n"
+           "   teq     %[bit], #0                              \n"
+           "   it      ne                                      \n"
+           "   bne     1b                                      \n"
+           "   ands    %[bit], %[oldv], ip                     \n"
+           "   it      ne                                      \n"
+           "   movne   %[bit], #1                              \n"
+           : [bit]  "=&r"   (result),
+             [oldv] "=&r"   (oldv),
+             [newv] "=&r"   (newv)
+           : [ptr]  "r"     (ptr),
+                    "[bit]" (bit)
+           : "cc", "ip", "memory");
+
+       return (result);
+}
+
+static __inline int
+atomic_testandclear_int(volatile u_int *p, u_int v)
+{
+
+       return (atomic_testandclear_32((volatile uint32_t *)p, v));
+}
+
+static __inline int
+atomic_testandclear_long(volatile u_long *p, u_int v)
+{
+
+       return (atomic_testandclear_32((volatile uint32_t *)p, v));
+}
+
+static __inline int
+atomic_testandset_32(volatile uint32_t *ptr, u_int bit)
+{
+       int newv, oldv, result;
+
+       __asm __volatile(
+           "   mov     ip, #1                                  \n"
+           "   lsl     ip, ip, %[bit]                          \n"
+           /*  Done with %[bit] as input, reuse below as output. */
+           "1:                                                 \n"
+           "   ldrex   %[oldv], [%[ptr]]                       \n"
+           "   orr     %[newv], %[oldv], ip                    \n"
+           "   strex   %[bit], %[newv], [%[ptr]]               \n"
+           "   teq     %[bit], #0                              \n"
+           "   it      ne                                      \n"
+           "   bne     1b                                      \n"
+           "   ands    %[bit], %[oldv], ip                     \n"
+           "   it      ne                                      \n"
+           "   movne   %[bit], #1                              \n"
+           : [bit]  "=&r"   (result),
+             [oldv] "=&r"   (oldv),
+             [newv] "=&r"   (newv)
+           : [ptr]  "r"     (ptr),
+                    "[bit]" (bit)
+           : "cc", "ip", "memory");
+
+       return (result);
 }
 
 static __inline int
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to