Re: Emit vzeroupper after avx memcpy

Darren Salt <[email protected]> Wed, 18 Sep 2013 15:46:57 +0100
Newsgroups gmane.comp.video.xine.devel
Message-ID <5392956C54%[email protected]>
I demand that Chris Rankin may or may not have written...

> I've applied this patch to the xine-lib branch, but my attempts also to
> merge it across from there to the xine-lib-1.2 branch have instead mangled
> my local repository in ways I would not have believed possible...

I cherry-picked it and pushed it, assuming that all was well with it, but...

$ gdb misc/.libs/xine-list-1.2
GNU gdb (GDB) 7.6 (Debian 7.6-5)
Reading symbols from .../misc/.libs/xine-list-1.2...done.
(gdb) run
Starting program: .../misc/.libs/xine-list-1.2 
warning: Could not load shared library symbols for linux-vdso.so.1.
Do you need "set solib-search-path" or "set sysroot"?
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".

Program received signal SIGILL, Illegal instruction.
sse_memcpy (to=0x7ffff5b62010, from=0x7ffff7fc7010, len=0) at memcpy.c:254
254	    __asm__ __volatile__ ("vzeroupper");
(gdb) 


This is on an Athlon II 240e.


The attached patch SHOULD fix this (by using an SSE variant which has this
extra instruction), but it needs some testing. Unfortunately, I can only test
on hardware which does NOT have this instruction.

I'll commit it if it's fine on hw which has this instruction.

(CCing the one responsible for the breakage regardless of subscription to the
list.)

-- 
|  _  | Darren Salt, using Debian GNU/Linux (and Android)
| ( ) |
|  X  | ASCII Ribbon campaign against HTML e-mail
| / \ | http://www.asciiribbon.org/

Life is far too important a thing ever to talk seriously about.

------------------------------------------------------------------------------
LIMITED TIME SALE - Full Year of Microsoft Training For Just $49.99!
1,500+ hours of tutorials including VisualStudio 2012, Windows 8, SharePoint
2013, SQL 2012, MVC 4, more. BEST VALUE: New Multi-Library Power Pack includes
Mobile, Cloud, Java, and UX Design. Lowest price ever! Ends 9/20/13. 
http://pubads.g.doubleclick.net/gampad/clk?id=58041151&iu=/4140/ostg.clktrk

