ARM: Create configure option --enable-arm-simd to govern assembly optimizations
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
diff --git a/configure.ac b/configure.ac
index 13c3b02..e9f62df 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1303,6 +1303,42 @@ AS_HELP_STRING([--enable-libsamplerate-shared], [dynamically load libsamplerate
fi
}
+dnl Check for ARM instruction support using gas syntax
+CheckARM()
+{
+ AC_ARG_ENABLE(arm-simd,
+AC_HELP_STRING([--enable-arm-simd], [use SIMD assembly blitters on ARM [[default=yes]]]),
+ enable_arm_simd=$enableval, enable_arm_simd=yes)
+ if test x$enable_video = xyes -a x$enable_assembly = xyes -a x$enable_arm_simd = xyes; then
+ save_CFLAGS="$CFLAGS"
+ have_arm_simd=no
+ CFLAGS="-x assembler-with-cpp $CFLAGS"
+
+ AC_MSG_CHECKING(for ARM SIMD)
+ AC_COMPILE_IFELSE([AC_LANG_SOURCE([[
+ .text
+ .arch armv6
+ .object_arch armv4
+ .arm
+ .altmacro
+ #ifndef __ARM_EABI__
+ #error EABI is required (to be sure that calling conventions are compatible)
+ #endif
+ pld [r0]
+ uqadd8 r0, r0, r0
+ ]])], have_arm_simd=yes)
+ AC_MSG_RESULT($have_arm_simd)
+
+ CFLAGS="$save_CFLAGS"
+
+ if test x$have_arm_simd = xyes; then
+ AC_DEFINE(SDL_ARM_SIMD_BLITTERS)
+dnl SOURCES="$SOURCES $srcdir/src/video/arm/pixman-arm-simd*.c"
+ SOURCES="$SOURCES $srcdir/src/video/arm/pixman-arm-simd*.S"
+ fi
+ fi
+}
+
dnl See if GCC's -fvisibility=hidden is supported (gcc4 and later, usually).
dnl Details of this flag are here: http://gcc.gnu.org/wiki/Visibility
CheckVisibilityHidden()
@@ -3396,6 +3432,7 @@ case "$host" in
CheckDiskAudio
CheckDummyAudio
CheckDLOPEN
+ CheckARM
CheckOSS
CheckALSA
CheckPulseAudio
diff --git a/include/SDL_config.h.in b/include/SDL_config.h.in
index c263e17..3765522 100644
--- a/include/SDL_config.h.in
+++ b/include/SDL_config.h.in
@@ -407,6 +407,7 @@
/* Enable assembly routines */
#undef SDL_ASSEMBLY_ROUTINES
#undef SDL_ALTIVEC_BLITTERS
+#undef SDL_ARM_SIMD_BLITTERS
/* Enable ime support */
#undef SDL_USE_IME
diff --git a/include/SDL_cpuinfo.h b/include/SDL_cpuinfo.h
index efbf6ff..2d094e8 100644
--- a/include/SDL_cpuinfo.h
+++ b/include/SDL_cpuinfo.h
@@ -187,6 +187,11 @@ extern DECLSPEC SDL_bool SDLCALL SDL_HasAVX2(void);
extern DECLSPEC SDL_bool SDLCALL SDL_HasAVX512F(void);
/**
+ * This function returns true if the CPU has ARM SIMD (ARMv6) features.
+ */
+extern DECLSPEC SDL_bool SDLCALL SDL_HasARMSIMD(void);
+
+/**
* This function returns true if the CPU has NEON (ARM SIMD) features.
*/
extern DECLSPEC SDL_bool SDLCALL SDL_HasNEON(void);
diff --git a/src/cpuinfo/SDL_cpuinfo.c b/src/cpuinfo/SDL_cpuinfo.c
index 0067040..5f86acf 100644
--- a/src/cpuinfo/SDL_cpuinfo.c
+++ b/src/cpuinfo/SDL_cpuinfo.c
@@ -96,6 +96,7 @@
#define CPU_HAS_AVX2 (1 << 10)
#define CPU_HAS_NEON (1 << 11)
#define CPU_HAS_AVX512F (1 << 12)
+#define CPU_HAS_ARM_SIMD (1 << 13)
#if SDL_ALTIVEC_BLITTERS && HAVE_SETJMP && !__MACOSX__ && !__OpenBSD__
/* This is the brute force way of detecting instruction sets...
@@ -325,7 +326,50 @@ CPU_haveAltiVec(void)
return altivec;
}
-#if defined(__LINUX__) && defined(__ARM_ARCH) && !defined(HAVE_GETAUXVAL)
+#ifdef __linux__
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <elf.h>
+
+static SDL_bool
+CPU_haveARMSIMD(void)
+{
+ int arm_simd = 0;
+ int fd;
+
+ fd = open("/proc/self/auxv", O_RDONLY);
+ if (fd >= 0)
+ {
+ Elf32_auxv_t aux;
+ while (read(fd, &aux, sizeof aux) == sizeof aux)
+ {
+ if (aux.a_type == AT_PLATFORM)
+ {
+ const char *plat = (const char *) aux.a_un.a_val;
+ arm_simd = strncmp(plat, "v6l", 3) == 0 ||
+ strncmp(plat, "v7l", 3) == 0;
+ }
+ }
+ close(fd);
+ }
+ return arm_simd;
+}
+
+#else
+
+static SDL_bool
+CPU_haveARMSIMD(void)
+{
+#warning SDL_HasARMSIMD is not implemented for this ARM platform. Write me.
+ return 0;
+}
+
+#endif
+
+#if (defined(__LINUX__) || defined(__ANDROID__)) && defined(__ARM_ARCH) && !defined(HAVE_GETAUXVAL)
static int
readProcAuxvForNeon(void)
{
@@ -668,6 +712,10 @@ SDL_GetCPUFeatures(void)
SDL_CPUFeatures |= CPU_HAS_AVX512F;
SDL_SIMDAlignment = SDL_max(SDL_SIMDAlignment, 64);
}
+ if (CPU_haveARMSIMD()) {
+ SDL_CPUFeatures |= CPU_HAS_ARM_SIMD;
+ SDL_SIMDAlignment = SDL_max(SDL_SIMDAlignment, 16);
+ }
if (CPU_haveNEON()) {
SDL_CPUFeatures |= CPU_HAS_NEON;
SDL_SIMDAlignment = SDL_max(SDL_SIMDAlignment, 16);
@@ -750,6 +798,12 @@ SDL_HasAVX512F(void)
}
SDL_bool
+SDL_HasARMSIMD(void)
+{
+ return CPU_FEATURE_AVAILABLE(CPU_HAS_ARM_SIMD);
+}
+
+SDL_bool
SDL_HasNEON(void)
{
return CPU_FEATURE_AVAILABLE(CPU_HAS_NEON);
@@ -870,6 +924,7 @@ main()
printf("AVX: %d\n", SDL_HasAVX());
printf("AVX2: %d\n", SDL_HasAVX2());
printf("AVX-512F: %d\n", SDL_HasAVX512F());
+ printf("ARM SIMD: %d\n", SDL_HasARMSIMD());
printf("NEON: %d\n", SDL_HasNEON());
printf("RAM: %d MB\n", SDL_GetSystemRAM());
return 0;