From dd92002416270c56c795cce81fb9f0e55c1b2ddd Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Mon, 10 Aug 2015 13:08:15 -0700 Subject: [PATCH] QHostAddress: Improve code generation Mostly related to IPv6, because Q_IPV6ADDR is an array of char, so the compilers were generating byte access to each value. Instead, force access as 32- and 64-bit in most places that make sense (64-bit access decays to 32-bit on 32-bit machines). In one isLoopback(), this is now a 128-bit access for best improvement. Some smaller improvements relating to SpecialAddress by combining the three IPv4 special addresses. Change-Id: I7de033f80b0e4431b7f1ffff13f932b1cd7b5d21 Reviewed-by: Richard J. Moore --- src/network/kernel/qhostaddress.cpp | 103 +++++++++--------- .../kernel/qhostaddress/tst_qhostaddress.cpp | 2 + 2 files changed, 56 insertions(+), 49 deletions(-) diff --git a/src/network/kernel/qhostaddress.cpp b/src/network/kernel/qhostaddress.cpp index 6ee76a4250..935af04e31 100644 --- a/src/network/kernel/qhostaddress.cpp +++ b/src/network/kernel/qhostaddress.cpp @@ -46,6 +46,9 @@ #ifndef QT_NO_DATASTREAM #include #endif +#ifdef __SSE2__ +# include +#endif #ifdef QT_LINUXBASE # include @@ -106,7 +109,11 @@ public: QString scopeId; quint32 a; // IPv4 address - Q_IPV6ADDR a6; // IPv6 address + union { + Q_IPV6ADDR a6; // IPv6 address + struct { quint64 c[2]; } a6_64; + struct { quint32 c[4]; } a6_32; + }; QAbstractSocket::NetworkLayerProtocol protocol; bool isParsed; @@ -123,24 +130,17 @@ QHostAddressPrivate::QHostAddressPrivate() void QHostAddressPrivate::setAddress(quint32 a_) { a = a_; - //create mapped address, except for a_ == 0 (any) - memset(&a6, 0, sizeof(a6)); - if (a) { - a6[11] = 0xFF; - a6[10] = 0xFF; - } else { - a6[11] = 0; - a6[10] = 0; - } - - int i; - for (i=15; a_ != 0; i--) { - a6[i] = a_ & 0xFF; - a_ >>=8; - } - Q_ASSERT(i >= 11); protocol = QAbstractSocket::IPv4Protocol; isParsed = true; + + //create mapped address, except for a_ == 0 (any) + a6_64.c[0] = 0; + if (a) { + a6_32.c[2] = qToBigEndian(0xffff); + a6_32.c[3] = qToBigEndian(a); + } else { + a6_64.c[1] = 0; + } } /// parses v4-mapped addresses or the AnyIPv6 address and stores in \a a; @@ -163,21 +163,16 @@ static bool convertToIpv4(quint32& a, const Q_IPV6ADDR &a6) void QHostAddressPrivate::setAddress(const quint8 *a_) { - for (int i = 0; i < 16; i++) - a6[i] = a_[i]; - a = 0; - convertToIpv4(a, a6); protocol = QAbstractSocket::IPv6Protocol; isParsed = true; + memcpy(a6.c, a_, sizeof(a6)); + a = 0; + convertToIpv4(a, a6); } void QHostAddressPrivate::setAddress(const Q_IPV6ADDR &a_) { - a6 = a_; - a = 0; - convertToIpv4(a, a6); - protocol = QAbstractSocket::IPv6Protocol; - isParsed = true; + setAddress(a_.c); } static bool parseIp6(const QString &address, QIPAddressUtils::IPv6Address &addr, QString *scopeId) @@ -486,31 +481,35 @@ QHostAddress::QHostAddress(SpecialAddress address) { Q_IPV6ADDR ip6; memset(&ip6, 0, sizeof ip6); + quint32 ip4 = INADDR_ANY; switch (address) { case Null: - break; + return; + case Broadcast: - d->setAddress(quint32(-1)); + ip4 = INADDR_BROADCAST; break; case LocalHost: - d->setAddress(0x7f000001); - break; - case LocalHostIPv6: - ip6[15] = 1; - d->setAddress(ip6); + ip4 = INADDR_LOOPBACK; break; case AnyIPv4: - setAddress(0u); break; + + case LocalHostIPv6: + ip6[15] = 1; + // fall through case AnyIPv6: d->setAddress(ip6); - break; + return; + case Any: - d->clear(); d->protocol = QAbstractSocket::AnyIPProtocol; - break; + return; } + + // common IPv4 part + d->setAddress(ip4); } /*! @@ -837,34 +836,36 @@ bool QHostAddress::operator==(const QHostAddress &other) const bool QHostAddress::operator ==(SpecialAddress other) const { QT_ENSURE_PARSED(this); + quint32 ip4 = INADDR_ANY; switch (other) { case Null: return d->protocol == QAbstractSocket::UnknownNetworkLayerProtocol; case Broadcast: - return d->protocol == QAbstractSocket::IPv4Protocol && d->a == INADDR_BROADCAST; + ip4 = INADDR_BROADCAST; + break; case LocalHost: - return d->protocol == QAbstractSocket::IPv4Protocol && d->a == INADDR_LOOPBACK; + ip4 = INADDR_LOOPBACK; + break; case Any: return d->protocol == QAbstractSocket::AnyIPProtocol; case AnyIPv4: - return d->protocol == QAbstractSocket::IPv4Protocol && d->a == INADDR_ANY; + break; case LocalHostIPv6: case AnyIPv6: if (d->protocol == QAbstractSocket::IPv6Protocol) { - Q_IPV6ADDR ip6 = { { 0 } }; - ip6[15] = quint8(other == LocalHostIPv6); // 1 for localhost, 0 for any - return memcmp(&d->a6, &ip6, sizeof ip6) == 0; + quint64 second = quint8(other == LocalHostIPv6); // 1 for localhost, 0 for any + return d->a6_64.c[0] == 0 && d->a6_64.c[1] == qToBigEndian(second); } return false; } - Q_UNREACHABLE(); - return false; + // common IPv4 part + return d->protocol == QAbstractSocket::IPv4Protocol && d->a == ip4; } /*! @@ -1086,11 +1087,15 @@ bool QHostAddress::isLoopback() const if ((d->a & 0xFF000000) == 0x7F000000) return true; // v4 range (including IPv6 wrapped IPv4 addresses) if (d->protocol == QAbstractSocket::IPv6Protocol) { - if (d->a6.c[15] != 1) +#ifdef __SSE2__ + const __m128i loopback = _mm_setr_epi8(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1); + __m128i ipv6 = _mm_loadu_si128((const __m128i *)d->a6.c); + __m128i cmp = _mm_cmpeq_epi8(ipv6, loopback); + return _mm_movemask_epi8(cmp) == 0xffff; +#else + if (d->a6_64.c[0] != 0 || qFromBigEndian(d->a6_64.c[1]) != 1) return false; - for (int i = 0; i < 15; i++) - if (d->a6[i] != 0) - return false; +#endif return true; } return false; diff --git a/tests/auto/network/kernel/qhostaddress/tst_qhostaddress.cpp b/tests/auto/network/kernel/qhostaddress/tst_qhostaddress.cpp index b644372dab..8069865d93 100644 --- a/tests/auto/network/kernel/qhostaddress/tst_qhostaddress.cpp +++ b/tests/auto/network/kernel/qhostaddress/tst_qhostaddress.cpp @@ -642,10 +642,12 @@ void tst_QHostAddress::isLoopback_data() QTest::newRow("AnyIPv6") << QHostAddress(QHostAddress::AnyIPv6) << false; QTest::newRow("Broadcast") << QHostAddress(QHostAddress::Broadcast) << false; QTest::newRow("Null") << QHostAddress(QHostAddress::Null) << false; + QTest::newRow("ipv6-all-ffff") << QHostAddress("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff") << false; QTest::newRow("::ffff:127.0.0.1") << QHostAddress("::ffff:127.0.0.1") << true; QTest::newRow("::ffff:127.0.0.2") << QHostAddress("::ffff:127.0.0.2") << true; QTest::newRow("::ffff:127.3.2.1") << QHostAddress("::ffff:127.3.2.1") << true; + } void tst_QHostAddress::isLoopback()