From 2aa8974f97a89aac05d532e10bfc6aefda0fe326 Mon Sep 17 00:00:00 2001 From: Ethan Lee Date: Thu, 11 Jun 2020 12:03:33 -0400 Subject: [PATCH] Add SDL_SIMDRealloc --- include/SDL_cpuinfo.h | 24 ++++++++++++++ src/cpuinfo/SDL_cpuinfo.c | 52 +++++++++++++++++++++++++++++++ src/dynapi/SDL_dynapi_overrides.h | 1 + src/dynapi/SDL_dynapi_procs.h | 1 + 4 files changed, 78 insertions(+) diff --git a/include/SDL_cpuinfo.h b/include/SDL_cpuinfo.h index 0d9b82131c908..56908d754010c 100644 --- a/include/SDL_cpuinfo.h +++ b/include/SDL_cpuinfo.h @@ -246,10 +246,33 @@ 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 * @@ -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 9cecb4f16f397..70e268bf49513 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 cb596aaca170c..5223a6cbd3898 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 b501d6998009c..90d207562be6f 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)