diff options
author | Thiago Macieira <thiago.macieira@intel.com> | 2021-09-10 15:50:33 -0700 |
---|---|---|
committer | Thiago Macieira <thiago.macieira@intel.com> | 2021-10-04 14:01:40 -0700 |
commit | 349fb14c1d387e3ec052953e9f5b91b3f6b0dea7 (patch) | |
tree | ed7f285ec5283db4ebe6d01bbd2e2c0426e4609d | |
parent | 16e7366b5ce61418a69ba13a74996514b69dac37 (diff) |
QPlugin: update the arch requirements to match the x86-64 ISA levels
When we created the functionality, the levels were not yet standardized.
Now they are and you can use -march=x86-64-v3 (for example) to get to
them. We're making a split between "v1" and "baseline" here for the
benefit of 32-bit, which is not included in the ISA levels.
Change-Id: I2de1b4dfacd443148279fffd16a397a700b9a15a
Reviewed-by: Lars Knoll <lars.knoll@qt.io>
-rw-r--r-- | src/corelib/plugin/qfactoryloader.cpp | 12 | ||||
-rw-r--r-- | src/corelib/plugin/qplugin.h | 23 | ||||
-rw-r--r-- | src/corelib/plugin/qplugin_p.h | 51 | ||||
-rw-r--r-- | tests/auto/corelib/plugin/qplugin/tst_qplugin.cpp | 19 |
4 files changed, 89 insertions, 16 deletions
diff --git a/src/corelib/plugin/qfactoryloader.cpp b/src/corelib/plugin/qfactoryloader.cpp index 5a2b9e7758..1a27559fd0 100644 --- a/src/corelib/plugin/qfactoryloader.cpp +++ b/src/corelib/plugin/qfactoryloader.cpp @@ -95,11 +95,15 @@ QJsonDocument qJsonFromRawLibraryMetaData(const char *raw, qsizetype size, QStri return QJsonDocument(); } + DecodedArchRequirements archReq = + header.version == 0 ? decodeVersion0ArchRequirements(header.plugin_arch_requirements) + : decodeVersion1ArchRequirements(header.plugin_arch_requirements); + QJsonObject o; o.insert(QLatin1String("version"), QT_VERSION_CHECK(header.qt_major_version, header.qt_minor_version, 0)); - o.insert(QLatin1String("debug"), bool(header.plugin_arch_requirements & 1)); - o.insert(QLatin1String("archreq"), header.plugin_arch_requirements); + o.insert(QLatin1String("debug"), archReq.isDebug); + o.insert(QLatin1String("archlevel"), archReq.level); // convert the top-level map integer keys for (auto it : metadata.toMap()) { @@ -112,9 +116,7 @@ QJsonDocument qJsonFromRawLibraryMetaData(const char *raw, qsizetype size, QStri #undef CONVERT_TO_STRING case int(QtPluginMetaDataKeys::Requirements): - // special case: recreate the debug key - o.insert(QLatin1String("debug"), bool(it.second.toInteger() & 1)); - key = QStringLiteral("archreq"); + // ignore, handled above break; } } else { diff --git a/src/corelib/plugin/qplugin.h b/src/corelib/plugin/qplugin.h index a80ee28c52..affe3f5412 100644 --- a/src/corelib/plugin/qplugin.h +++ b/src/corelib/plugin/qplugin.h @@ -47,6 +47,7 @@ QT_BEGIN_NAMESPACE +// Used up to Qt 6.2 inline constexpr unsigned char qPluginArchRequirements() { return 0 @@ -65,7 +66,7 @@ inline constexpr unsigned char qPluginArchRequirements() typedef QObject *(*QtPluginInstanceFunction)(); struct QPluginMetaData { - static constexpr quint8 CurrentMetaDataVersion = 0; + static constexpr quint8 CurrentMetaDataVersion = 1; static constexpr char MagicString[] = { 'Q', 'T', 'M', 'E', 'T', 'A', 'D', 'A', 'T', 'A', ' ', '!' }; @@ -79,11 +80,29 @@ struct QPluginMetaData out[i] = in[i]; } + static constexpr quint8 archRequirements() + { + quint8 v = 0; +#if defined(__AVX512F__) + v = 4; // x86-64-v4: AVX512F, AVX512BW, AVX512CD, AVX512DQ and AVX512VL +#elif defined(__AVX__) || defined(__BMI__) || defined(__BMI2__) || defined(__MOVBE__) + v = 3; // x86-64-v3: AVX, AVX2, BMI1, BMI2, F16C, FMA, LZCNT, MOVBE, XSAVE +#elif defined(__SSE3__) + v = 2; // x86-64-v2: POPCNT, SSE3, SSSE3, SSE4.1 and SSE4.2. +#elif defined(__SSE__) || defined(__MMX___) + v = 1; // x86-64 baseline: SSE and SSE2 +#endif +#ifndef QT_NO_DEBUG + v |= 0x80; +#endif + return v; + } + struct Header { quint8 version = CurrentMetaDataVersion; quint8 qt_major_version = QT_VERSION_MAJOR; quint8 qt_minor_version = QT_VERSION_MINOR; - quint8 plugin_arch_requirements = qPluginArchRequirements(); + quint8 plugin_arch_requirements = archRequirements(); }; static_assert(alignof(Header) == 1, "Alignment of header incorrect with this compiler"); diff --git a/src/corelib/plugin/qplugin_p.h b/src/corelib/plugin/qplugin_p.h index ce45ebf700..80ee02e761 100644 --- a/src/corelib/plugin/qplugin_p.h +++ b/src/corelib/plugin/qplugin_p.h @@ -72,6 +72,57 @@ enum class QtPluginMetaDataKeys { F(QtPluginMetaDataKeys::MetaData, "MetaData", "Other meta data") \ F(QtPluginMetaDataKeys::URI, "URI", "Plugin URI") +namespace { +struct DecodedArchRequirements +{ + quint8 level; + bool isDebug; + friend constexpr bool operator==(DecodedArchRequirements r1, DecodedArchRequirements r2) + { + return r1.level == r2.level && r1.isDebug == r2.isDebug; + } +}; + +static constexpr DecodedArchRequirements decodeVersion0ArchRequirements(quint8 value) +{ + // see qPluginArchRequirements() and QPluginMetaDataV2::archRequirements() + DecodedArchRequirements r = {}; +#ifdef Q_PROCESSOR_X86 + if (value & 4) + r.level = 4; // AVX512F -> x86-64-v4 + else if (value & 2) + r.level = 3; // AVX2 -> x86-64-v3 +#endif + if (value & 1) + r.isDebug = true; + return r; +} +// self checks +static_assert(decodeVersion0ArchRequirements(0) == DecodedArchRequirements{ 0, false }); +static_assert(decodeVersion0ArchRequirements(1) == DecodedArchRequirements{ 0, true }); +#ifdef Q_PROCESSOR_X86 +static_assert(decodeVersion0ArchRequirements(2) == DecodedArchRequirements{ 3, false }); +static_assert(decodeVersion0ArchRequirements(3) == DecodedArchRequirements{ 3, true }); +static_assert(decodeVersion0ArchRequirements(4) == DecodedArchRequirements{ 4, false }); +static_assert(decodeVersion0ArchRequirements(5) == DecodedArchRequirements{ 4, true }); +#endif + +static constexpr DecodedArchRequirements decodeVersion1ArchRequirements(quint8 value) +{ + return { quint8(value & 0x7f), bool(value & 0x80) }; +} +// self checks +static_assert(decodeVersion1ArchRequirements(0) == DecodedArchRequirements{ 0, false }); +static_assert(decodeVersion1ArchRequirements(0x80) == DecodedArchRequirements{ 0, true }); +#ifdef Q_PROCESSOR_X86 +static_assert(decodeVersion1ArchRequirements(1) == DecodedArchRequirements{ 1, false }); +static_assert(decodeVersion1ArchRequirements(3) == DecodedArchRequirements{ 3, false}); +static_assert(decodeVersion1ArchRequirements(4) == DecodedArchRequirements{ 4, false }); +static_assert(decodeVersion1ArchRequirements(0x82) == DecodedArchRequirements{ 2, true }); +static_assert(decodeVersion1ArchRequirements(0x84) == DecodedArchRequirements{ 4, true }); +#endif +} // unnamed namespace + QT_END_NAMESPACE #endif // QPLUGIN_P_H diff --git a/tests/auto/corelib/plugin/qplugin/tst_qplugin.cpp b/tests/auto/corelib/plugin/qplugin/tst_qplugin.cpp index 14be0082c7..ddc9ff7e7c 100644 --- a/tests/auto/corelib/plugin/qplugin/tst_qplugin.cpp +++ b/tests/auto/corelib/plugin/qplugin/tst_qplugin.cpp @@ -139,6 +139,7 @@ void tst_QPlugin::scanInvalidPlugin_data() // CBOR metadata static constexpr QPluginMetaData::MagicHeader header = {}; + static constexpr qsizetype MagicLen = sizeof(header.magic); QByteArray cprefix(reinterpret_cast<const char *>(&header), sizeof(header)); QByteArray cborValid = [] { @@ -150,27 +151,27 @@ void tst_QPlugin::scanInvalidPlugin_data() }(); QTest::newRow("cbor-control") << (cprefix + cborValid) << true << ""; - cprefix[12] = 1; - QTest::newRow("cbor-major-too-new") << (cprefix + cborValid) << false - << " Invalid metadata version"; - - cprefix[12] = 0; - cprefix[13] = QT_VERSION_MAJOR + 1; + cprefix[MagicLen + 1] = QT_VERSION_MAJOR + 1; QTest::newRow("cbor-major-too-new") << (cprefix + cborValid) << false << ""; - cprefix[13] = QT_VERSION_MAJOR - 1; + cprefix[MagicLen + 1] = QT_VERSION_MAJOR - 1; QTest::newRow("cbor-major-too-old") << (cprefix + cborValid) << false << ""; - cprefix[13] = QT_VERSION_MAJOR; - cprefix[14] = QT_VERSION_MINOR + 1; + cprefix[MagicLen + 1] = QT_VERSION_MAJOR; + cprefix[MagicLen + 2] = QT_VERSION_MINOR + 1; QTest::newRow("cbor-minor-too-new") << (cprefix + cborValid) << false << ""; + cprefix[MagicLen + 2] = QT_VERSION_MINOR; QTest::newRow("cbor-invalid") << (cprefix + "\xff") << false << " Metadata parsing error: Invalid CBOR stream: unexpected 'break' byte"; QTest::newRow("cbor-not-map1") << (cprefix + "\x01") << false << " Unexpected metadata contents"; QTest::newRow("cbor-not-map2") << (cprefix + "\x81\x01") << false << " Unexpected metadata contents"; + + ++cprefix[MagicLen + 0]; + QTest::newRow("cbor-major-too-new") << (cprefix + cborValid) << false + << " Invalid metadata version"; } static const char invalidPluginSignature[] = "qplugin testfile"; |