Add configure-time checking for the SSE and AVX features on Windows
authorThiago Macieira <thiago.macieira@intel.com>
Fri, 30 Dec 2011 00:44:16 +0000 (22:44 -0200)
committerQt by Nokia <qt-info@nokia.com>
Tue, 12 Jun 2012 15:34:52 +0000 (17:34 +0200)
Modify configure.exe to run some configure-time tests and check if
the SSE and AVX compiler features are supported.

The tests themselves required a bit of changes to compile with
MSVC. The include in sse4_2.cpp was wrong. And for whatever reason, it
didn't like the volatile variables, which GCC, Clang and ICC have been
happy with. This should produce no effect in compilation, though: even
dead code must be syntactically correct. We're not running the output.

Change-Id: Ibe5d0904a378a7efed853c7215f88a2ddcefb1b3
Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@nokia.com>
17 files changed:
config.tests/common/avx/avx.cpp
config.tests/common/avx/avx.pro
config.tests/common/avx2/avx2.cpp
config.tests/common/avx2/avx2.pro
config.tests/common/sse2/sse2.pro
config.tests/common/sse3/sse3.cpp
config.tests/common/sse3/sse3.pro
config.tests/common/sse4_1/sse4_1.cpp
config.tests/common/sse4_1/sse4_1.pro
config.tests/common/sse4_2/sse4_2.cpp
config.tests/common/sse4_2/sse4_2.pro
config.tests/common/ssse3/ssse3.cpp
config.tests/common/ssse3/ssse3.pro
tools/configure/configureapp.cpp
tools/configure/configureapp.h
tools/configure/environment.cpp
tools/configure/environment.h

index bc5be65..9d849a7 100644 (file)
@@ -43,9 +43,9 @@
 
 int main(int, char**)
 {
-    volatile __m256d a = _mm256_setzero_pd();
-    volatile __m256d b = _mm256_set1_pd(42.42);
-    volatile __m256d result = _mm256_add_pd(a, b);
+    __m256d a = _mm256_setzero_pd();
+    __m256d b = _mm256_set1_pd(42.42);
+    __m256d result = _mm256_add_pd(a, b);
     (void)result;
     return 0;
 }
index f16f7e8..ba7fd96 100644 (file)
@@ -1,5 +1,6 @@
 SOURCES = avx.cpp
-CONFIG -= x11 qt
+CONFIG -= qt dylib release debug_and_release
+CONFIG += debug console
 mac:CONFIG -= app_bundle
 isEmpty(QMAKE_CFLAGS_AVX):error("This compiler does not support AVX")
 else:QMAKE_CXXFLAGS += $$QMAKE_CFLAGS_AVX
index 9e56531..6ebe252 100644 (file)
@@ -45,11 +45,11 @@ int main(int, char**)
 {
     /* AVX */
     _mm256_zeroall();
-    volatile __m256i a = _mm256_setzero_si256();
+    __m256i a = _mm256_setzero_si256();
 
     /* AVX2 */
-    volatile __m256i b = _mm256_and_si256(a, a);
-    volatile __m256i result = _mm256_add_epi8(a, b);
+    __m256i b = _mm256_and_si256(a, a);
+    __m256i result = _mm256_add_epi8(a, b);
     (void)result;
     return 0;
 }
index 09590a8..5aa9429 100644 (file)
@@ -1,5 +1,6 @@
 SOURCES = avx2.cpp
-CONFIG -= x11 qt
+CONFIG -= qt dylib release debug_and_release
+CONFIG += debug console
 mac:CONFIG -= app_bundle
 isEmpty(QMAKE_CFLAGS_AVX2):error("This compiler does not support AVX2")
 else:QMAKE_CXXFLAGS += $$QMAKE_CFLAGS_AVX2
index 13f252a..c8d0861 100644 (file)
@@ -1,5 +1,6 @@
 SOURCES = sse2.cpp
