Commit 2aa8974f97a89aac05d532e10bfc6aefda0fe326

Ethan Lee 2020-06-11T12:03:33

Add SDL_SIMDRealloc

diff --git a/include/SDL_cpuinfo.h b/include/SDL_cpuinfo.h
index 0d9b821..56908d7 100644
--- a/include/SDL_cpuinfo.h
+++ b/include/SDL_cpuinfo.h
@@ -246,11 +246,34 @@ extern DECLSPEC size_t SDLCALL SDL_SIMDGetAlignment(void);
  * \return Pointer to newly-allocated block, NULL if out of memory.
  *
  * \sa SDL_SIMDAlignment
+ * \sa SDL_SIMDRealloc
  * \sa SDL_SIMDFree
  */
 extern DECLSPEC void * SDLCALL SDL_SIMDAlloc(const size_t len);
 
 /**
+ * \brief Reallocate memory obtained from SDL_SIMDAlloc
+ *
+ * It is not valid to use this function on a pointer from anything but
+ *  SDL_SIMDAlloc(). It can't be used on pointers from malloc, realloc,
+ *  SDL_malloc, memalign, new[], etc.
+ *
+ *  \param mem The pointer obtained from SDL_SIMDAlloc. This function also
+ *             accepts NULL, at which point this function is the same as
+ *             calling SDL_realloc with a NULL pointer.
+ *  \param len The length, in bytes, of the block to allocated. The actual
+ *             allocated block might be larger due to padding, etc. Passing 0
+ *             will return a non-NULL pointer, assuming the system isn't out of
+ *             memory.
+ * \return Pointer to newly-reallocated block, NULL if out of memory.
+ *
+ * \sa SDL_SIMDAlignment
+ * \sa SDL_SIMDAlloc
+ * \sa SDL_SIMDFree
+ */
+extern DECLSPEC void * SDLCALL SDL_SIMDRealloc(void *mem, size_t len);
+
+/**
  * \brief Deallocate memory obtained from SDL_SIMDAlloc
  *
  * It is not valid to use this function on a pointer from anything but
@@ -260,6 +283,7 @@ extern DECLSPEC void * SDLCALL SDL_SIMDAlloc(const size_t len);
  * However, SDL_SIMDFree(NULL) is a legal no-op.
  *
  * \sa SDL_SIMDAlloc
+ * \sa SDL_SIMDRealloc
  */
 extern DECLSPEC void SDLCALL SDL_SIMDFree(void *ptr);
 
diff --git a/src/cpuinfo/SDL_cpuinfo.c b/src/cpuinfo/SDL_cpuinfo.c
index 9cecb4f..70e268b 100644
--- a/src/cpuinfo/SDL_cpuinfo.c
+++ b/src/cpuinfo/SDL_cpuinfo.c
@@ -956,6 +956,58 @@ SDL_SIMDAlloc(const size_t len)
     return retval;
 }
 
+void *
+SDL_SIMDRealloc(void *mem, const size_t len)
+{
+    const size_t alignment = SDL_SIMDGetAlignment();
+    const size_t padding = alignment - (len % alignment);
+    const size_t padded = (padding != alignment) ? (len + padding) : len;
+    Uint8 *retval = (Uint8*) mem;
+    void *oldmem = mem;
+    size_t memdiff, ptrdiff;
+    Uint8 *ptr;
+
+    if (mem) {
+        void **realptr = (void **) mem;
+        realptr--;
+        mem = *(((void **) mem) - 1);
+
+        /* Check the delta between the real pointer and user pointer */
+        memdiff = ((size_t) oldmem) - ((size_t) mem);
+    }
+
+    ptr = (Uint8 *) SDL_realloc(mem, padded + alignment + sizeof (void *));
+
+    if (ptr == mem) {
+        return retval; /* Pointer didn't change, nothing to do */
+    }
+    if (ptr == NULL) {
+        return NULL; /* Out of memory, bail! */
+    }
+
+    /* Store the actual malloc pointer right before our aligned pointer. */
+    retval = ptr + sizeof (void *);
+    retval += alignment - (((size_t) retval) % alignment);
+
+    /* Make sure the delta is the same! */
+    if (mem) {
+        ptrdiff = ((size_t) retval) - ((size_t) ptr);
+        if (memdiff != ptrdiff) { /* Delta has changed, copy to new offset! */
+            oldmem = (void*) (((size_t) ptr) + memdiff);
+
+            /* Even though the data past the old `len` is undefined, this is the
+             * only length value we have, and it guarantees that we copy all the
+             * previous memory anyhow.
+             */
+            SDL_memmove(retval, oldmem, len);
+        }
+    }
+
+    /* Actually store the malloc pointer, finally. */
+    *(((void **) retval) - 1) = ptr;
+    return retval;
+}
+
 void
 SDL_SIMDFree(void *ptr)
 {
diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h
index cb596aa..5223a6c 100644
--- a/src/dynapi/SDL_dynapi_overrides.h
+++ b/src/dynapi/SDL_dynapi_overrides.h
@@ -716,6 +716,7 @@
 #define SDL_UIKitRunApp SDL_UIKitRunApp_REAL
 #define SDL_SIMDGetAlignment SDL_SIMDGetAlignment_REAL
 #define SDL_SIMDAlloc SDL_SIMDAlloc_REAL
+#define SDL_SIMDRealloc SDL_SIMDRealloc_REAL
 #define SDL_SIMDFree SDL_SIMDFree_REAL
 #define SDL_RWsize SDL_RWsize_REAL
 #define SDL_RWseek SDL_RWseek_REAL
diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h
index b501d69..90d2075 100644
--- a/src/dynapi/SDL_dynapi_procs.h
+++ b/src/dynapi/SDL_dynapi_procs.h
@@ -772,6 +772,7 @@ SDL_DYNAPI_PROC(int,SDL_UIKitRunApp,(int a, char *b, SDL_main_func c),(a,b,c),re
 #endif
 SDL_DYNAPI_PROC(size_t,SDL_SIMDGetAlignment,(void),(),return)
 SDL_DYNAPI_PROC(void*,SDL_SIMDAlloc,(const size_t a),(a),return)
+SDL_DYNAPI_PROC(void*,SDL_SIMDRealloc,(void *a, const size_t b),(a, b),return)
 SDL_DYNAPI_PROC(void,SDL_SIMDFree,(void *a),(a),)
 SDL_DYNAPI_PROC(Sint64,SDL_RWsize,(SDL_RWops *a),(a),return)
 SDL_DYNAPI_PROC(Sint64,SDL_RWseek,(SDL_RWops *a, Sint64 b, int c),(a,b,c),return)