svn commit: r357709 - head/sys/arm/include

Ian Lepore ian at FreeBSD.org
Mon Feb 10 00:05:05 UTC 2020


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


More information about the svn-src-all mailing list