-CONFIG -= x11 qt
+CONFIG -= qt dylib release debug_and_release
+CONFIG += debug console
 mac:CONFIG -= app_bundle
 isEmpty(QMAKE_CFLAGS_SSE2):error("This compiler does not support SSE2")
 else:QMAKE_CXXFLAGS += $$QMAKE_CFLAGS_SSE2
index c35586a..9a79dca 100644 (file)
@@ -43,9 +43,9 @@
 
 int main(int, char**)
 {
-    volatile __m128d a = _mm_set1_pd(6.28);
-    volatile __m128d b = _mm_set1_pd(3.14);
-    volatile __m128d result = _mm_addsub_pd(a, b);
+    __m128d a = _mm_set1_pd(6.28);
+    __m128d b = _mm_set1_pd(3.14);
+    __m128d result = _mm_addsub_pd(a, b);
     result = _mm_movedup_pd(result);
     return 0;
 }
index 8d9853c..90f61d2 100644 (file)
@@ -1,5 +1,6 @@
 SOURCES = sse3.cpp
-CONFIG -= x11 qt
+CONFIG -= qt dylib release debug_and_release
+CONFIG += debug console
 mac:CONFIG -= app_bundle
 isEmpty(QMAKE_CFLAGS_SSE3):error("This compiler does not support SSE3")
 else:QMAKE_CXXFLAGS += $$QMAKE_CFLAGS_SSE3
index b2762b9..693fd8a 100644 (file)
@@ -43,9 +43,9 @@
 
 int main(int, char**)
 {
-    volatile __m128 a = _mm_setzero_ps();
+    __m128 a = _mm_setzero_ps();
     _mm_ceil_ps(a);
-    volatile __m128i result = _mm_mullo_epi32(_mm_set1_epi32(42), _mm_set1_epi32(64));
+    __m128i result = _mm_mullo_epi32(_mm_set1_epi32(42), _mm_set1_epi32(64));
     (void)result;
     return 0;
 }
index 5395176..d92be9d 100644 (file)
@@ -1,5 +1,6 @@
 SOURCES = sse4_1.cpp
-CONFIG -= x11 qt
+CONFIG -= qt dylib release debug_and_release
+CONFIG += debug console
 mac:CONFIG -= app_bundle
 isEmpty(QMAKE_CFLAGS_SSE4_1):error("This compiler does not support SSE4.1")
 else:QMAKE_CXXFLAGS += $$QMAKE_CFLAGS_SSE4_1
index 9052d06..1645070 100644 (file)
 **
 ****************************************************************************/
 
-#include <smmintrin.h>
+#include <nmmintrin.h>
 
 int main(int, char**)
 {
-    volatile __m128i a = _mm_setzero_si128();
-    volatile __m128i b = _mm_set1_epi32(42);
-    volatile __m128i result = _mm_cmpestrm(a, 16, b, 16, 0);
+    __m128i a = _mm_setzero_si128();
+    __m128i b = _mm_set1_epi32(42);
+    __m128i result = _mm_cmpestrm(a, 16, b, 16, 0);
     (void)result;
     return 0;
 }
index 044eb19..744098d 100644 (file)
@@ -1,5 +1,6 @@
 SOURCES = sse4_2.cpp
-CONFIG -= x11 qt
+CONFIG -= qt dylib release debug_and_release
+CONFIG += debug console
 mac:CONFIG -= app_bundle
 isEmpty(QMAKE_CFLAGS_SSE4_2):error("This compiler does not support SSE4.2")
 else:QMAKE_CXXFLAGS += $$QMAKE_CFLAGS_SSE4_2
index f486bed..fed9142 100644 (file)
@@ -43,9 +43,9 @@
 
 int main(int, char**)
 {
-    volatile __m128i a = _mm_set1_epi32(42);
+    __m128i a = _mm_set1_epi32(42);
     _mm_abs_epi8(a);
-    volatile __m128i result = _mm_sign_epi16(a, _mm_set1_epi32(64));
+    __m128i result = _mm_sign_epi16(a, _mm_set1_epi32(64));
     (void)result;
     return 0;
 }
