ARM and MIPS builds of libjpeg-turbo in QEMU, which passes through
/proc/cpuinfo from the host system.
+2. libjpeg-turbo previously assumed that AltiVec instructions were always
+available on PowerPC platforms, which led to "illegal instruction" errors when
+running on PowerPC chips that lack AltiVec support (such as the older 7xx/G3
+and newer e5500 series.) libjpeg-turbo now examines /proc/cpuinfo on
+Linux/Android systems and enables AltiVec instructions only if the CPU supports
+them. It also now provides two environment variables, `JSIMD_FORCEALTIVEC` and
+`JSIMD_FORCENONE`, to force-enable and force-disable AltiVec instructions in
+environments where /proc/cpuinfo is an unreliable means of CPU feature
+detection (such as when running in QEMU.) On OS X, libjpeg-turbo continues to
+assume that AltiVec support is always available, which means that libjpeg-turbo
+cannot be used with G3 Macs unless you set the environment variable
+`JSIMD_FORCENONE` to `1`.
+
1.5.0
=====
if SIMD_POWERPC
-libsimd_la_SOURCES = jsimd_powerpc.c jsimd_altivec.h jcsample.h \
+noinst_LTLIBRARIES += libsimd_altivec.la
+
+libsimd_altivec_la_SOURCES = \
jccolor-altivec.c jcgray-altivec.c jcsample-altivec.c \
jdcolor-altivec.c jdmerge-altivec.c jdsample-altivec.c \
jfdctfst-altivec.c jfdctint-altivec.c \
jidctfst-altivec.c jidctint-altivec.c \
jquanti-altivec.c
-libsimd_la_CFLAGS = -maltivec
+libsimd_altivec_la_CFLAGS = -maltivec
jccolor-altivec.lo: jccolext-altivec.c
jcgray-altivec.lo: jcgryext-altivec.c
jdcolor-altivec.lo: jdcolext-altivec.c
jdmerge-altivec.lo: jdmrgext-altivec.c
+libsimd_la_SOURCES = jsimd_powerpc.c jsimd_altivec.h jcsample.h
+libsimd_la_LIBADD = libsimd_altivec.la
+
endif
AM_CPPFLAGS = -I$(top_srcdir)
* jsimd_powerpc.c
*
* Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
- * Copyright (C) 2009-2011, 2014-2015, D. R. Commander.
+ * Copyright (C) 2009-2011, 2014-2016, D. R. Commander.
* Copyright (C) 2015, Matthieu Darbois.
*
* Based on the x86 SIMD extension for IJG JPEG library,
#include "../jsimddct.h"
#include "jsimd.h"
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
static unsigned int simd_support = ~0;
+#if defined(__linux__) || defined(ANDROID) || defined(__ANDROID__)
+
+#define SOMEWHAT_SANE_PROC_CPUINFO_SIZE_LIMIT (1024 * 1024)
+
+LOCAL(int)
+check_feature (char *buffer, char *feature)
+{
+ char *p;
+ if (*feature == 0)
+ return 0;
+ if (strncmp(buffer, "cpu", 3) != 0)
+ return 0;
+ buffer += 3;
+ while (isspace(*buffer))
+ buffer++;
+
+ /* Check if 'feature' is present in the buffer as a separate word */
+ while ((p = strstr(buffer, feature))) {
+ if (p > buffer && !isspace(*(p - 1))) {
+ buffer++;
+ continue;
+ }
+ p += strlen(feature);
+ if (*p != 0 && !isspace(*p)) {
+ buffer++;
+ continue;
+ }
+ return 1;
+ }
+ return 0;
+}
+
+LOCAL(int)
+parse_proc_cpuinfo (int bufsize)
+{
+ char *buffer = (char *)malloc(bufsize);
+ FILE *fd;
+ simd_support = 0;
+
+ if (!buffer)
+ return 0;
+
+ fd = fopen("/proc/cpuinfo", "r");
+ if (fd) {
+ while (fgets(buffer, bufsize, fd)) {
+ if (!strchr(buffer, '\n') && !feof(fd)) {
+ /* "impossible" happened - insufficient size of the buffer! */
+ fclose(fd);
+ free(buffer);
+ return 0;
+ }
+ if (check_feature(buffer, "altivec"))
+ simd_support |= JSIMD_ALTIVEC;
+ }
+ fclose(fd);
+ }
+ free(buffer);
+ return 1;
+}
+
+#endif
+
+/*
+ * Check what SIMD accelerations are supported.
+ *
+ * FIXME: This code is racy under a multi-threaded environment.
+ */
LOCAL(void)
init_simd (void)
{
char *env = NULL;
+#if !defined(__ALTIVEC__) && (defined(__linux__) || defined(ANDROID) || defined(__ANDROID__))
+ int bufsize = 1024; /* an initial guess for the line buffer size limit */
+#endif
if (simd_support != ~0U)
return;
- simd_support = JSIMD_ALTIVEC;
+ simd_support = 0;
+
+#if defined(__ALTIVEC__) || defined(__APPLE__)
+ simd_support |= JSIMD_ALTIVEC;
+#elif defined(__linux__) || defined(ANDROID) || defined(__ANDROID__)
+ while (!parse_proc_cpuinfo(bufsize)) {
+ bufsize *= 2;
+ if (bufsize > SOMEWHAT_SANE_PROC_CPUINFO_SIZE_LIMIT)
+ break;
+ }
+#endif
/* Force different settings through environment variables */
+ env = getenv("JSIMD_FORCEALTIVEC");
+ if ((env != NULL) && (strcmp(env, "1") == 0))
+ simd_support = JSIMD_ALTIVEC;
env = getenv("JSIMD_FORCENONE");
if ((env != NULL) && (strcmp(env, "1") == 0))
simd_support = 0;