Loongson MMI: Merge with MIPS64/add auto-detection

Modern Loongson processors are MIPS64-compatible, and MMI instructions
are now supported in the mainline of GCC.  Thus, this commit adds
compile-time and run-time auto-detection of MMI instructions and moves
the MMI SIMD extensions for libjpeg-turbo from simd/loongson/ to
simd/mips64/.  That will allow MMI and MSA instructions to co-exist
in the same build once #377 has been integrated.

Based on:
https://github.com/FlyGoat/libjpeg-turbo/commit/82953ddd61549428f58066f7eff0d60ce7429865

Closes #383
diff --git a/simd/CMakeLists.txt b/simd/CMakeLists.txt
index 10ae7c9..d63457e 100755
--- a/simd/CMakeLists.txt
+++ b/simd/CMakeLists.txt
@@ -314,15 +314,35 @@
 endif()
 
 ###############################################################################
-# Loongson (Intrinsics)
+# MIPS64 (Intrinsics)
 ###############################################################################
 
-elseif(CPU_TYPE STREQUAL "loongson")
+elseif(CPU_TYPE STREQUAL "loongson" OR CPU_TYPE MATCHES "mips64*")
 
-set(SIMD_SOURCES loongson/jccolor-mmi.c loongson/jcgray-mmi.c
-  loongson/jcsample-mmi.c loongson/jdcolor-mmi.c loongson/jdsample-mmi.c
-  loongson/jdmerge-mmi.c loongson/jfdctfst-mmi.c loongson/jfdctint-mmi.c
-  loongson/jidctfst-mmi.c loongson/jidctint-mmi.c loongson/jquanti-mmi.c)
+set(CMAKE_REQUIRED_FLAGS -Wa,-mloongson-mmi,-mloongson-ext)
+
+check_c_source_compiles("
+  int main(void) {
+    int c = 0, a = 0, b = 0;
+    asm (
+      \"paddb %0, %1, %2\"
+      : \"=f\" (c)
+      : \"f\" (a), \"f\" (b)
+    );
+    return c;
+  }" HAVE_MMI)
+
+unset(CMAKE_REQUIRED_FLAGS)
+
+if(NOT HAVE_MMI)
+  simd_fail("SIMD extensions not available for this CPU")
+  return()
+endif()
+
+set(SIMD_SOURCES mips64/jccolor-mmi.c mips64/jcgray-mmi.c mips64/jcsample-mmi.c
+  mips64/jdcolor-mmi.c mips64/jdmerge-mmi.c mips64/jdsample-mmi.c
+  mips64/jfdctfst-mmi.c mips64/jfdctint-mmi.c mips64/jidctfst-mmi.c
+  mips64/jidctint-mmi.c mips64/jquanti-mmi.c)
 
 if(CMAKE_COMPILER_IS_GNUCC)
   foreach(file ${SIMD_SOURCES})
@@ -330,8 +350,12 @@
       " -fno-strict-aliasing")
   endforeach()
 endif()
+foreach(file ${SIMD_SOURCES})
+  set_property(SOURCE ${file} APPEND_STRING PROPERTY COMPILE_FLAGS
+    " -Wa,-mloongson-mmi,-mloongson-ext")
+endforeach()
 
-add_library(simd OBJECT ${SIMD_SOURCES} loongson/jsimd.c)
+add_library(simd OBJECT ${SIMD_SOURCES} mips64/jsimd.c)
 
 if(CMAKE_POSITION_INDEPENDENT_CODE OR ENABLE_SHARED)
   set_target_properties(simd PROPERTIES POSITION_INDEPENDENT_CODE 1)
