]> granicus.if.org Git - libatomic_ops/commitdiff
Implement AO_nop_full/write using 'dmb' instruction if available (gcc/arm)
authorIvan Maidanski <ivmai@mail.ru>
Mon, 7 Jan 2013 08:52:59 +0000 (12:52 +0400)
committerIvan Maidanski <ivmai@mail.ru>
Mon, 7 Jan 2013 08:52:59 +0000 (12:52 +0400)
* src/atomic_ops/sysdeps/gcc/arm.h (AO_ARM_HAVE_DMB): New macro
(defined for ARMv6M and ARMv7+).
* src/atomic_ops/sysdeps/gcc/arm.h (AO_nop_full): Update comment;
use "dmb" instruction if AO_ARM_HAVE_DMB (and not AO_UNIPROCESSOR).
* src/atomic_ops/sysdeps/gcc/arm.h (AO_nop_write): Implement using
"dmb st" instruction and define AO_HAVE_nop_write (only if
AO_ARM_HAVE_DMB and not AO_UNIPROCESSOR).

src/atomic_ops/sysdeps/gcc/arm.h

index ab0b42ff9bbda6d45e8be05a264210e93590127b..3f19cc0637689c332f335d060c0776fda95ea36d 100644 (file)
 
 #include "../test_and_set_t_is_ao_t.h" /* Probably suboptimal */
 
-/* NEC LE-IT: ARMv6 is the first architecture providing support for     */
-/* simple LL/SC.  A data memory barrier must be raised via CP15 command */
-/* (see documentation).                                                 */
-/* ARMv7 is compatible to ARMv6 but has a simpler command for issuing   */
-/* a memory barrier (DMB). Raising it via CP15 should still work as     */
-/* told me by the support engineers. If it turns out to be much quicker */
-/* than we should implement custom code for ARMv7 using the asm { dmb } */
-/* instruction.                                                         */
-/* If only a single processor is used, we can define AO_UNIPROCESSOR    */
-/* and do not need to access CP15 for ensuring a DMB.                   */
-
 #if defined(__thumb__) && !defined(__thumb2__)
   /* Thumb One mode does not have ARM "mcr", "swp" and some load/store  */
   /* instructions, so we temporarily switch to ARM mode and go back     */
 # define AO_ARM_HAVE_LDREX
 # if !defined(__ARM_ARCH_6__) && !defined(__ARM_ARCH_6J__) \
      && !defined(__ARM_ARCH_6T2__) && !defined(__ARM_ARCH_6Z__) \
-     && !defined(__ARM_ARCH_6ZT2__) && (!defined(__thumb__) \
-              || (defined(__thumb2__) && !defined(__ARM_ARCH_7__) \
-                  && !defined(__ARM_ARCH_7M__) && !defined(__ARM_ARCH_7EM__)))
-    /* LDREXD/STREXD present in ARMv6K/M+ (see gas/config/tc-arm.c)       */
-    /* In the Thumb mode, this works only starting from ARMv7 (except for */
-    /* the base and 'M' models).                                          */
-#   define AO_ARM_HAVE_LDREXD
+     && !defined(__ARM_ARCH_6ZT2__)
+#   if !defined(__ARM_ARCH_6K__) && !defined(__ARM_ARCH_6ZK__)
+      /* DMB is present in ARMv6M and ARMv7+.   */
+#     define AO_ARM_HAVE_DMB
+#   endif
+#   if !defined(__thumb__) \
+       || (defined(__thumb2__) && !defined(__ARM_ARCH_7__) \
+           && !defined(__ARM_ARCH_7M__) && !defined(__ARM_ARCH_7EM__))
+      /* LDREXD/STREXD present in ARMv6K/M+ (see gas/config/tc-arm.c).  */
+      /* In the Thumb mode, this works only starting from ARMv7 (except */
+      /* for the base and 'M' models).                                  */
+#     define AO_ARM_HAVE_LDREXD
+#   endif /* !thumb || ARMv7A || ARMv7R+ */
 # endif /* ARMv7+ */
 #endif /* ARMv6+ */
 
 
 #ifdef AO_ARM_HAVE_LDREX
 
-AO_INLINE void
-AO_nop_full(void)
-{
-# ifndef AO_UNIPROCESSOR
-    unsigned dest = 0;
+  /* ARMv6 is the first architecture providing support for simple       */
+  /* LL/SC.  A data memory barrier must be raised via CP15 command (see */
+  /* documentation).  ARMv7 is compatible to ARMv6 but has a simpler    */
+  /* command for issuing a memory barrier (DMB).  Raising it via CP15   */
+  /* should still work (but slightly less efficient because it requires */
+  /* the use of a general-purpose register).  If only a single          */
+  /* processor (core) is used, AO_UNIPROCESSOR could be defined by      */
+  /* client to avoid unnecessary memory barrier.                        */
+
+# if defined(AO_ARM_HAVE_DMB) && !defined(AO_UNIPROCESSOR)
+
+    AO_INLINE void
+    AO_nop_full(void)
+    {
+      __asm__ __volatile__("dmb" : : : "memory");
+    }
+#   define AO_HAVE_nop_full
+
+    AO_INLINE void
+    AO_nop_write(void)
+    {
+      __asm__ __volatile__("dmb st" : : : "memory");
+    }
+#   define AO_HAVE_nop_write
 
-    /* Issue a data memory barrier (keeps ordering of memory    */
-    /* transactions before and after this operation).           */
-    __asm__ __volatile__("@AO_nop_full\n"
-      AO_THUMB_GO_ARM
-      "       mcr p15,0,%0,c7,c10,5\n"
-      AO_THUMB_RESTORE_MODE
-      : "=&r"(dest)
-      : /* empty */
-      : AO_THUMB_SWITCH_CLOBBERS "memory");
 # else
-    AO_compiler_barrier();
-# endif
-}
-#define AO_HAVE_nop_full
+
+    AO_INLINE void
+    AO_nop_full(void)
+    {
+#     ifndef AO_UNIPROCESSOR
+        unsigned dest = 0;
+
+        /* Issue a data memory barrier (keeps ordering of memory        */
+        /* transactions before and after this operation).               */
+        __asm__ __volatile__("@AO_nop_full\n"
+          AO_THUMB_GO_ARM
+          "       mcr p15,0,%0,c7,c10,5\n"
+          AO_THUMB_RESTORE_MODE
+          : "=&r"(dest)
+          : /* empty */
+          : AO_THUMB_SWITCH_CLOBBERS "memory");
+#     else
+        AO_compiler_barrier();
+#     endif
+    }
+#   define AO_HAVE_nop_full
+
+# endif /* !AO_ARM_HAVE_DMB */
 
 /* NEC LE-IT: AO_t load is simple reading */
 AO_INLINE AO_t