SDL: Add SDL_FLOATWORDORDER for older ARM toolchains

From b398a847be0814ea36fe72da4f6ecb2e6d49a86b Mon Sep 17 00:00:00 2001
From: Cameron Cawley <[EMAIL REDACTED]>
Date: Tue, 3 May 2022 23:21:10 +0100
Subject: [PATCH] Add SDL_FLOATWORDORDER for older ARM toolchains

---
 include/SDL_endian.h           | 22 ++++++++++++++++++++++
 src/libm/math_private.h        |  3 ++-
 test/testautomation_platform.c | 19 +++++++++++++++++++
 test/testplatform.c            | 23 +++++++++++++++++++++++
 4 files changed, 66 insertions(+), 1 deletion(-)

diff --git a/include/SDL_endian.h b/include/SDL_endian.h
index 2866f4beab9..e1c6b5ef4a5 100644
--- a/include/SDL_endian.h
+++ b/include/SDL_endian.h
@@ -87,6 +87,28 @@ _m_prefetch(void *__P)
 #endif /* __linux__ */
 #endif /* !SDL_BYTEORDER */
 
+#ifndef SDL_FLOATWORDORDER           /* Not defined in SDL_config.h? */
+/* predefs from newer gcc versions: */
+#if defined(__ORDER_LITTLE_ENDIAN__) && defined(__ORDER_BIG_ENDIAN__) && defined(__FLOAT_WORD_ORDER__)
+#if (__FLOAT_WORD_ORDER__ == __ORDER_LITTLE_ENDIAN__)
+#define SDL_FLOATWORDORDER   SDL_LIL_ENDIAN
+#elif (__FLOAT_WORD_ORDER__ == __ORDER_BIG_ENDIAN__)
+#define SDL_FLOATWORDORDER   SDL_BIG_ENDIAN
+#else
+#error Unsupported endianness
+#endif /**/
+#elif defined(__MAVERICK__)
+/* For Maverick, float words are always little-endian. */
+#define SDL_FLOATWORDORDER   SDL_LIL_ENDIAN
+#elif (defined(__arm__) || defined(__thumb__)) && !defined(__VFP_FP__) && !defined(__ARM_EABI__)
+/* For FPA, float words are always big-endian. */
+#define SDL_FLOATWORDORDER   SDL_BIG_ENDIAN
+#else
+/* By default, assume that floats words follow the memory system mode. */
+#define SDL_FLOATWORDORDER   SDL_BYTEORDER
+#endif /* __FLOAT_WORD_ORDER__ */
+#endif /* !SDL_FLOATWORDORDER */
+
 
 #include "begin_code.h"
 /* Set up for C function definitions, even when using C++ */
diff --git a/src/libm/math_private.h b/src/libm/math_private.h
index 4a30a521afa..2e4bb140213 100644
--- a/src/libm/math_private.h
+++ b/src/libm/math_private.h
@@ -66,9 +66,10 @@ typedef unsigned int u_int32_t;
  * Math on arm is special:
  * For FPA, float words are always big-endian.
  * For VFP, floats words follow the memory system mode.
+ * For Maverick, float words are always little-endian.
  */
 