index dd86c41..e3984bd 100644 (file)
@@ -1,5 +1,6 @@
 SOURCES = ssse3.cpp
-CONFIG -= x11 qt
+CONFIG -= qt dylib release debug_and_release
+CONFIG += debug console
 mac:CONFIG -= app_bundle
 isEmpty(QMAKE_CFLAGS_SSSE3):error("This compiler does not support SSSE3")
 else:QMAKE_CXXFLAGS += $$QMAKE_CFLAGS_SSSE3
index 5a24e9b..84d759b 100644 (file)
@@ -212,6 +212,12 @@ Configure::Configure(int& argc, char** argv)
     dictionary[ "WIDGETS" ]         = "yes";
     dictionary[ "RTTI" ]            = "yes";
     dictionary[ "SSE2" ]            = "auto";
+    dictionary[ "SSE3" ]            = "auto";
+    dictionary[ "SSSE3" ]           = "auto";
+    dictionary[ "SSE4_1" ]          = "auto";
+    dictionary[ "SSE4_2" ]          = "auto";
+    dictionary[ "AVX" ]             = "auto";
+    dictionary[ "AVX2" ]            = "auto";
     dictionary[ "IWMMXT" ]          = "auto";
     dictionary[ "SYNCQT" ]          = "auto";
     dictionary[ "CE_CRT" ]          = "no";
@@ -808,6 +814,30 @@ void Configure::parseCmdLine()
             dictionary[ "SSE2" ] = "no";
         else if (configCmdLine.at(i) == "-sse2")
             dictionary[ "SSE2" ] = "yes";
+        else if (configCmdLine.at(i) == "-no-sse3")
+            dictionary[ "SSE3" ] = "no";
+        else if (configCmdLine.at(i) == "-sse3")
+            dictionary[ "SSE3" ] = "yes";
+        else if (configCmdLine.at(i) == "-no-ssse3")
+            dictionary[ "SSSE3" ] = "no";
+        else if (configCmdLine.at(i) == "-ssse3")
+            dictionary[ "SSSE3" ] = "yes";
+        else if (configCmdLine.at(i) == "-no-sse4.1")
+            dictionary[ "SSE4_1" ] = "no";
+        else if (configCmdLine.at(i) == "-sse4.1")
+            dictionary[ "SSE4_1" ] = "yes";
+        else if (configCmdLine.at(i) == "-no-sse4.2")
+            dictionary[ "SSE4_2" ] = "no";
+        else if (configCmdLine.at(i) == "-sse4.2")
+            dictionary[ "SSE4_2" ] = "yes";
+        else if (configCmdLine.at(i) == "-no-avx")
+            dictionary[ "AVX" ] = "no";
+        else if (configCmdLine.at(i) == "-avx")
+            dictionary[ "AVX" ] = "yes";
+        else if (configCmdLine.at(i) == "-no-avx2")
+            dictionary[ "AVX2" ] = "no";
+        else if (configCmdLine.at(i) == "-avx2")
+            dictionary[ "AVX2" ] = "yes";
         else if (configCmdLine.at(i) == "-no-iwmmxt")
             dictionary[ "IWMMXT" ] = "no";
         else if (configCmdLine.at(i) == "-iwmmxt")
@@ -1380,6 +1410,12 @@ void Configure::applySpecSpecifics()
         dictionary[ "OPENSSL" ]             = "no";
         dictionary[ "RTTI" ]                = "no";
         dictionary[ "SSE2" ]                = "no";