diff --git a/simd/loongson/jccolext-mmi.c b/simd/mips64/jccolext-mmi.c
similarity index 100%
rename from simd/loongson/jccolext-mmi.c
rename to simd/mips64/jccolext-mmi.c
diff --git a/simd/loongson/jccolor-mmi.c b/simd/mips64/jccolor-mmi.c
similarity index 100%
rename from simd/loongson/jccolor-mmi.c
rename to simd/mips64/jccolor-mmi.c
diff --git a/simd/loongson/jcgray-mmi.c b/simd/mips64/jcgray-mmi.c
similarity index 100%
rename from simd/loongson/jcgray-mmi.c
rename to simd/mips64/jcgray-mmi.c
diff --git a/simd/loongson/jcgryext-mmi.c b/simd/mips64/jcgryext-mmi.c
similarity index 100%
rename from simd/loongson/jcgryext-mmi.c
rename to simd/mips64/jcgryext-mmi.c
diff --git a/simd/loongson/jcsample-mmi.c b/simd/mips64/jcsample-mmi.c
similarity index 100%
rename from simd/loongson/jcsample-mmi.c
rename to simd/mips64/jcsample-mmi.c
diff --git a/simd/loongson/jcsample.h b/simd/mips64/jcsample.h
similarity index 100%
rename from simd/loongson/jcsample.h
rename to simd/mips64/jcsample.h
diff --git a/simd/loongson/jdcolext-mmi.c b/simd/mips64/jdcolext-mmi.c
similarity index 100%
rename from simd/loongson/jdcolext-mmi.c
rename to simd/mips64/jdcolext-mmi.c
diff --git a/simd/loongson/jdcolor-mmi.c b/simd/mips64/jdcolor-mmi.c
similarity index 100%
rename from simd/loongson/jdcolor-mmi.c
rename to simd/mips64/jdcolor-mmi.c
diff --git a/simd/loongson/jdmerge-mmi.c b/simd/mips64/jdmerge-mmi.c
similarity index 100%
rename from simd/loongson/jdmerge-mmi.c
rename to simd/mips64/jdmerge-mmi.c
diff --git a/simd/loongson/jdmrgext-mmi.c b/simd/mips64/jdmrgext-mmi.c
similarity index 100%
rename from simd/loongson/jdmrgext-mmi.c
rename to simd/mips64/jdmrgext-mmi.c
diff --git a/simd/loongson/jdsample-mmi.c b/simd/mips64/jdsample-mmi.c
similarity index 100%
rename from simd/loongson/jdsample-mmi.c
rename to simd/mips64/jdsample-mmi.c
diff --git a/simd/loongson/jfdctfst-mmi.c b/simd/mips64/jfdctfst-mmi.c
similarity index 100%
rename from simd/loongson/jfdctfst-mmi.c
rename to simd/mips64/jfdctfst-mmi.c
diff --git a/simd/loongson/jfdctint-mmi.c b/simd/mips64/jfdctint-mmi.c
similarity index 100%
rename from simd/loongson/jfdctint-mmi.c
rename to simd/mips64/jfdctint-mmi.c
diff --git a/simd/loongson/jidctfst-mmi.c b/simd/mips64/jidctfst-mmi.c
similarity index 100%
rename from simd/loongson/jidctfst-mmi.c
rename to simd/mips64/jidctfst-mmi.c
diff --git a/simd/loongson/jidctint-mmi.c b/simd/mips64/jidctint-mmi.c
similarity index 100%
rename from simd/loongson/jidctint-mmi.c
rename to simd/mips64/jidctint-mmi.c
diff --git a/simd/loongson/jquanti-mmi.c b/simd/mips64/jquanti-mmi.c
similarity index 100%
rename from simd/loongson/jquanti-mmi.c
rename to simd/mips64/jquanti-mmi.c
diff --git a/simd/loongson/jsimd.c b/simd/mips64/jsimd.c
similarity index 89%
rename from simd/loongson/jsimd.c
rename to simd/mips64/jsimd.c
index f7bc472..e8f1af5 100644
--- a/simd/loongson/jsimd.c
+++ b/simd/mips64/jsimd.c
@@ -1,5 +1,5 @@
 /*
- * jsimd_loongson.c
+ * jsimd_mips64.c
  *
  * Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
  * Copyright (C) 2009-2011, 2014, 2016, 2018, D. R. Commander.
@@ -13,7 +13,7 @@
  *
  * This file contains the interface between the "normal" portions
  * of the library and the SIMD implementations when running on a
- * Loongson architecture.
+ * 64-bit MIPS architecture.
  */
 
 #define JPEG_INTERNALS
@@ -24,8 +24,76 @@
 #include "../../jsimddct.h"
 #include "../jsimd.h"
 
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
 static unsigned int simd_support = ~0;
 
+#if defined(__linux__)
+
+#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, "ASEs implemented", 16) != 0)
+    return 0;
+  buffer += 16;
+  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, "loongson-mmi"))
+        simd_support |= JSIMD_MMI;
+    }
+    fclose(fd);
+  }
+  free(buffer);
+  return 1;
+}
+
+#endif
+
 /*
  * Check what SIMD accelerations are supported.
  *
@@ -37,14 +105,32 @@
 #ifndef NO_GETENV
   char *env = NULL;
 #endif
+#if defined(__linux__)
+  int bufsize = 1024; /* an initial guess for the line buffer size limit */
+#endif
 
   if (simd_support != ~0U)
     return;
 
+  simd_support = 0;
+
+#if defined(__linux__)
+  while (!parse_proc_cpuinfo(bufsize)) {
+    bufsize *= 2;
+    if (bufsize > SOMEWHAT_SANE_PROC_CPUINFO_SIZE_LIMIT)
+      break;
+  }
+#elif defined(__mips_loongson_vector_rev)
+  /* Only enable MMI by default on non-Linux platforms when the compiler flags
+   * support it. */
   simd_support |= JSIMD_MMI;
+#endif
 
 #ifndef NO_GETENV
   /* Force different settings through environment variables */
+  env = getenv("JSIMD_FORCEMMI");
+  if ((env != NULL) && (strcmp(env, "1") == 0))
+    simd_support = JSIMD_MMI;
   env = getenv("JSIMD_FORCENONE");
   if ((env != NULL) && (strcmp(env, "1") == 0))
     simd_support = 0;
diff --git a/simd/loongson/jsimd_mmi.h b/simd/mips64/jsimd_mmi.h
similarity index 100%
rename from simd/loongson/jsimd_mmi.h
rename to simd/mips64/jsimd_mmi.h
diff --git a/simd/loongson/loongson-mmintrin.h b/simd/mips64/loongson-mmintrin.h
similarity index 100%
rename from simd/loongson/loongson-mmintrin.h
rename to simd/mips64/loongson-mmintrin.h