-#if (SDL_BYTEORDER == SDL_BIG_ENDIAN)
+#if (SDL_FLOATWORDORDER == SDL_BIG_ENDIAN)
 
 typedef union
 {
diff --git a/test/testautomation_platform.c b/test/testautomation_platform.c
index 4e28ba166fc..0a31ad8cfab 100644
--- a/test/testautomation_platform.c
+++ b/test/testautomation_platform.c
@@ -54,12 +54,18 @@ int platform_testTypes(void *arg)
 int platform_testEndianessAndSwap(void *arg)
 {
     int real_byteorder;
+    int real_floatwordorder = 0;
     Uint16 value = 0x1234;
     Uint16 value16 = 0xCDAB;
     Uint16 swapped16 = 0xABCD;
     Uint32 value32 = 0xEFBEADDE;
     Uint32 swapped32 = 0xDEADBEEF;
 
+    union {
+       double d;
+       Uint32 ui32[2];
+    } value_double;
+
     Uint64 value64, swapped64;
     value64 = 0xEFBEADDE;
     value64 <<= 32;
@@ -67,6 +73,7 @@ int platform_testEndianessAndSwap(void *arg)
     swapped64 = 0x1234ABCD;
     swapped64 <<= 32;
     swapped64 |= 0xDEADBEEF;
+    value_double.d = 3.141593;
 
     if ((*((char *) &value) >> 4) == 0x1) {
         real_byteorder = SDL_BIG_ENDIAN;
@@ -80,6 +87,18 @@ int platform_testEndianessAndSwap(void *arg)
              (SDL_BYTEORDER == SDL_LIL_ENDIAN) ? "little" : "big",
              (real_byteorder == SDL_LIL_ENDIAN) ? "little" : "big" );
 
+    if (value_double.ui32[0] == 0x82c2bd7f && value_double.ui32[1] == 0x400921fb) {
+        real_floatwordorder = SDL_LIL_ENDIAN;
+    } else if (value_double.ui32[0] == 0x400921fb && value_double.ui32[1] == 0x82c2bd7f) {
+        real_floatwordorder = SDL_BIG_ENDIAN;
+    }
+
+    /* Test endianness. */
+    SDLTest_AssertCheck( real_floatwordorder == SDL_FLOATWORDORDER,
+             "Machine detected as having %s endian float word order, appears to be %s endian.",
+             (SDL_FLOATWORDORDER == SDL_LIL_ENDIAN) ? "little" : "big",
+             (real_floatwordorder == SDL_LIL_ENDIAN) ? "little" : (real_floatwordorder == SDL_BIG_ENDIAN) ? "big" : "unknown" );
+
     /* Test 16 swap. */
     SDLTest_AssertCheck( SDL_Swap16(value16) == swapped16,
              "SDL_Swap16(): 16 bit swapped: 0x%X => 0x%X",
diff --git a/test/testplatform.c b/test/testplatform.c
index 5aa649c125f..f5b524d573c 100644
--- a/test/testplatform.c
+++ b/test/testplatform.c
@@ -86,18 +86,25 @@ TestEndian(SDL_bool verbose)
     int error = 0;
     Uint16 value = 0x1234;
     int real_byteorder;
+    int real_floatwordorder = 0;
     Uint16 value16 = 0xCDAB;
     Uint16 swapped16 = 0xABCD;
     Uint32 value32 = 0xEFBEADDE;
     Uint32 swapped32 = 0xDEADBEEF;
     Uint64 value64, swapped64;
 
+    union {
+       double d;
+       Uint32 ui32[2];
+    } value_double;
+
     value64 = 0xEFBEADDE;
     value64 <<= 32;
     value64 |= 0xCDAB3412;
     swapped64 = 0x1234ABCD;
     swapped64 <<= 32;
     swapped64 |= 0xDEADBEEF;
+    value_double.d = 3.141593;
 
     if (verbose) {
         SDL_Log("Detected a %s endian machine.\n",
@@ -115,6 +122,22 @@ TestEndian(SDL_bool verbose)
         }
         ++error;
     }
+    if (verbose) {
+        SDL_Log("Detected a %s endian float word order machine.\n",
+               (SDL_FLOATWORDORDER == SDL_LIL_ENDIAN) ? "little" : "big");
+    }
+    if (value_double.ui32[0] == 0x82c2bd7f && value_double.ui32[1] == 0x400921fb) {
+        real_floatwordorder = SDL_LIL_ENDIAN;
+    } else if (value_double.ui32[0] == 0x400921fb && value_double.ui32[1] == 0x82c2bd7f) {
+        real_floatwordorder = SDL_BIG_ENDIAN;
+    }
+    if (real_floatwordorder != SDL_FLOATWORDORDER) {
+        if (verbose) {
+            SDL_Log("Actually a %s endian float word order machine!\n",
+                   (real_floatwordorder == SDL_LIL_ENDIAN) ? "little" : (real_floatwordorder == SDL_BIG_ENDIAN) ? "big" : "unknown" );
+        }
+        ++error;
+    }
     if (verbose) {
         SDL_Log("Value 16 = 0x%X, swapped = 0x%X\n", value16,
                SDL_Swap16(value16));