+        dictionary[ "SSE3" ]                = "no";
+        dictionary[ "SSSE3" ]               = "no";
+        dictionary[ "SSE4_1" ]              = "no";
+        dictionary[ "SSE4_2" ]              = "no";
+        dictionary[ "AVX" ]                 = "no";
+        dictionary[ "AVX2" ]                = "no";
         dictionary[ "IWMMXT" ]              = "no";
         dictionary[ "CE_CRT" ]              = "yes";
         dictionary[ "DIRECTSHOW" ]          = "no";
@@ -1468,7 +1504,10 @@ bool Configure::displayHelp()
                     "[-qt-zlib] [-system-zlib] [-qt-pcre] [-system-pcre] [-no-gif]\n"
                     "[-no-libpng] [-qt-libpng] [-system-libpng]\n"
                     "[-no-libjpeg] [-qt-libjpeg] [-system-libjpeg]\n"
-                    "[-sse2] [-no-sse2]\n"
+                    "[-sse2] [-no-sse2] [-sse3] [-no-sse3]\n"
+                    "[-ssse3] [-no-ssse3]\n"
+                    "[-sse4.1] [-no-sse4.1] [-sse4.2] [-no-sse4.2]\n"
+                    "[-avx] [-no-avx] [-avx2] [-no-avx2]\n"
                     "[-no-iwmmxt] [-iwmmxt] [-openssl] [-openssl-linked]\n"
                     "[-no-openssl] [-no-dbus] [-dbus] [-dbus-linked] [-platform <spec>]\n"
                     "[-qtnamespace <namespace>] [-qtlibinfix <infix>] [-no-phonon]\n"
@@ -1635,7 +1674,19 @@ bool Configure::displayHelp()
         desc("RTTI", "no",      "-no-rtti",             "Do not compile runtime type information.");
         desc("RTTI", "yes",     "-rtti",                "Compile runtime type information.\n");
         desc("SSE2", "no",      "-no-sse2",             "Do not compile with use of SSE2 instructions");
-        desc("SSE2", "yes",      "-sse2",               "Compile with use of SSE2 instructions");
+        desc("SSE2", "yes",     "-sse2",                "Compile with use of SSE2 instructions");
+        desc("SSE3", "no",      "-no-sse3",             "Do not compile with use of SSE3 instructions");
+        desc("SSE3", "yes",     "-sse3",                "Compile with use of SSE3 instructions");
+        desc("SSSE3", "no",     "-no-ssse3",            "Do not compile with use of SSSE3 instructions");
+        desc("SSSE3", "yes",    "-ssse3",               "Compile with use of SSSE3 instructions");
+        desc("SSE4_1", "no",    "-no-sse4.1",           "Do not compile with use of SSE4.1 instructions");
+        desc("SSE4_1", "yes",   "-sse4.1",              "Compile with use of SSE4.1 instructions");
+        desc("SSE4_2", "no",    "-no-sse4.2",           "Do not compile with use of SSE4.2 instructions");
+        desc("SSE4_2", "yes",   "-sse4.2",              "Compile with use of SSE4.2 instructions");
+        desc("AVX", "no",       "-no-avx",              "Do not compile with use of AVX instructions");
+        desc("AVX", "yes",      "-avx",                 "Compile with use of AVX instructions");
+        desc("AVX2", "no",      "-no-avx2",             "Do not compile with use of AVX2 instructions");
+        desc("AVX2", "yes",     "-avx2",                "Compile with use of AVX2 instructions");
         desc("OPENSSL", "no",    "-no-openssl",         "Do not compile in OpenSSL support");
         desc("OPENSSL", "yes",   "-openssl",            "Compile in run-time OpenSSL support");
         desc("OPENSSL", "linked","-openssl-linked",     "Compile in linked OpenSSL support");
@@ -1878,7 +1929,19 @@ bool Configure::checkAvailability(const QString &part)
     else if (part == "DIRECTSHOW")
         available = (dictionary.value("XQMAKESPEC").startsWith("wince"));
     else if (part == "SSE2")
