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>
This commit is contained in:
Thiago Macieira 2021-09-10 15:50:33 -07:00
parent 16e7366b5c
commit 349fb14c1d
4 changed files with 89 additions and 16 deletions

View File

@ -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 {

View File

@ -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");

View File

@ -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

View File

@ -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";