_______________________________________________
xine-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/xine-devel
vzeroupper-fix.patch (application/octet-stream, 5.7 KB)
diff --git a/src/xine-utils/memcpy.c b/src/xine-utils/memcpy.c
--- a/src/xine-utils/memcpy.c
+++ b/src/xine-utils/memcpy.c
@@ -251,6 +251,96 @@ static void * sse_memcpy(void * to, cons
     /* since movntq is weakly-ordered, a "sfence"
      * is needed to become ordered again. */
     __asm__ __volatile__ ("sfence":::"memory");
+  }
+  /*
+   *	Now do the tail of the block
+   */
+  if(len) linux_kernel_memcpy_impl(to, from, len);
+  return retval;
+}
+
+#ifdef HAVE_AVX
+/* SSE, adapted for the presence of AVX.
+ * Only difference from above is the addition of vzeroupper,
+ * which many SSE-capable CPUs don't have. */
+static void * sse_memcpy_compat(void * to, const void * from, size_t len)
+{
+  void *retval;
+  size_t i;
+  retval = to;
+
+  /* PREFETCH has effect even for MOVSB instruction ;) */
+  __asm__ __volatile__ (
+    "   prefetchnta (%0)\n"
+    "   prefetchnta 32(%0)\n"
+    "   prefetchnta 64(%0)\n"
+    "   prefetchnta 96(%0)\n"
+    "   prefetchnta 128(%0)\n"
+    "   prefetchnta 160(%0)\n"
+    "   prefetchnta 192(%0)\n"
+    "   prefetchnta 224(%0)\n"
+    "   prefetchnta 256(%0)\n"
+    "   prefetchnta 288(%0)\n"
+    : : "r" (from) );
+
+  if(len >= MIN_LEN)
+  {
+    register uintptr_t delta;
+    /* Align destinition to MMREG_SIZE -boundary */
+    delta = ((uintptr_t)to)&(SSE_MMREG_SIZE-1);
+    if(delta)
+    {
+      delta=SSE_MMREG_SIZE-delta;
+      len -= delta;
+      small_memcpy(to, from, delta);
+    }
+    i = len >> 6; /* len/64 */
+    len&=63;
+    if(((uintptr_t)from) & 15)
+      /* if SRC is misaligned */
+      for(; i>0; i--)
+      {
+        __asm__ __volatile__ (
+        "prefetchnta 320(%0)\n"
+       "prefetchnta 352(%0)\n"
+        "movups (%0), %%xmm0\n"
+        "movups 16(%0), %%xmm1\n"
+        "movups 32(%0), %%xmm2\n"
+        "movups 48(%0), %%xmm3\n"
+        "movntps %%xmm0, (%1)\n"
+        "movntps %%xmm1, 16(%1)\n"
+        "movntps %%xmm2, 32(%1)\n"
+        "movntps %%xmm3, 48(%1)\n"
+        :: "r" (from), "r" (to) : "memory");
+        from = ((const unsigned char *)from) + 64;
+        to = ((unsigned char *)to) + 64;
+      }
+    else
+      /*
+         Only if SRC is aligned on 16-byte boundary.
+         It allows to use movaps instead of movups, which required data
+         to be aligned or a general-protection exception (#GP) is generated.
+      */
+      for(; i>0; i--)
+      {
+        __asm__ __volatile__ (
+        "prefetchnta 320(%0)\n"
+       "prefetchnta 352(%0)\n"
+        "movaps (%0), %%xmm0\n"
+        "movaps 16(%0), %%xmm1\n"
+        "movaps 32(%0), %%xmm2\n"
+        "movaps 48(%0), %%xmm3\n"
+        "movntps %%xmm0, (%1)\n"
+        "movntps %%xmm1, 16(%1)\n"
+        "movntps %%xmm2, 32(%1)\n"
+        "movntps %%xmm3, 48(%1)\n"
+        :: "r" (from), "r" (to) : "memory");
+        from = ((const unsigned char *)from) + 64;
+        to = ((unsigned char *)to) + 64;
+      }
+    /* since movntq is weakly-ordered, a "sfence"
+     * is needed to become ordered again. */
+    __asm__ __volatile__ ("sfence":::"memory");
     __asm__ __volatile__ ("vzeroupper");
   }
   /*
@@ -260,7 +350,6 @@ static void * sse_memcpy(void * to, cons
   return retval;
 }
 
-#ifdef HAVE_AVX
 static void * avx_memcpy(void * to, const void * from, size_t len)
 {
   void *retval;
@@ -484,6 +573,7 @@ static const struct {
   void *(*const  function)(void *to, const void *from, size_t len);
 
   uint32_t cpu_require;
+  uint32_t cpu_ignore;
 } memcpy_method[] =
 {
   { "", NULL, 0 },
@@ -492,8 +582,9 @@ static const struct {
   { "linux kernel", linux_kernel_memcpy, 0 },
   { "MMX ", mmx_memcpy, MM_MMX },
   { "MMXEXT", mmx2_memcpy, MM_MMXEXT },
-  { "SSE", sse_memcpy, MM_MMXEXT|MM_SSE },
+  { "SSE", sse_memcpy, MM_MMXEXT|MM_SSE, MM_ACCEL_X86_AVX },
 # ifdef HAVE_AVX
+  { "SSE-AVX-COMPAT", sse_memcpy_compat, MM_MMXEXT|MM_SSE|MM_ACCEL_X86_AVX },
   { "AVX", avx_memcpy, MM_ACCEL_X86_AVX },
 # endif /* HAVE_AVX */
 #endif /* ARCH_X86 */
@@ -545,6 +636,13 @@ static uint64_t rdtsc(int config_flags)
 }
 #endif
 
+static inline int validate_fast_memcpy(int flags, int method)
+{
+  return method > 0 && method < sizeof(memcpy_method) / sizeof(memcpy_method[0])
+      && (flags & memcpy_method[method].cpu_require) == memcpy_method[method].cpu_require
+      && (flags & memcpy_method[method].cpu_ignore)  == 0;
+}
+
 static void update_fast_memcpy(void *user_data, xine_cfg_entry_t *entry) {
   static int   config_flags = -1;
   xine_t      *xine = (xine_t *) user_data;
@@ -554,9 +652,7 @@ static void update_fast_memcpy(void *use
 
   method = entry->num_value;
 
-  if (method != 0
-      && (config_flags & memcpy_method[method].cpu_require) ==
-      memcpy_method[method].cpu_require ) {
+  if (validate_fast_memcpy(config_flags, method)) {
     lprintf("using %s memcpy()\n", memcpy_method[method].name );
     xine_fast_memcpy = memcpy_method[method].function;
     return;
@@ -577,7 +673,7 @@ void xine_probe_fast_memcpy(xine_t *xine
 #if (defined(ARCH_X86) || defined(ARCH_X86_64)) && !defined(_MSC_VER)
     "kernel", "mmx", "mmxext", "sse",
 # ifdef HAVE_AVX
-    "avx",
+    "sse-avx-compat", "avx",
 # endif /* HAVE_AVX */
 #endif
 #if defined (ARCH_PPC) && !defined (HOST_OS_DARWIN)
@@ -598,10 +694,7 @@ void xine_probe_fast_memcpy(xine_t *xine
 				      20, update_fast_memcpy, (void *) xine);
 
   /* check if function is configured and valid for this machine */
-  if( best != 0 &&
-      best < sizeof(memcpy_methods)/sizeof(memcpy_method[0]) &&
-     (config_flags & memcpy_method[best].cpu_require) ==
-      memcpy_method[best].cpu_require ) {
+  if( validate_fast_memcpy(config_flags, best) ) {
     lprintf("using %s memcpy()\n", memcpy_method[best].name );
     xine_fast_memcpy = memcpy_method[best].function;
     return;