-        available = (dictionary.value("QMAKESPEC") != "win32-msvc");
+        available = tryCompileProject("common/sse2");
+    else if (part == "SSE3")
+        available = tryCompileProject("common/sse3");
+    else if (part == "SSSE3")
+        available = tryCompileProject("common/ssse3");
+    else if (part == "SSE4_1")
+        available = tryCompileProject("common/sse4_1");
+    else if (part == "SSE4_2")
+        available = tryCompileProject("common/sse4_2");
+    else if (part == "AVX")
+        available = tryCompileProject("common/avx");
+    else if (part == "AVX2")
+        available = tryCompileProject("common/avx2");
     else if (part == "OPENSSL")
         available = findFile("openssl\\ssl.h");
     else if (part == "DBUS")
@@ -1989,6 +2052,18 @@ void Configure::autoDetection()
         dictionary["SQL_IBASE"] = checkAvailability("SQL_IBASE") ? defaultTo("SQL_IBASE") : "no";
     if (dictionary["SSE2"] == "auto")
         dictionary["SSE2"] = checkAvailability("SSE2") ? "yes" : "no";
+    if (dictionary["SSE3"] == "auto")
+        dictionary["SSE3"] = checkAvailability("SSE3") ? "yes" : "no";
+    if (dictionary["SSSE3"] == "auto")
+        dictionary["SSSE3"] = checkAvailability("SSSE3") ? "yes" : "no";
+    if (dictionary["SSE4_1"] == "auto")
+        dictionary["SSE4_1"] = checkAvailability("SSE4_1") ? "yes" : "no";
+    if (dictionary["SSE4_2"] == "auto")
+        dictionary["SSE4_2"] = checkAvailability("SSE4_2") ? "yes" : "no";
+    if (dictionary["AVX"] == "auto")
+        dictionary["AVX"] = checkAvailability("AVX") ? "yes" : "no";
+    if (dictionary["AVX2"] == "auto")
+        dictionary["AVX2"] = checkAvailability("AVX2") ? "yes" : "no";
     if (dictionary["IWMMXT"] == "auto")
         dictionary["IWMMXT"] = checkAvailability("IWMMXT") ? "yes" : "no";
     if (dictionary["OPENSSL"] == "auto")
@@ -2543,6 +2618,18 @@ void Configure::generateCachefile()
         moduleStream << "CONFIG += create_prl link_prl";
         if (dictionary[ "SSE2" ] == "yes")
             moduleStream << " sse2";
+        if (dictionary[ "SSE3" ] == "yes")
+            moduleStream << " sse3";
+        if (dictionary[ "SSSE3" ] == "yes")
+            moduleStream << " ssse3";
+        if (dictionary[ "SSE4_1" ] == "yes")
+            moduleStream << " sse4_1";
+        if (dictionary[ "SSE4_2" ] == "yes")
+            moduleStream << " sse4_2";
+        if (dictionary[ "AVX" ] == "yes")
+            moduleStream << " avx";
+        if (dictionary[ "AVX2" ] == "yes")
+            moduleStream << " avx2";
         if (dictionary[ "IWMMXT" ] == "yes")
             moduleStream << " iwmmxt";
         moduleStream << endl;
@@ -2665,6 +2752,47 @@ void Configure::detectArch()
     QDir::setCurrent(oldpwd);
 }
 
+bool Configure::tryCompileProject(const QString &projectPath, const QString &extraOptions)
+{
+    QString oldpwd = QDir::currentPath();
+
+    QString newpwd = fixSeparators(QString("%1/config.tests/%2").arg(buildPath, projectPath));
+    if (!QDir().exists(newpwd) && !QDir().mkpath(newpwd)) {
+        cout << "Failed to create directory " << qPrintable(newpwd) << endl;
+        dictionary["DONE"] = "error";
+        return false;
+    }
+    if (!QDir::setCurrent(newpwd)) {
+        cout << "Failed to change working directory to " << qPrintable(newpwd) << endl;
+        dictionary["DONE"] = "error";
+        return false;
+    }
+
+    // run qmake
+    QString command =
+            fixSeparators(QString("%1/bin/qmake.exe %2/config.tests/%3 %4 2>&1")
+                          .arg(buildPath, sourcePath, projectPath, extraOptions));
+    int code = 0;
+    QString output = Environment::execute(command, &code);
+    //cout << output << endl;
+
+    if (code == 0) {
+        // compile
+        command = dictionary[ "MAKE" ];
+        if (command.contains("nmake"))
+            command += " /NOLOGO";
+        command += " -s 2>&1";
+        output = Environment::execute(command, &code);
+        //cout << output << endl;
+
+        // clean up
+        Environment::execute(command + " distclean 2>&1");
+    }
+
+    QDir::setCurrent(oldpwd);
+    return code == 0;
+}
+
 void Configure::generateQConfigPri()
 {
     // Generate qconfig.pri
@@ -3108,6 +3236,12 @@ void Configure::displayConfig()
     sout << "Accessibility support......." << dictionary[ "ACCESSIBILITY" ] << endl;
     sout << "RTTI support................" << dictionary[ "RTTI" ] << endl;
     sout << "SSE2 support................" << dictionary[ "SSE2" ] << endl;
+    sout << "SSE3 support................" << dictionary[ "SSE3" ] << endl;
+    sout << "SSSE3 support..............." << dictionary[ "SSSE3" ] << endl;
+    sout << "SSE4.1 support.............." << dictionary[ "SSE4_1" ] << endl;
+    sout << "SSE4.2 support.............." << dictionary[ "SSE4_2" ] << endl;
+    sout << "AVX support................." << dictionary[ "AVX" ] << endl;
+    sout << "AVX2 support................" << dictionary[ "AVX2" ] << endl;
     sout << "IWMMXT support.............." << dictionary[ "IWMMXT" ] << endl;
     sout << "OpenGL support.............." << dictionary[ "OPENGL" ] << endl;
     if (dictionary.value(QStringLiteral("OPENGL_ES_2")) == QStringLiteral("yes")) {
index 4ac0736..5aac227 100644 (file)
@@ -169,6 +169,8 @@ private:
     void saveCmdLine();
 #endif
 
+    bool tryCompileProject(const QString &projectPath, const QString &extraOptions = QString());
+
     void desc(const char *description, int startingAt = 0, int wrapIndent = 0);
     void desc(const char *option, const char *description, bool skipIndent = false, char fillChar = '.');
     void desc(const char *mark_option, const char *mark, const char *option, const char *description, char fillChar = '.');
index 43cfc06..0365340 100644 (file)
@@ -431,7 +431,7 @@ int Environment::execute(QStringList arguments, const QStringList &additionalEnv
 
     Taken from qmake's system() command.
 */
-QString Environment::execute(const QString &command)
+QString Environment::execute(const QString &command, int *returnCode)
 {
     QString output;
     FILE *proc = _popen(command.toLatin1().constData(), "r");
@@ -443,8 +443,11 @@ QString Environment::execute(const QString &command)
         buff[read_in] = '\0';
         output += buff;
     }
-    if (proc)
-        _pclose(proc);
+    if (proc) {
+        int r = _pclose(proc);
+        if (returnCode)
+            *returnCode = r;
+    }
     return output;
 }
 
index 5075e9a..979d538 100644 (file)
@@ -66,7 +66,7 @@ public:
     static bool detectExecutable(const QString &executable);
 
     static int execute(QStringList arguments, const QStringList &additionalEnv, const QStringList &removeEnv);
-    static QString execute(const QString &command);
+    static QString execute(const QString &command, int *returnCode = 0);
     static bool cpdir(const QString &srcDir,
                       const QString &destDir,
                       const QString &includeSrcDir = QString());