From 673fa509fe0ac8262e53a12907e99d2a007fb5f2 Mon Sep 17 00:00:00 2001 From: Martin Jones Date: Thu, 19 Aug 2010 10:18:19 +1000 Subject: Document QML_DECLARE_TYPEINFO --- doc/src/declarative/qtdeclarative.qdoc | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/doc/src/declarative/qtdeclarative.qdoc b/doc/src/declarative/qtdeclarative.qdoc index b4f4c83..f163a66 100644 --- a/doc/src/declarative/qtdeclarative.qdoc +++ b/doc/src/declarative/qtdeclarative.qdoc @@ -59,6 +59,16 @@ Equivalent to Q_DECLARE_METATYPE(TYPE) and Q_DECLARE_METATYPE(QDeclarativeListProperty) */ +/*! + \macro QML_DECLARE_TYPEINFO(Type,Flags) + \relates QDeclarativeEngine + + Declares additional properties of a type. + + Current the only supported type info is \c QML_HAS_ATTACHED_PROPERTIES which + declares that the \c Type supports \l {Attached Properties}. +*/ + /*! \fn int qmlRegisterType(const char *uri, int versionMajor, int versionMinor, const char *qmlName) -- cgit v0.12 From 2abbc5fc400dfa8ad26397cc39f49f9b3a4304c9 Mon Sep 17 00:00:00 2001 From: Martin Jones Date: Thu, 19 Aug 2010 10:26:18 +1000 Subject: Make QML tests compile on OpenSolaris Task-number: QTBUG-13003 --- .../declarative/qdeclarativeecmascript/testtypes.h | 24 +++++++++++----------- .../tst_qdeclarativemetatype.cpp | 6 +++--- .../tst_qdeclarativetextedit.cpp | 2 +- .../tst_qdeclarativetextinput.cpp | 8 ++++---- 4 files changed, 20 insertions(+), 20 deletions(-) diff --git a/tests/auto/declarative/qdeclarativeecmascript/testtypes.h b/tests/auto/declarative/qdeclarativeecmascript/testtypes.h index 19bfd37..37d6dbd 100644 --- a/tests/auto/declarative/qdeclarativeecmascript/testtypes.h +++ b/tests/auto/declarative/qdeclarativeecmascript/testtypes.h @@ -604,62 +604,62 @@ class NumberAssignment : public QObject { Q_OBJECT public: - Q_PROPERTY(qreal test1 READ test1 WRITE setTest1); + Q_PROPERTY(qreal test1 READ test1 WRITE setTest1) qreal _test1; qreal test1() const { return _test1; } void setTest1(qreal v) { _test1 = v; } - Q_PROPERTY(qreal test2 READ test2 WRITE setTest2); + Q_PROPERTY(qreal test2 READ test2 WRITE setTest2) qreal _test2; qreal test2() const { return _test2; } void setTest2(qreal v) { _test2 = v; } - Q_PROPERTY(qreal test3 READ test3 WRITE setTest3); + Q_PROPERTY(qreal test3 READ test3 WRITE setTest3) qreal _test3; qreal test3() const { return _test3; } void setTest3(qreal v) { _test3 = v; } - Q_PROPERTY(qreal test4 READ test4 WRITE setTest4); + Q_PROPERTY(qreal test4 READ test4 WRITE setTest4) qreal _test4; qreal test4() const { return _test4; } void setTest4(qreal v) { _test4 = v; } - Q_PROPERTY(int test5 READ test5 WRITE setTest5); + Q_PROPERTY(int test5 READ test5 WRITE setTest5) int _test5; int test5() const { return _test5; } void setTest5(int v) { _test5 = v; } - Q_PROPERTY(int test6 READ test6 WRITE setTest6); + Q_PROPERTY(int test6 READ test6 WRITE setTest6) int _test6; int test6() const { return _test6; } void setTest6(int v) { _test6 = v; } - Q_PROPERTY(int test7 READ test7 WRITE setTest7); + Q_PROPERTY(int test7 READ test7 WRITE setTest7) int _test7; int test7() const { return _test7; } void setTest7(int v) { _test7 = v; } - Q_PROPERTY(int test8 READ test8 WRITE setTest8); + Q_PROPERTY(int test8 READ test8 WRITE setTest8) int _test8; int test8() const { return _test8; } void setTest8(int v) { _test8 = v; } - Q_PROPERTY(unsigned int test9 READ test9 WRITE setTest9); + Q_PROPERTY(unsigned int test9 READ test9 WRITE setTest9) unsigned int _test9; unsigned int test9() const { return _test9; } void setTest9(unsigned int v) { _test9 = v; } - Q_PROPERTY(unsigned int test10 READ test10 WRITE setTest10); + Q_PROPERTY(unsigned int test10 READ test10 WRITE setTest10) unsigned int _test10; unsigned int test10() const { return _test10; } void setTest10(unsigned int v) { _test10 = v; } - Q_PROPERTY(unsigned int test11 READ test11 WRITE setTest11); + Q_PROPERTY(unsigned int test11 READ test11 WRITE setTest11) unsigned int _test11; unsigned int test11() const { return _test11; } void setTest11(unsigned int v) { _test11 = v; } - Q_PROPERTY(unsigned int test12 READ test12 WRITE setTest12); + Q_PROPERTY(unsigned int test12 READ test12 WRITE setTest12) unsigned int _test12; unsigned int test12() const { return _test12; } void setTest12(unsigned int v) { _test12 = v; } diff --git a/tests/auto/declarative/qdeclarativemetatype/tst_qdeclarativemetatype.cpp b/tests/auto/declarative/qdeclarativemetatype/tst_qdeclarativemetatype.cpp index b06ad7c..862b7d2 100644 --- a/tests/auto/declarative/qdeclarativemetatype/tst_qdeclarativemetatype.cpp +++ b/tests/auto/declarative/qdeclarativemetatype/tst_qdeclarativemetatype.cpp @@ -313,7 +313,7 @@ void tst_qdeclarativemetatype::qmlParserStatusCast() QVERIFY(reinterpret_cast((QObject *)&t) != reinterpret_cast((QDeclarativeParserStatus *)&t)); QDeclarativeParserStatus *status = reinterpret_cast(reinterpret_cast((QObject *)&t) + cast); - QCOMPARE(status, &t); + QCOMPARE(status, (QDeclarativeParserStatus*)&t); } void tst_qdeclarativemetatype::qmlPropertyValueSourceCast() @@ -333,7 +333,7 @@ void tst_qdeclarativemetatype::qmlPropertyValueSourceCast() QVERIFY(reinterpret_cast((QObject *)&t) != reinterpret_cast((QDeclarativePropertyValueSource *)&t)); QDeclarativePropertyValueSource *source = reinterpret_cast(reinterpret_cast((QObject *)&t) + cast); - QCOMPARE(source, &t); + QCOMPARE(source, (QDeclarativePropertyValueSource*)&t); } void tst_qdeclarativemetatype::qmlPropertyValueInterceptorCast() @@ -353,7 +353,7 @@ void tst_qdeclarativemetatype::qmlPropertyValueInterceptorCast() QVERIFY(reinterpret_cast((QObject *)&t) != reinterpret_cast((QDeclarativePropertyValueInterceptor *)&t)); QDeclarativePropertyValueInterceptor *interceptor = reinterpret_cast(reinterpret_cast((QObject *)&t) + cast); - QCOMPARE(interceptor, &t); + QCOMPARE(interceptor, (QDeclarativePropertyValueInterceptor*)&t); } void tst_qdeclarativemetatype::isList() diff --git a/tests/auto/declarative/qdeclarativetextedit/tst_qdeclarativetextedit.cpp b/tests/auto/declarative/qdeclarativetextedit/tst_qdeclarativetextedit.cpp index 57a5e29..56a3121 100644 --- a/tests/auto/declarative/qdeclarativetextedit/tst_qdeclarativetextedit.cpp +++ b/tests/auto/declarative/qdeclarativetextedit/tst_qdeclarativetextedit.cpp @@ -1096,7 +1096,7 @@ void tst_qdeclarativetextedit::openInputPanelOnFocus() QApplication::processEvents(); QCOMPARE(ic.openInputPanelReceived, true); ic.openInputPanelReceived = false; - QCOMPARE(view.inputContext(), &ic); + QCOMPARE(view.inputContext(), (QInputContext*)&ic); QVERIFY(view.testAttribute(Qt::WA_InputMethodEnabled)); // input method should be disabled if focus diff --git a/tests/auto/declarative/qdeclarativetextinput/tst_qdeclarativetextinput.cpp b/tests/auto/declarative/qdeclarativetextinput/tst_qdeclarativetextinput.cpp index ca9009d..a5c2dda 100644 --- a/tests/auto/declarative/qdeclarativetextinput/tst_qdeclarativetextinput.cpp +++ b/tests/auto/declarative/qdeclarativetextinput/tst_qdeclarativetextinput.cpp @@ -193,7 +193,7 @@ void tst_qdeclarativetextinput::width() QDeclarativeTextInput *textinputObject = qobject_cast(textinputComponent.create()); QVERIFY(textinputObject != 0); - int delta = abs(int(textinputObject->width()) - metricWidth); + int delta = abs(int(int(textinputObject->width()) - metricWidth)); QVERIFY(delta <= 3.0); // As best as we can hope for cross-platform. delete textinputObject; @@ -450,7 +450,7 @@ void tst_qdeclarativetextinput::positionAt() QFontMetrics fm(textinputObject->font()); int pos = textinputObject->positionAt(textinputObject->width()/2); - int diff = abs(fm.width(textinputObject->text()) - (fm.width(textinputObject->text().left(pos))+textinputObject->width()/2)); + int diff = abs(int(fm.width(textinputObject->text()) - (fm.width(textinputObject->text().left(pos))+textinputObject->width()/2))); // some tollerance for different fonts. #ifdef Q_OS_LINUX @@ -462,7 +462,7 @@ void tst_qdeclarativetextinput::positionAt() // Check without autoscroll... textinputObject->setAutoScroll(false); pos = textinputObject->positionAt(textinputObject->width()/2); - diff = abs(fm.width(textinputObject->text().left(pos))-textinputObject->width()/2); + diff = abs(int(fm.width(textinputObject->text().left(pos))-textinputObject->width()/2)); // some tollerance for different fonts. #ifdef Q_OS_LINUX @@ -1022,7 +1022,7 @@ void tst_qdeclarativetextinput::openInputPanelOnFocus() QApplication::processEvents(); QCOMPARE(ic.openInputPanelReceived, true); ic.openInputPanelReceived = false; - QCOMPARE(view.inputContext(), &ic); + QCOMPARE(view.inputContext(), (QInputContext*)&ic); QVERIFY(view.testAttribute(Qt::WA_InputMethodEnabled)); // input method should be disabled if focus -- cgit v0.12 From 0303d8da8555ccbf28ee4dcdb5367302ed940534 Mon Sep 17 00:00:00 2001 From: Martin Jones Date: Mon, 23 Aug 2010 09:41:22 +1000 Subject: Enable mouse text selection in searchbox example Add selectByMouse: true Task-number: QTBUG-13024 --- examples/declarative/ui-components/searchbox/SearchBox.qml | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/declarative/ui-components/searchbox/SearchBox.qml b/examples/declarative/ui-components/searchbox/SearchBox.qml index 6d87837..8ef21b3 100644 --- a/examples/declarative/ui-components/searchbox/SearchBox.qml +++ b/examples/declarative/ui-components/searchbox/SearchBox.qml @@ -75,6 +75,7 @@ FocusScope { id: textInput anchors { left: parent.left; leftMargin: 8; right: clear.left; rightMargin: 8; verticalCenter: parent.verticalCenter } focus: true + selectByMouse: true } Image { -- cgit v0.12 From 1690ad91cc9e686e688aa7832a16cbf2c9336948 Mon Sep 17 00:00:00 2001 From: Martin Jones Date: Mon, 23 Aug 2010 10:32:02 +1000 Subject: Fix crach in synchronization of ListModel in WorkerThread. Task-number: QTBUG-13039 Reviewed-by: Aaron Kennedy --- .../util/qdeclarativelistmodelworkeragent.cpp | 16 ++++++++++++++-- .../util/qdeclarativelistmodelworkeragent_p.h | 4 ++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/declarative/util/qdeclarativelistmodelworkeragent.cpp b/src/declarative/util/qdeclarativelistmodelworkeragent.cpp index 534c923..498de6d 100644 --- a/src/declarative/util/qdeclarativelistmodelworkeragent.cpp +++ b/src/declarative/util/qdeclarativelistmodelworkeragent.cpp @@ -187,12 +187,17 @@ void QDeclarativeListModelWorkerAgent::sync() s->data = data; s->list = m_copy; data.changes.clear(); + + mutex.lock(); QCoreApplication::postEvent(this, s); + syncDone.wait(&mutex); + mutex.unlock(); } bool QDeclarativeListModelWorkerAgent::event(QEvent *e) { if (e->type() == QEvent::User) { + QMutexLocker locker(&mutex); Sync *s = static_cast(e); const QList &changes = s->data.changes; @@ -202,13 +207,18 @@ bool QDeclarativeListModelWorkerAgent::event(QEvent *e) FlatListModel *orig = m_orig->m_flat; FlatListModel *copy = s->list->m_flat; - if (!orig || !copy) + if (!orig || !copy) { + syncDone.wakeAll(); return QObject::event(e); - + } + orig->m_roles = copy->m_roles; orig->m_strings = copy->m_strings; orig->m_values = copy->m_values; + syncDone.wakeAll(); + locker.unlock(); + for (int ii = 0; ii < changes.count(); ++ii) { const Change &change = changes.at(ii); switch (change.type) { @@ -229,6 +239,8 @@ bool QDeclarativeListModelWorkerAgent::event(QEvent *e) if (cc) emit m_orig->countChanged(); + } else { + syncDone.wakeAll(); } } diff --git a/src/declarative/util/qdeclarativelistmodelworkeragent_p.h b/src/declarative/util/qdeclarativelistmodelworkeragent_p.h index 1622144..01da374 100644 --- a/src/declarative/util/qdeclarativelistmodelworkeragent_p.h +++ b/src/declarative/util/qdeclarativelistmodelworkeragent_p.h @@ -57,6 +57,8 @@ #include #include +#include +#include QT_BEGIN_HEADER @@ -142,6 +144,8 @@ private: QAtomicInt m_ref; QDeclarativeListModel *m_orig; QDeclarativeListModel *m_copy; + QMutex mutex; + QWaitCondition syncDone; }; QT_END_NAMESPACE -- cgit v0.12 From a2f83283a64460ca26530321f8eb64f3ddfe4c8b Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Mon, 23 Aug 2010 13:44:12 +0200 Subject: Fix assignment of a container included in the container itself Task-number: QTBUG-13079 Reviewed-by: Joao --- src/corelib/tools/qhash.h | 5 +- src/corelib/tools/qlinkedlist.h | 5 +- src/corelib/tools/qlist.h | 5 +- src/corelib/tools/qmap.h | 5 +- src/corelib/tools/qvector.h | 5 +- tests/auto/collections/tst_collections.cpp | 87 ++++++++++++++++++++++++++++++ 6 files changed, 102 insertions(+), 10 deletions(-) diff --git a/src/corelib/tools/qhash.h b/src/corelib/tools/qhash.h index 0777f06..c7e4bc1 100644 --- a/src/corelib/tools/qhash.h +++ b/src/corelib/tools/qhash.h @@ -589,10 +589,11 @@ template Q_INLINE_TEMPLATE QHash &QHash::operator=(const QHash &other) { if (d != other.d) { - other.d->ref.ref(); + QHashData *o = other.d; + o->ref.ref(); if (!d->ref.deref()) freeData(d); - d = other.d; + d = o; if (!d->sharable) detach_helper(); } diff --git a/src/corelib/tools/qlinkedlist.h b/src/corelib/tools/qlinkedlist.h index d145fe3..9b3efa3 100644 --- a/src/corelib/tools/qlinkedlist.h +++ b/src/corelib/tools/qlinkedlist.h @@ -312,10 +312,11 @@ template QLinkedList &QLinkedList::operator=(const QLinkedList &l) { if (d != l.d) { - l.d->ref.ref(); + QLinkedListData *o = l.d; + o->ref.ref(); if (!d->ref.deref()) free(d); - d = l.d; + d = o; if (!d->sharable) detach_helper(); } diff --git a/src/corelib/tools/qlist.h b/src/corelib/tools/qlist.h index 722744c..d843cbe 100644 --- a/src/corelib/tools/qlist.h +++ b/src/corelib/tools/qlist.h @@ -424,10 +424,11 @@ template Q_INLINE_TEMPLATE QList &QList::operator=(const QList &l) { if (d != l.d) { - l.d->ref.ref(); + QListData::Data *o = l.d; + o->ref.ref(); if (!d->ref.deref()) free(d); - d = l.d; + d = o; if (!d->sharable) detach_helper(); } diff --git a/src/corelib/tools/qmap.h b/src/corelib/tools/qmap.h index e4b73a1..1c2aad3 100644 --- a/src/corelib/tools/qmap.h +++ b/src/corelib/tools/qmap.h @@ -426,10 +426,11 @@ template Q_INLINE_TEMPLATE QMap &QMap::operator=(const QMap &other) { if (d != other.d) { - other.d->ref.ref(); + QMapData* o = other.d; + o->ref.ref(); if (!d->ref.deref()) freeData(d); - d = other.d; + d = o; if (!d->sharable) detach_helper(); } diff --git a/src/corelib/tools/qvector.h b/src/corelib/tools/qvector.h index c2e2485..b762b8a 100644 --- a/src/corelib/tools/qvector.h +++ b/src/corelib/tools/qvector.h @@ -377,10 +377,11 @@ inline void QVector::replace(int i, const T &t) template QVector &QVector::operator=(const QVector &v) { - v.d->ref.ref(); + QVectorData *o = v.d; + o->ref.ref(); if (!d->ref.deref()) free(p); - d = v.d; + d = o; if (!d->sharable) detach_helper(); return *this; diff --git a/tests/auto/collections/tst_collections.cpp b/tests/auto/collections/tst_collections.cpp index d092c34..8617e02 100644 --- a/tests/auto/collections/tst_collections.cpp +++ b/tests/auto/collections/tst_collections.cpp @@ -165,6 +165,7 @@ private slots: void containerTypedefs(); void forwardDeclared(); void alignment(); + void QTBUG13079_collectionInsideCollection(); }; struct LargeStatic { @@ -3589,5 +3590,91 @@ void tst_Collections::alignment() } #endif +#ifndef QT_NO_TEMPLATE_TEMPLATE_PARAMETERS + +template class C> +struct QTBUG13079_Node { + C children; + QString s; + + ~QTBUG13079_Node() { + children.begin(); //play with memory + } +}; +template class C> void QTBUG13079_collectionInsideCollectionImpl() +{ + C > nodeList; + nodeList << QTBUG13079_Node(); + nodeList.first().s = "parent"; + nodeList.first().children << QTBUG13079_Node(); + nodeList.first().children.first().s = "child"; + + nodeList = nodeList.first().children; + QCOMPARE(nodeList.first().s, QString::fromLatin1("child")); + + nodeList = nodeList.first().children; + QCOMPARE(nodeList.count(), 0); + nodeList << QTBUG13079_Node(); +} + +template class C> +struct QTBUG13079_NodeAssoc { + C children; + QString s; + + ~QTBUG13079_NodeAssoc() { + children.begin(); //play with memory + } +}; +template class C> void QTBUG13079_collectionInsideCollectionAssocImpl() +{ + C > nodeMap; + nodeMap[18] = QTBUG13079_NodeAssoc(); + nodeMap[18].s = "parent"; + nodeMap[18].children[12] = QTBUG13079_NodeAssoc(); + nodeMap[18].children[12].s = "child"; + + nodeMap = nodeMap[18].children; + QCOMPARE(nodeMap[12].s, QString::fromLatin1("child")); + + nodeMap = nodeMap[12].children; + QCOMPARE(nodeMap.count(), 0); + nodeMap[42] = QTBUG13079_NodeAssoc(); +} + + +static quint32 qHash(const QTBUG13079_Node &) +{ + return 0; +} + +bool operator==(const QTBUG13079_Node &a, const QTBUG13079_Node &b) +{ + return a.s == b.s && a.children == b.children; +} + +#endif + +void tst_Collections::QTBUG13079_collectionInsideCollection() +{ +#ifndef QT_NO_TEMPLATE_TEMPLATE_PARAMETERS + QTBUG13079_collectionInsideCollectionImpl(); + QTBUG13079_collectionInsideCollectionImpl(); + QTBUG13079_collectionInsideCollectionImpl(); + QTBUG13079_collectionInsideCollectionImpl(); + QTBUG13079_collectionInsideCollectionImpl(); + + { + QSet > nodeSet; + nodeSet << QTBUG13079_Node(); + nodeSet = nodeSet.begin()->children; + QCOMPARE(nodeSet.count(), 0); + } + + QTBUG13079_collectionInsideCollectionAssocImpl(); + QTBUG13079_collectionInsideCollectionAssocImpl(); +#endif +} + QTEST_APPLESS_MAIN(tst_Collections) #include "tst_collections.moc" -- cgit v0.12 From 6d8c9c3fddbe1fe0736a015164d5713d49a296d8 Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Mon, 23 Aug 2010 15:47:21 +0200 Subject: Fix assignment of a Q(Explicitly)SharedDataPointer included in the data itself Task-number: related to QTBUG-13079 Reviewed-by: Joao --- src/corelib/tools/qshareddata.h | 20 ++++++++------ tests/auto/collections/tst_collections.cpp | 42 ++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 8 deletions(-) diff --git a/src/corelib/tools/qshareddata.h b/src/corelib/tools/qshareddata.h index 7e9934d..6483c90 100644 --- a/src/corelib/tools/qshareddata.h +++ b/src/corelib/tools/qshareddata.h @@ -95,9 +95,10 @@ public: if (o.d != d) { if (o.d) o.d->ref.ref(); - if (d && !d->ref.deref()) - delete d; + T *old = d; d = o.d; + if (old && !old->ref.deref()) + delete old; } return *this; } @@ -105,9 +106,10 @@ public: if (o != d) { if (o) o->ref.ref(); - if (d && !d->ref.deref()) - delete d; + T *old = d; d = o; + if (old && !old->ref.deref()) + delete old; } return *this; } @@ -174,9 +176,10 @@ public: if (o.d != d) { if (o.d) o.d->ref.ref(); - if (d && !d->ref.deref()) - delete d; + T *old = d; d = o.d; + if (old && !old->ref.deref()) + delete old; } return *this; } @@ -184,9 +187,10 @@ public: if (o != d) { if (o) o->ref.ref(); - if (d && !d->ref.deref()) - delete d; + T *old = d; d = o; + if (old && !old->ref.deref()) + delete old; } return *this; } diff --git a/tests/auto/collections/tst_collections.cpp b/tests/auto/collections/tst_collections.cpp index 8617e02..2dc41aa 100644 --- a/tests/auto/collections/tst_collections.cpp +++ b/tests/auto/collections/tst_collections.cpp @@ -3653,6 +3653,44 @@ bool operator==(const QTBUG13079_Node &a, const QTBUG13079_Node &b) return a.s == b.s && a.children == b.children; } +template class C> +struct QTBUG13079_NodePtr : QSharedData { + C child; + QTBUG13079_NodePtr *next; + QString s; + + ~QTBUG13079_NodePtr() { + child.data(); //play with memory + next = 0; + } +}; +template class C> void QTBUG13079_collectionInsidePtrImpl() +{ + typedef C > Ptr; + { + Ptr nodePtr; + nodePtr = Ptr(new QTBUG13079_NodePtr()); + nodePtr->s = "parent"; + nodePtr->child = Ptr(new QTBUG13079_NodePtr()); + nodePtr->child->s = "child"; + nodePtr = nodePtr->child; + QCOMPARE(nodePtr->s, QString::fromLatin1("child")); + nodePtr = nodePtr->child; + QVERIFY(!nodePtr); + } + { + Ptr nodePtr; + nodePtr = Ptr(new QTBUG13079_NodePtr()); + nodePtr->s = "parent"; + nodePtr->next = new QTBUG13079_NodePtr(); + nodePtr->next->s = "next"; + nodePtr = Ptr(nodePtr->next); + QCOMPARE(nodePtr->s, QString::fromLatin1("next")); + nodePtr = Ptr(nodePtr->next); + QVERIFY(!nodePtr); + } +} + #endif void tst_Collections::QTBUG13079_collectionInsideCollection() @@ -3673,6 +3711,10 @@ void tst_Collections::QTBUG13079_collectionInsideCollection() QTBUG13079_collectionInsideCollectionAssocImpl(); QTBUG13079_collectionInsideCollectionAssocImpl(); + + QTBUG13079_collectionInsidePtrImpl(); + QTBUG13079_collectionInsidePtrImpl(); + QTBUG13079_collectionInsidePtrImpl(); #endif } -- cgit v0.12 From 0d2e88f417275a85b4e22a274fa04bc80742382e Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Fri, 20 Aug 2010 12:26:06 +1000 Subject: QDeclarativeVisualItemModel code cleanup. Remove unused function. Set abstract item model to 0 after disconnecting, in line with the other model types. Reviewed-by: Martin Jones --- .../graphicsitems/qdeclarativevisualitemmodel.cpp | 47 +--------------------- .../graphicsitems/qdeclarativevisualitemmodel_p.h | 3 -- 2 files changed, 1 insertion(+), 49 deletions(-) diff --git a/src/declarative/graphicsitems/qdeclarativevisualitemmodel.cpp b/src/declarative/graphicsitems/qdeclarativevisualitemmodel.cpp index 764676a..50a0a33 100644 --- a/src/declarative/graphicsitems/qdeclarativevisualitemmodel.cpp +++ b/src/declarative/graphicsitems/qdeclarativevisualitemmodel.cpp @@ -238,20 +238,6 @@ QString QDeclarativeVisualItemModel::stringValue(int index, const QString &name) return QDeclarativeEngine::contextForObject(d->children.at(index).item)->contextProperty(name).toString(); } -QVariant QDeclarativeVisualItemModel::evaluate(int index, const QString &expression, QObject *objectContext) -{ - Q_D(QDeclarativeVisualItemModel); - if (index < 0 || index >= d->children.count()) - return QVariant(); - QDeclarativeContext *ccontext = qmlContext(this); - QDeclarativeContext *ctxt = new QDeclarativeContext(ccontext); - ctxt->setContextObject(d->children.at(index).item); - QDeclarativeExpression e(ctxt, objectContext, expression); - QVariant value = e.evaluate(); - delete ctxt; - return value; -} - int QDeclarativeVisualItemModel::indexOf(QDeclarativeItem *item, QObject *) const { Q_D(const QDeclarativeVisualItemModel); @@ -728,6 +714,7 @@ void QDeclarativeVisualDataModel::setModel(const QVariant &model) QObject::disconnect(d->m_abstractItemModel, SIGNAL(rowsMoved(const QModelIndex&,int,int,const QModelIndex&,int)), this, SLOT(_q_rowsMoved(const QModelIndex&,int,int,const QModelIndex&,int))); QObject::disconnect(d->m_abstractItemModel, SIGNAL(modelReset()), this, SLOT(_q_modelReset())); + d->m_abstractItemModel = 0; } else if (d->m_visualItemModel) { QObject::disconnect(d->m_visualItemModel, SIGNAL(itemsInserted(int,int)), this, SIGNAL(itemsInserted(int,int))); @@ -1167,38 +1154,6 @@ QString QDeclarativeVisualDataModel::stringValue(int index, const QString &name) return val; } -QVariant QDeclarativeVisualDataModel::evaluate(int index, const QString &expression, QObject *objectContext) -{ - Q_D(QDeclarativeVisualDataModel); - if (d->m_visualItemModel) - return d->m_visualItemModel->evaluate(index, expression, objectContext); - - if ((!d->m_listModelInterface && !d->m_abstractItemModel) || !d->m_delegate) - return QVariant(); - - QVariant value; - QObject *nobj = d->m_cache.item(index); - if (nobj) { - QDeclarativeItem *item = qobject_cast(nobj); - if (item) { - QDeclarativeExpression e(qmlContext(item), objectContext, expression); - value = e.evaluate(); - } - } else { - QDeclarativeContext *ccontext = d->m_context; - if (!ccontext) ccontext = qmlContext(this); - QDeclarativeContext *ctxt = new QDeclarativeContext(ccontext); - QDeclarativeVisualDataModelData *data = new QDeclarativeVisualDataModelData(index, this); - ctxt->setContextObject(data); - QDeclarativeExpression e(ctxt, objectContext, expression); - value = e.evaluate(); - delete data; - delete ctxt; - } - - return value; -} - int QDeclarativeVisualDataModel::indexOf(QDeclarativeItem *item, QObject *) const { QVariant val = QDeclarativeEngine::contextForObject(item)->contextProperty(QLatin1String("index")); diff --git a/src/declarative/graphicsitems/qdeclarativevisualitemmodel_p.h b/src/declarative/graphicsitems/qdeclarativevisualitemmodel_p.h index d5c0de2..50d2c53 100644 --- a/src/declarative/graphicsitems/qdeclarativevisualitemmodel_p.h +++ b/src/declarative/graphicsitems/qdeclarativevisualitemmodel_p.h @@ -79,7 +79,6 @@ public: virtual ReleaseFlags release(QDeclarativeItem *item) = 0; virtual bool completePending() const = 0; virtual void completeItem() = 0; - virtual QVariant evaluate(int index, const QString &expression, QObject *objectContext) = 0; virtual QString stringValue(int, const QString &) { return QString(); } virtual int indexOf(QDeclarativeItem *item, QObject *objectContext) const = 0; @@ -122,7 +121,6 @@ public: virtual bool completePending() const; virtual void completeItem(); virtual QString stringValue(int index, const QString &role); - virtual QVariant evaluate(int index, const QString &expression, QObject *objectContext); virtual int indexOf(QDeclarativeItem *item, QObject *objectContext) const; @@ -177,7 +175,6 @@ public: bool completePending() const; void completeItem(); virtual QString stringValue(int index, const QString &role); - QVariant evaluate(int index, const QString &expression, QObject *objectContext); int indexOf(QDeclarativeItem *item, QObject *objectContext) const; -- cgit v0.12 From 35db70bf1c046f880861bbf4f48b8741ced405c4 Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Tue, 24 Aug 2010 10:25:13 +1000 Subject: Fix PathView when setting an empty model that is later filled. Task-number: QTBUG-13017 Reviewed-by: Martin Jones --- .../graphicsitems/qdeclarativepathview.cpp | 3 ++- .../qdeclarativepathview/data/emptymodel.qml | 5 +++++ .../tst_qdeclarativepathview.cpp | 24 +++++++++++++++++++++- 3 files changed, 30 insertions(+), 2 deletions(-) create mode 100644 tests/auto/declarative/qdeclarativepathview/data/emptymodel.qml diff --git a/src/declarative/graphicsitems/qdeclarativepathview.cpp b/src/declarative/graphicsitems/qdeclarativepathview.cpp index 535fb90..4b97505 100644 --- a/src/declarative/graphicsitems/qdeclarativepathview.cpp +++ b/src/declarative/graphicsitems/qdeclarativepathview.cpp @@ -480,7 +480,8 @@ void QDeclarativePathView::setModel(const QVariant &model) connect(d->model, SIGNAL(modelReset()), this, SLOT(modelReset())); connect(d->model, SIGNAL(createdItem(int, QDeclarativeItem*)), this, SLOT(createdItem(int,QDeclarativeItem*))); } - d->offset = qmlMod(d->offset, qreal(d->model->count())); + if (d->model->count()) + d->offset = qmlMod(d->offset, qreal(d->model->count())); if (d->offset < 0) d->offset = d->model->count() + d->offset; d->regenerate(); diff --git a/tests/auto/declarative/qdeclarativepathview/data/emptymodel.qml b/tests/auto/declarative/qdeclarativepathview/data/emptymodel.qml new file mode 100644 index 0000000..177c405 --- /dev/null +++ b/tests/auto/declarative/qdeclarativepathview/data/emptymodel.qml @@ -0,0 +1,5 @@ +import Qt 4.7 + +PathView { + model: emptyModel +} diff --git a/tests/auto/declarative/qdeclarativepathview/tst_qdeclarativepathview.cpp b/tests/auto/declarative/qdeclarativepathview/tst_qdeclarativepathview.cpp index fdbb16d..e2ccfd2 100644 --- a/tests/auto/declarative/qdeclarativepathview/tst_qdeclarativepathview.cpp +++ b/tests/auto/declarative/qdeclarativepathview/tst_qdeclarativepathview.cpp @@ -84,7 +84,7 @@ private slots: void modelChanges(); void pathUpdateOnStartChanged(); void package(); - + void emptyModel(); private: QDeclarativeView *createView(); @@ -755,6 +755,28 @@ void tst_QDeclarativePathView::package() delete canvas; } +//QTBUG-13017 +void tst_QDeclarativePathView::emptyModel() +{ + QDeclarativeView *canvas = createView(); + + QStringListModel model; + + QDeclarativeContext *ctxt = canvas->rootContext(); + ctxt->setContextProperty("emptyModel", &model); + + canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/emptymodel.qml")); + qApp->processEvents(); + + QDeclarativePathView *pathview = qobject_cast(canvas->rootObject()); + QVERIFY(pathview != 0); + + QCOMPARE(pathview->offset(), qreal(0.0)); + + delete canvas; +} + + QDeclarativeView *tst_QDeclarativePathView::createView() { QDeclarativeView *canvas = new QDeclarativeView(0); -- cgit v0.12 From 0f32923c15739ad555e8915cba8afae9c05fd485 Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Tue, 24 Aug 2010 13:51:20 +1000 Subject: Use SpringAnimation in relevant examples again. --- examples/declarative/toys/clocks/content/Clock.qml | 6 +++--- examples/declarative/toys/tvtennis/tvtennis.qml | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/declarative/toys/clocks/content/Clock.qml b/examples/declarative/toys/clocks/content/Clock.qml index eaa14c6..765e8b8 100644 --- a/examples/declarative/toys/clocks/content/Clock.qml +++ b/examples/declarative/toys/clocks/content/Clock.qml @@ -77,7 +77,7 @@ Item { origin.x: 7.5; origin.y: 73; angle: (clock.hours * 30) + (clock.minutes * 0.5) Behavior on angle { - RotationAnimation{ direction: RotationAnimation.Clockwise } + SpringAnimation { spring: 2; damping: 0.2; modulus: 360 } } } } @@ -91,7 +91,7 @@ Item { origin.x: 6.5; origin.y: 83; angle: clock.minutes * 6 Behavior on angle { - RotationAnimation{ direction: RotationAnimation.Clockwise } + SpringAnimation { spring: 2; damping: 0.2; modulus: 360 } } } } @@ -105,7 +105,7 @@ Item { origin.x: 2.5; origin.y: 80; angle: clock.seconds * 6 Behavior on angle { - RotationAnimation{ direction: RotationAnimation.Clockwise } + SpringAnimation { spring: 2; damping: 0.2; modulus: 360 } } } } diff --git a/examples/declarative/toys/tvtennis/tvtennis.qml b/examples/declarative/toys/tvtennis/tvtennis.qml index 2e144ed..4080c87 100644 --- a/examples/declarative/toys/tvtennis/tvtennis.qml +++ b/examples/declarative/toys/tvtennis/tvtennis.qml @@ -87,14 +87,14 @@ Rectangle { color: "Lime" x: 2; width: 20; height: 90 y: ball.direction == 'left' ? ball.y - 45 : page.height/2 -45; - Behavior on y { SpringAnimation{ spring: 1; damping: .1; } } + Behavior on y { SpringAnimation{ velocity: 300 } } } Rectangle { id: rightBat color: "Lime" x: page.width - 22; width: 20; height: 90 y: ball.direction == 'right' ? ball.y - 45 : page.height/2 -45; - Behavior on y { SpringAnimation{ spring: 1; damping: .1; } } + Behavior on y { SpringAnimation{ velocity: 300 } } } // The rest, to make it look realistic, if neither ever scores... -- cgit v0.12 From 0f3d7560855dd83b63ee090ee74b8770163e806c Mon Sep 17 00:00:00 2001 From: Joona Petrell Date: Tue, 24 Aug 2010 14:13:25 +1000 Subject: Fix few declarative code issues discovered by static code analysis Task-number: Reviewed-by: Aaron Kennedy --- src/declarative/graphicsitems/qdeclarativelistview.cpp | 2 +- src/declarative/graphicsitems/qdeclarativetext.cpp | 2 +- src/declarative/qml/parser/qdeclarativejslexer.cpp | 2 +- src/declarative/qml/qdeclarativecompositetypemanager.cpp | 2 +- src/declarative/qml/qdeclarativeengine.cpp | 2 +- src/declarative/qml/qdeclarativeimport.cpp | 2 +- src/declarative/qml/qdeclarativescriptparser.cpp | 2 +- src/declarative/qml/qmetaobjectbuilder.cpp | 2 +- src/declarative/util/qdeclarativelistmodel.cpp | 4 ++-- src/declarative/util/qdeclarativestategroup.cpp | 4 ++-- 10 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/declarative/graphicsitems/qdeclarativelistview.cpp b/src/declarative/graphicsitems/qdeclarativelistview.cpp index ec1b6cf..2e2e08c 100644 --- a/src/declarative/graphicsitems/qdeclarativelistview.cpp +++ b/src/declarative/graphicsitems/qdeclarativelistview.cpp @@ -983,7 +983,7 @@ void QDeclarativeListViewPrivate::updateSections() void QDeclarativeListViewPrivate::updateCurrentSection() { if (!sectionCriteria || visibleItems.isEmpty()) { - currentSection = QString(); + currentSection.clear(); return; } int index = 0; diff --git a/src/declarative/graphicsitems/qdeclarativetext.cpp b/src/declarative/graphicsitems/qdeclarativetext.cpp index fcd112e..b96b43c 100644 --- a/src/declarative/graphicsitems/qdeclarativetext.cpp +++ b/src/declarative/graphicsitems/qdeclarativetext.cpp @@ -1218,7 +1218,7 @@ void QDeclarativeText::mousePressEvent(QGraphicsSceneMouseEvent *event) if (!d->richText || !d->doc || d->doc->documentLayout()->anchorAt(event->pos()).isEmpty()) { event->setAccepted(false); - d->activeLink = QString(); + d->activeLink.clear(); } else { d->activeLink = d->doc->documentLayout()->anchorAt(event->pos()); } diff --git a/src/declarative/qml/parser/qdeclarativejslexer.cpp b/src/declarative/qml/parser/qdeclarativejslexer.cpp index 65a6af2..cd08658 100644 --- a/src/declarative/qml/parser/qdeclarativejslexer.cpp +++ b/src/declarative/qml/parser/qdeclarativejslexer.cpp @@ -120,7 +120,7 @@ Lexer::~Lexer() void Lexer::setCode(const QString &c, int lineno) { - errmsg = QString(); + errmsg.clear(); yylineno = lineno; yycolumn = 1; restrKeyword = false; diff --git a/src/declarative/qml/qdeclarativecompositetypemanager.cpp b/src/declarative/qml/qdeclarativecompositetypemanager.cpp index 26b2a9b..2e77534 100644 --- a/src/declarative/qml/qdeclarativecompositetypemanager.cpp +++ b/src/declarative/qml/qdeclarativecompositetypemanager.cpp @@ -544,7 +544,7 @@ int QDeclarativeCompositeTypeManager::resolveTypes(QDeclarativeCompositeTypeData } - foreach (QDeclarativeScriptParser::Import imp, unit->data.imports()) { + foreach (const QDeclarativeScriptParser::Import &imp, unit->data.imports()) { QDeclarativeDirComponents qmldircomponentsnetwork; if (imp.type == QDeclarativeScriptParser::Import::Script) continue; diff --git a/src/declarative/qml/qdeclarativeengine.cpp b/src/declarative/qml/qdeclarativeengine.cpp index cedf9d5..4e45636 100644 --- a/src/declarative/qml/qdeclarativeengine.cpp +++ b/src/declarative/qml/qdeclarativeengine.cpp @@ -2079,7 +2079,7 @@ void QDeclarativeEnginePrivate::registerCompositeType(QDeclarativeCompiledData * QByteArray name = data->root->className(); QByteArray ptr = name + '*'; - QByteArray lst = "QDeclarativeListProperty<" + name + ">"; + QByteArray lst = "QDeclarativeListProperty<" + name + '>'; int ptr_type = QMetaType::registerType(ptr.constData(), voidptr_destructor, voidptr_constructor); diff --git a/src/declarative/qml/qdeclarativeimport.cpp b/src/declarative/qml/qdeclarativeimport.cpp index 8d81b34..5c21ebc 100644 --- a/src/declarative/qml/qdeclarativeimport.cpp +++ b/src/declarative/qml/qdeclarativeimport.cpp @@ -338,7 +338,7 @@ QString QDeclarativeImportsPrivate::resolvedUri(const QString &dir_arg, QDeclara qSort(paths.begin(), paths.end(), greaterThan); // Ensure subdirs preceed their parents. QString stableRelativePath = dir; - foreach( QString path, paths) { + foreach(const QString &path, paths) { if (dir.startsWith(path)) { stableRelativePath = dir.mid(path.length()+1); break; diff --git a/src/declarative/qml/qdeclarativescriptparser.cpp b/src/declarative/qml/qdeclarativescriptparser.cpp index 0657f49..0b3b35f 100644 --- a/src/declarative/qml/qdeclarativescriptparser.cpp +++ b/src/declarative/qml/qdeclarativescriptparser.cpp @@ -543,7 +543,7 @@ bool ProcessAST::visit(AST::UiPublicMember *node) QString typemodifier; if(node->typeModifier) typemodifier = node->typeModifier->asString(); - if (typemodifier == QString()) { + if (typemodifier.isEmpty()) { type = Object::DynamicProperty::Custom; } else if(typemodifier == QLatin1String("list")) { type = Object::DynamicProperty::CustomList; diff --git a/src/declarative/qml/qmetaobjectbuilder.cpp b/src/declarative/qml/qmetaobjectbuilder.cpp index 6e4d7b8..0954248 100644 --- a/src/declarative/qml/qmetaobjectbuilder.cpp +++ b/src/declarative/qml/qmetaobjectbuilder.cpp @@ -1142,7 +1142,7 @@ static QByteArray buildParameterNames if (!parameterNames.isEmpty()) { QByteArray names; bool first = true; - foreach (QByteArray name, parameterNames) { + foreach (const QByteArray &name, parameterNames) { if (first) first = false; else diff --git a/src/declarative/util/qdeclarativelistmodel.cpp b/src/declarative/util/qdeclarativelistmodel.cpp index 1f66f0f..0162beb 100644 --- a/src/declarative/util/qdeclarativelistmodel.cpp +++ b/src/declarative/util/qdeclarativelistmodel.cpp @@ -570,7 +570,7 @@ bool QDeclarativeListModelParser::compileProperty(const QDeclarativeCustomParser QList props = node.properties(); for(int jj = 0; jj < props.count(); ++jj) { const QDeclarativeCustomParserProperty &nodeProp = props.at(jj); - if (nodeProp.name() == "") { + if (nodeProp.name().isEmpty()) { error(nodeProp, QDeclarativeListModel::tr("ListElement: cannot contain nested elements")); return false; } @@ -658,7 +658,7 @@ QByteArray QDeclarativeListModelParser::compile(const QListcurrentState.isEmpty()) { QString cs = d->currentState; - d->currentState = QString(); + d->currentState.clear(); d->setCurrentStateInternal(cs, true); } } @@ -314,7 +314,7 @@ bool QDeclarativeStateGroupPrivate::updateAutoState() } } if (revert) { - bool rv = currentState != QString(); + bool rv = !currentState.isEmpty(); q->setState(QString()); return rv; } else { -- cgit v0.12 From 9d77ff2064be61d2fdf2c034b13ef75cc4905bb3 Mon Sep 17 00:00:00 2001 From: Aaron McCarthy Date: Tue, 24 Aug 2010 12:14:03 +1000 Subject: Fix race condition on bearer management initialisation. Defer initialisation and changing thread affinity until after the global static is constructed. Task-number: QTBUG-12686 --- src/network/bearer/qnetworkconfigmanager.cpp | 12 ++++++++++-- src/network/bearer/qnetworkconfigmanager_p.cpp | 10 +++++++--- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/network/bearer/qnetworkconfigmanager.cpp b/src/network/bearer/qnetworkconfigmanager.cpp index 102b347..65014a6 100644 --- a/src/network/bearer/qnetworkconfigmanager.cpp +++ b/src/network/bearer/qnetworkconfigmanager.cpp @@ -54,7 +54,15 @@ Q_GLOBAL_STATIC(QNetworkConfigurationManagerPrivate, connManager); QNetworkConfigurationManagerPrivate *qNetworkConfigurationManagerPrivate() { - return connManager(); + static bool initialized = false; + + QNetworkConfigurationManagerPrivate *m = connManager(); + if (!initialized) { + initialized = true; + m->updateConfigurations(); + } + + return m; } /*! @@ -178,7 +186,7 @@ QNetworkConfigurationManagerPrivate *qNetworkConfigurationManagerPrivate() QNetworkConfigurationManager::QNetworkConfigurationManager( QObject* parent ) : QObject(parent) { - QNetworkConfigurationManagerPrivate *priv = connManager(); + QNetworkConfigurationManagerPrivate *priv = qNetworkConfigurationManagerPrivate(); connect(priv, SIGNAL(configurationAdded(QNetworkConfiguration)), this, SIGNAL(configurationAdded(QNetworkConfiguration))); diff --git a/src/network/bearer/qnetworkconfigmanager_p.cpp b/src/network/bearer/qnetworkconfigmanager_p.cpp index dd174bf..d388920 100644 --- a/src/network/bearer/qnetworkconfigmanager_p.cpp +++ b/src/network/bearer/qnetworkconfigmanager_p.cpp @@ -64,9 +64,6 @@ QNetworkConfigurationManagerPrivate::QNetworkConfigurationManagerPrivate() { qRegisterMetaType("QNetworkConfiguration"); qRegisterMetaType("QNetworkConfigurationPrivatePointer"); - - moveToThread(QCoreApplicationPrivate::mainThread()); - updateConfigurations(); } QNetworkConfigurationManagerPrivate::~QNetworkConfigurationManagerPrivate() @@ -359,6 +356,13 @@ void QNetworkConfigurationManagerPrivate::updateConfigurations() if (sender()) return; + if (thread() != QCoreApplicationPrivate::mainThread()) { + if (thread() != QThread::currentThread()) + return; + + moveToThread(QCoreApplicationPrivate::mainThread()); + } + updating = false; #ifndef QT_NO_LIBRARY -- cgit v0.12 From fdd6436987a114521168f48b9b96013772af7d49 Mon Sep 17 00:00:00 2001 From: Joerg Bornemann Date: Tue, 24 Aug 2010 08:41:22 +0200 Subject: qmake vcxproj generator: fix bug when using CharacterSet=1 in .pro file Task-number: QTBUG-13080 Reviewed-by: Martin Petersson --- qmake/generators/win32/msvc_vcxproj.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/qmake/generators/win32/msvc_vcxproj.cpp b/qmake/generators/win32/msvc_vcxproj.cpp index f68a435..271d9ae 100644 --- a/qmake/generators/win32/msvc_vcxproj.cpp +++ b/qmake/generators/win32/msvc_vcxproj.cpp @@ -202,7 +202,6 @@ void VcxprojGenerator::initConfiguration() conf.CharacterSet = "NotSet"; break; } - conf.CharacterSet = charSet(temp.isEmpty() ? (short)charSetNotSet : temp.toShort()); } conf.DeleteExtensionsOnClean = project->first("DeleteExtensionsOnClean"); conf.ImportLibrary = conf.linker.ImportLibrary; -- cgit v0.12 From 409d41185e85f2eefe6bb4872c4dd3005bef8170 Mon Sep 17 00:00:00 2001 From: Joerg Bornemann Date: Tue, 24 Aug 2010 08:58:17 +0200 Subject: qmake vc[x]proj generators: support /MAP option without file name Task-number: QTBUG-13081 Reviewed-by: Martin Petersson --- qmake/generators/win32/msbuild_objectmodel.cpp | 3 ++- qmake/generators/win32/msvc_objectmodel.cpp | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/qmake/generators/win32/msbuild_objectmodel.cpp b/qmake/generators/win32/msbuild_objectmodel.cpp index 17c4d5a..2505056 100644 --- a/qmake/generators/win32/msbuild_objectmodel.cpp +++ b/qmake/generators/win32/msbuild_objectmodel.cpp @@ -1573,7 +1573,8 @@ bool VCXLinkerTool::parseOption(const char* option) break; case 0x0034160: // /MAP[:filename] GenerateMapFile = _True; - MapFileName = option+5; + if (option[4] == ':') + MapFileName = option+5; break; case 0x164e1ef: // /MAPINFO:{EXPORTS} if(*(option+9) == 'E') diff --git a/qmake/generators/win32/msvc_objectmodel.cpp b/qmake/generators/win32/msvc_objectmodel.cpp index 1e060a0..980e686 100644 --- a/qmake/generators/win32/msvc_objectmodel.cpp +++ b/qmake/generators/win32/msvc_objectmodel.cpp @@ -1430,7 +1430,8 @@ bool VCLinkerTool::parseOption(const char* option) break; case 0x0034160: // /MAP[:filename] GenerateMapFile = _True; - MapFileName = option+5; + if (option[4] == ':') + MapFileName = option+5; break; case 0x164e1ef: // /MAPINFO:{EXPORTS|LINES} if(*(option+9) == 'E') -- cgit v0.12 From 337f2562c5b3b5dc99f62b406f13021e502791e7 Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Tue, 24 Aug 2010 10:57:42 +0200 Subject: Fix tst_Collections::QTBUG13079_collectionInsideCollection the 'next' was not initialized --- tests/auto/collections/tst_collections.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/auto/collections/tst_collections.cpp b/tests/auto/collections/tst_collections.cpp index 2dc41aa..f81535e 100644 --- a/tests/auto/collections/tst_collections.cpp +++ b/tests/auto/collections/tst_collections.cpp @@ -3659,9 +3659,9 @@ struct QTBUG13079_NodePtr : QSharedData { QTBUG13079_NodePtr *next; QString s; + QTBUG13079_NodePtr() : next(0) {} ~QTBUG13079_NodePtr() { - child.data(); //play with memory - next = 0; + next = child.data(); //play with memory } }; template class C> void QTBUG13079_collectionInsidePtrImpl() -- cgit v0.12 From feb5677d0e077f8b527e3ff7c2f92dfb5c92c074 Mon Sep 17 00:00:00 2001 From: axis Date: Tue, 24 Aug 2010 11:51:39 +0200 Subject: Added an install target to runonphone. RevBy: Trust me --- tools/runonphone/runonphone.pro | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/runonphone/runonphone.pro b/tools/runonphone/runonphone.pro index 15dff51..7ff361c 100644 --- a/tools/runonphone/runonphone.pro +++ b/tools/runonphone/runonphone.pro @@ -31,4 +31,5 @@ else { SOURCES += serenum_stub.cpp } - +target.path=$$[QT_INSTALL_BINS] +INSTALLS += target -- cgit v0.12 From ae29cdf5cd319e447ef75b11ac1247375c6c8192 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Wed, 18 Aug 2010 16:17:55 +0200 Subject: Keep the scopeid that getaddrinfo(3) returns to us. Task-number: QTBUG-12608, QTBUG-12243 Reviewed-by: Markus Goetz --- src/network/kernel/qhostinfo_unix.cpp | 5 ++++- src/network/socket/qnativesocketengine_unix.cpp | 9 ++++++--- src/network/socket/qnativesocketengine_win.cpp | 1 + 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/network/kernel/qhostinfo_unix.cpp b/src/network/kernel/qhostinfo_unix.cpp index 3112dd6..9e3da61 100644 --- a/src/network/kernel/qhostinfo_unix.cpp +++ b/src/network/kernel/qhostinfo_unix.cpp @@ -247,7 +247,10 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName) #ifndef QT_NO_IPV6 else if (node->ai_family == AF_INET6) { QHostAddress addr; - addr.setAddress(((sockaddr_in6 *) node->ai_addr)->sin6_addr.s6_addr); + sockaddr_in6 *sa6 = (sockaddr_in6 *) node->ai_addr; + addr.setAddress(sa6->sin6_addr.s6_addr); + if (sa6->sin6_scope_id) + addr.setScopeId(QString::number(sa6->sin6_scope_id)); if (!addresses.contains(addr)) addresses.append(addr); } diff --git a/src/network/socket/qnativesocketengine_unix.cpp b/src/network/socket/qnativesocketengine_unix.cpp index fe28863..f6bfbac 100644 --- a/src/network/socket/qnativesocketengine_unix.cpp +++ b/src/network/socket/qnativesocketengine_unix.cpp @@ -352,10 +352,13 @@ bool QNativeSocketEnginePrivate::nativeConnect(const QHostAddress &addr, quint16 memset(&sockAddrIPv6, 0, sizeof(sockAddrIPv6)); sockAddrIPv6.sin6_family = AF_INET6; sockAddrIPv6.sin6_port = htons(port); + + QString scopeid = addr.scopeId(); + bool ok; + sockAddrIPv6.sin6_scope_id = scopeid.toInt(&ok); #ifndef QT_NO_IPV6IFNAME - sockAddrIPv6.sin6_scope_id = ::if_nametoindex(addr.scopeId().toLatin1().data()); -#else - sockAddrIPv6.sin6_scope_id = addr.scopeId().toInt(); + if (!ok) + sockAddrIPv6.sin6_scope_id = ::if_nametoindex(scopeid.toLatin1()); #endif Q_IPV6ADDR ip6 = addr.toIPv6Address(); memcpy(&sockAddrIPv6.sin6_addr.s6_addr, &ip6, sizeof(ip6)); diff --git a/src/network/socket/qnativesocketengine_win.cpp b/src/network/socket/qnativesocketengine_win.cpp index 8177b4f..477ef45 100644 --- a/src/network/socket/qnativesocketengine_win.cpp +++ b/src/network/socket/qnativesocketengine_win.cpp @@ -207,6 +207,7 @@ static inline void qt_socket_setPortAndAddress(SOCKET socketDescriptor, sockaddr if (address.protocol() == QAbstractSocket::IPv6Protocol) { memset(sockAddrIPv6, 0, sizeof(qt_sockaddr_in6)); sockAddrIPv6->sin6_family = AF_INET6; + sockAddrIPv6->sin6_scope_id = address.scopeId().toInt(); WSAHtons(socketDescriptor, port, &(sockAddrIPv6->sin6_port)); Q_IPV6ADDR tmp = address.toIPv6Address(); memcpy(&(sockAddrIPv6->sin6_addr.qt_s6_addr), &tmp, sizeof(tmp)); -- cgit v0.12 From aa442648396e1367d6236801c5e1ad36884e4a81 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Thu, 12 Aug 2010 11:17:58 +0200 Subject: Introduce a second compatibility build key to Qt. Some compilers are compatible with one another. In particular, the Intel CC on Unix systems is compatible with g++ on the same system. We should be saving the ABI "name" in the build key, not the compiler name, but it's too late for that. Choose "g++-{VERSION}" as the standard ABI name and make ICC support that. Reviewed-by: Bradley T. Hughes --- configure | 32 ++++++++++++++++++++++++++++++++ src/corelib/global/qlibraryinfo.cpp | 8 ++++++++ src/corelib/plugin/qlibrary.cpp | 5 ++++- 3 files changed, 44 insertions(+), 1 deletion(-) diff --git a/configure b/configure index 3230086..1221d62 100755 --- a/configure +++ b/configure @@ -7278,6 +7278,7 @@ fi # some compilers generate binary incompatible code between different versions, # so we need to generate a build key that is different between these compilers +COMPAT_COMPILER= case "$COMPILER" in g++*) # GNU C++ @@ -7311,6 +7312,22 @@ g++*) esac [ '!' -z "$COMPILER_VERSION" ] && COMPILER="g++-${COMPILER_VERSION}" ;; +icc*) + # The Intel CC compiler on Unix systems matches the ABI of the g++ + # that is found on PATH + COMPILER="icc" + COMPAT_COMPILER="g++-4" + case "`g++ -dumpversion` 2>/dev/null" in + 2.95.*) + COMPAT_COMPILER="g++-2.95.*" + ;; + 3.*) + COMPAT_COMPILER="g++-3.*" + ;; + *) + ;; + esac + ;; *) # ;; @@ -7453,9 +7470,20 @@ if [ "$QT_CROSS_COMPILE" = "no" ]; then QT_BUILD_KEY_COMPAT="$QT_BUILD_KEY_COMPAT $QT_NAMESPACE" fi fi + +# is this compiler compatible with some other "standard" build key +QT_BUILD_KEY_COMPAT_COMPILER= +if [ ! -z "$COMPAT_COMPILER" ]; then + QT_BUILD_KEY_COMPAT_COMPILER="$CFG_USER_BUILD_KEY $CFG_ARCH $TARGET_OPERATING_SYSTEM $COMPAT_COMPILER $BUILD_OPTIONS" + if [ -n "$QT_NAMESPACE" ]; then + QT_BUILD_KEY_COMPAT_COMPILER="$QT_BUILD_KEY_COMPAT_COMPILER $QT_NAMESPACE" + fi +fi + # strip out leading/trailing/extra whitespace QT_BUILD_KEY=`echo $QT_BUILD_KEY | sed -e "s, *, ,g" -e "s,^ *,," -e "s, *$,,"` QT_BUILD_KEY_COMPAT=`echo $QT_BUILD_KEY_COMPAT | sed -e "s, *, ,g" -e "s,^ *,," -e "s, *$,,"` +QT_BUILD_KEY_COMPAT_COMPILER=`echo $QT_BUILD_KEY_COMPAT_COMPILER | sed -e "s, *, ,g" -e "s,^ *,," -e "s, *$,,"` #------------------------------------------------------------------------------- # part of configuration information goes into qconfig.h @@ -7504,6 +7532,10 @@ if [ -n "$QT_BUILD_KEY_COMPAT" ]; then echo "#define QT_BUILD_KEY_COMPAT \"$QT_BUILD_KEY_COMPAT\"" \ >> "$outpath/src/corelib/global/qconfig.h.new" fi +if [ -n "$QT_BUILD_KEY_COMPAT_COMPILER" ]; then + echo "#define QT_BUILD_KEY_COMPAT2 \"$QT_BUILD_KEY_COMPAT_COMPILER\"" \ + >> "$outpath/src/corelib/global/qconfig.h.new" +fi echo "" >>"$outpath/src/corelib/global/qconfig.h.new" echo "#ifdef QT_BOOTSTRAPPED" >>"$outpath/src/corelib/global/qconfig.h.new" diff --git a/src/corelib/global/qlibraryinfo.cpp b/src/corelib/global/qlibraryinfo.cpp index ea7e2e4..7ebee3d 100644 --- a/src/corelib/global/qlibraryinfo.cpp +++ b/src/corelib/global/qlibraryinfo.cpp @@ -508,6 +508,14 @@ void qt_core_boilerplate() "Contact: Nokia Corporation (qt-info@nokia.com)\n" "\n" "Build key: " QT_BUILD_KEY "\n" + "Compat build key: " +#ifdef QT_BUILD_KEY_COMPAT + "| " QT_BUILD_KEY_COMPAT " " +#endif +#ifdef QT_BUILD_KEY_COMPAT2 + "| " QT_BUILD_KEY_COMPAT2 " " +#endif + "|\n" "Build date: %s\n" "Installation prefix: %s\n" "Library path: %s\n" diff --git a/src/corelib/plugin/qlibrary.cpp b/src/corelib/plugin/qlibrary.cpp index 0f99948..a9ae2ab 100644 --- a/src/corelib/plugin/qlibrary.cpp +++ b/src/corelib/plugin/qlibrary.cpp @@ -790,10 +790,13 @@ bool QLibraryPrivate::isPlugin(QSettings *settings) .arg(qt_version&0xff) .arg(debug ? QLatin1String("debug") : QLatin1String("release")); } else if (key != QT_BUILD_KEY + // we may have some compatibility keys, try them too: #ifdef QT_BUILD_KEY_COMPAT - // be sure to load plugins using an older but compatible build key && key != QT_BUILD_KEY_COMPAT #endif +#ifdef QT_BUILD_KEY_COMPAT2 + && key != QT_BUILD_KEY_COMPAT2 +#endif ) { if (qt_debug_component()) { qWarning("In %s:\n" -- cgit v0.12 From b46f40ac8998a98122b3d85a9fed6bf9f094edd4 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Wed, 11 Aug 2010 20:30:18 +0200 Subject: linux-icc can take -msse2, -msse3, etc. flags, so enable this as well Otherwise, we actually get compilation errors because configure detected that the compiler supports this, so QT_HAVE_SSSE3 is defined, but we then compile qimage_ssse3.cpp without -mssse3 (Among others) Reviewed-By: Benjamin Poulain --- src/gui/gui.pro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/gui.pro b/src/gui/gui.pro index 3943e26..13d2c77 100644 --- a/src/gui/gui.pro +++ b/src/gui/gui.pro @@ -99,7 +99,7 @@ neon:*-g++* { contains(QMAKE_MAC_XARCH, no) { DEFINES += QT_NO_MAC_XARCH } else { - win32-g++*|!win32:!*-icc* { + win32-g++*|!win32:!win32-icc*:!macx-icc* { mmx { mmx_compiler.commands = $$QMAKE_CXX -c -Winline -- cgit v0.12 From 8585a340712e901bfe8389c6b951ae7b548daeca Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Mon, 16 Aug 2010 13:12:45 +0200 Subject: Include the SSE4.2 intrinsics header Reviewed-By: Benjamin Poulain --- src/corelib/tools/qsimd_p.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/corelib/tools/qsimd_p.h b/src/corelib/tools/qsimd_p.h index a3148fb..2626657 100644 --- a/src/corelib/tools/qsimd_p.h +++ b/src/corelib/tools/qsimd_p.h @@ -85,6 +85,7 @@ QT_BEGIN_HEADER // SSE4.1 and SSE4.2 intrinsics #if (defined(QT_HAVE_SSE4_1) || defined(QT_HAVE_SSE4_2)) && (defined(__SSE4_1__) || defined(Q_CC_MSVC)) #include +#include #endif // AVX intrinsics -- cgit v0.12 From cb9fa64c9ff61027e34c29fd8dd638f1237b41a7 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Thu, 12 Aug 2010 11:17:13 +0200 Subject: Allow other compilers than GCC on Linux to have a boilerplate --- src/corelib/global/global.pri | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/corelib/global/global.pri b/src/corelib/global/global.pri index b916b4d..2505e72 100644 --- a/src/corelib/global/global.pri +++ b/src/corelib/global/global.pri @@ -19,7 +19,7 @@ INCLUDEPATH += $$QT_BUILD_TREE/src/corelib/global # Only used on platforms with CONFIG += precompile_header PRECOMPILED_HEADER = global/qt_pch.h -linux*-g++*:!static { +linux*:!static { QMAKE_LFLAGS += -Wl,-e,qt_core_boilerplate prog=$$quote(if (/program interpreter: (.*)]/) { print $1; }) DEFINES += ELF_INTERPRETER=\\\"$$system(readelf -l /bin/ls | perl -n -e \'$$prog\')\\\" -- cgit v0.12 From 06080c767602715861ca4f1e7406d7834f52f30e Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Thu, 12 Aug 2010 21:11:18 +0200 Subject: Add some quick benchmarks for QChar comparison --- tests/benchmarks/corelib/tools/qstring/main.cpp | 143 +++++++++++++++++++++++- 1 file changed, 142 insertions(+), 1 deletion(-) diff --git a/tests/benchmarks/corelib/tools/qstring/main.cpp b/tests/benchmarks/corelib/tools/qstring/main.cpp index 12826eb..ee7ce5c 100644 --- a/tests/benchmarks/corelib/tools/qstring/main.cpp +++ b/tests/benchmarks/corelib/tools/qstring/main.cpp @@ -40,7 +40,7 @@ ****************************************************************************/ #include #include -#include +#include #ifdef Q_OS_SYMBIAN // In Symbian OS test data is located in applications private dir @@ -48,12 +48,18 @@ #define SRCDIR "" #endif +#include + class tst_QString: public QObject { Q_OBJECT +public: + tst_QString(); private slots: void equals() const; void equals_data() const; + void equals2_data() const; + void equals2() const; void fromUtf8() const; }; @@ -67,6 +73,22 @@ void tst_QString::equals() const } } +static ushort databuffer[4096]; + +tst_QString::tst_QString() +{ + // populate databuffer with our seed, each byte 3 times in a row + // include the NUL! + static const char seed[] = "AAAAAAAAAEhlbGxvIFdvcmxkIAAAAAA="; + static const int repeat = 3; + int pos = 0; + for (ushort *p = databuffer; p < databuffer + (sizeof(databuffer) / sizeof(databuffer[0])); p += repeat) { + for (int j = 0; j < repeat; ++p, ++j) + *p = seed[pos]; + pos = (pos + 1) % sizeof(seed); + } +} + void tst_QString::equals_data() const { static const struct { @@ -126,6 +148,125 @@ void tst_QString::equals_data() const << QString::fromRawData(ptr + 1, 58) << QString::fromRawData(ptr + 3, 58); } +static bool equals2_memcmp_call(ushort *p1, ushort *p2, int len) +{ + return memcmp(p1, p2, len * 2) == 0; +} + +static bool equals2_bytewise(ushort *p1, ushort *p2, int len) +{ + uchar *b1 = (uchar *)p1; + uchar *b2 = (uchar *)p2; + len *= 2; + while (len--) + if (*b1++ != *b2++) + return false; + return true; +} + +static bool equals2_shortwise(ushort *p1, ushort *p2, int len) +{ + register ushort * const end = p1 + len; + for ( ; p1 != end; ++p1, ++p2) + if (*p1 != *p2) + return false; + return true; +} + +void tst_QString::equals2_data() const +{ + QTest::addColumn("algorithm"); + QTest::newRow("selftest") << -1; + QTest::newRow("memcmp_call") << 0; + QTest::newRow("bytewise") << 1; + QTest::newRow("shortwise") << 2; +} + +void tst_QString::equals2() const +{ + static const short positions[] = { + 190, 1719, 2149, 1752, + 158, 244, 365, 1117, + 254, 265, 1047, 1785, + 1435, 552, 1476, 2030, + // 16 + 421, 1840, 2209, 232, + 1389, 907, 1500, 1479, + 1152, 541, 655, 1960, + 1642, 299, 740, 1995, + // 32 + 1946, 1407, 1272, 1946, + 1459, 1851, 1717, 1484, + 1761, 1630, 1377, 1675, + 629, 341, 661, 244 + // 48 + }; + // the length list must not contain 0 + static const int lens[] = { + 11, // 0 + 40, + 28, + 38, + 9, + 52, // 5 + 48, + 38, + 29, + 7, + 2, // 10 + 49, + 41, + 5, + 20, + 62 // 15 + }; + + typedef bool (* FuncPtr)(ushort *, ushort *, int); + static const FuncPtr func[] = { + equals2_memcmp_call, // 0 + equals2_bytewise, // 1 + equals2_shortwise, // 1 + 0 + }; + + QFETCH(int, algorithm); + if (algorithm == -1) { + for (uint pos1 = 0; pos1 < sizeof positions / sizeof positions[0]; ++pos1) + for (uint pos2 = 0; pos2 < (sizeof positions / sizeof positions[0]) - 32; ++pos2) + for (uint len = 0; len < sizeof lens / sizeof lens[0]; ++len) { + ushort *p1 = databuffer + positions[pos1]; + ushort *p2 = databuffer + positions[pos2]; + bool expected = memcmp(p1, p2, lens[len] * 2) == 0; + + for (uint algo = 0; algo < -1 + (sizeof func / sizeof func[0]); ++algo) { + bool result = (func[algo])(p1, p2, lens[len]); + if (expected != result) + qWarning().nospace() + << "algo=" << algo + << " pos1=" << positions[pos1] + << " pos2=" << positions[pos2] + << " len=" << lens[len] + << " failed (" << result << "!=" << expected + << "); strings were " + << QByteArray((char*)p1, lens[len]).toHex() + << " and " + << QByteArray((char*)p2, lens[len]).toHex(); + } + + } + return; + } + + QBENCHMARK { + for (uint pos1 = 0; pos1 < sizeof positions / sizeof positions[0]; ++pos1) + for (uint pos2 = 0; pos2 < (sizeof positions / sizeof positions[0]) - 32; ++pos2) + for (uint len = 0; len < sizeof lens / sizeof lens[0]; ++len) { + bool result = (func[algorithm])(databuffer + positions[pos1], databuffer + positions[pos2], lens[len]); + Q_UNUSED(result); + } + } +} + void tst_QString::fromUtf8() const { QFile file(SRCDIR "utf-8.txt"); -- cgit v0.12 From de76f8f32b84409a7053d5d95a3855b8590389e1 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Thu, 12 Aug 2010 21:12:22 +0200 Subject: Add a 4-byte comparison routine. This is a copy of qMemEquals from qstring.cpp --- tests/benchmarks/corelib/tools/qstring/main.cpp | 48 +++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/tests/benchmarks/corelib/tools/qstring/main.cpp b/tests/benchmarks/corelib/tools/qstring/main.cpp index ee7ce5c..9eb6294 100644 --- a/tests/benchmarks/corelib/tools/qstring/main.cpp +++ b/tests/benchmarks/corelib/tools/qstring/main.cpp @@ -173,6 +173,52 @@ static bool equals2_shortwise(ushort *p1, ushort *p2, int len) return true; } +static bool equals2_intwise(ushort *p1, ushort *p2, int length) +{ + register union { + const quint16 *w; + const quint32 *d; + quintptr value; + } sa, sb; + sa.w = p1; + sb.w = p2; + + // check alignment + if ((sa.value & 2) == (sb.value & 2)) { + // both addresses have the same alignment + if (sa.value & 2) { + // both addresses are not aligned to 4-bytes boundaries + // compare the first character + if (*sa.w != *sb.w) + return false; + --length; + ++sa.w; + ++sb.w; + + // now both addresses are 4-bytes aligned + } + + // both addresses are 4-bytes aligned + // do a fast 32-bit comparison + register const quint32 *e = sa.d + (length >> 1); + for ( ; sa.d != e; ++sa.d, ++sb.d) { + if (*sa.d != *sb.d) + return false; + } + + // do we have a tail? + return (length & 1) ? *sa.w == *sb.w : true; + } else { + // one of the addresses isn't 4-byte aligned but the other is + register const quint16 *e = sa.w + length; + for ( ; sa.w != e; ++sa.w, ++sb.w) { + if (*sa.w != *sb.w) + return false; + } + } + return true; +} + void tst_QString::equals2_data() const { QTest::addColumn("algorithm"); @@ -180,6 +226,7 @@ void tst_QString::equals2_data() const QTest::newRow("memcmp_call") << 0; QTest::newRow("bytewise") << 1; QTest::newRow("shortwise") << 2; + QTest::newRow("intwise") << 3; } void tst_QString::equals2() const @@ -226,6 +273,7 @@ void tst_QString::equals2() const equals2_memcmp_call, // 0 equals2_bytewise, // 1 equals2_shortwise, // 1 + equals2_intwise, // 3 0 }; -- cgit v0.12 From d8ad0812c7fdc2684ce7f09cc13b69f567e82031 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Thu, 12 Aug 2010 21:14:00 +0200 Subject: Add a benchmark for SSE2 comparison. This function uses unaligned loads. I'll try to write one with aligned loads later. --- tests/benchmarks/corelib/tools/qstring/main.cpp | 27 ++++++++++++++++++++++ tests/benchmarks/corelib/tools/qstring/qstring.pro | 1 + 2 files changed, 28 insertions(+) diff --git a/tests/benchmarks/corelib/tools/qstring/main.cpp b/tests/benchmarks/corelib/tools/qstring/main.cpp index 9eb6294..5210034 100644 --- a/tests/benchmarks/corelib/tools/qstring/main.cpp +++ b/tests/benchmarks/corelib/tools/qstring/main.cpp @@ -219,6 +219,27 @@ static bool equals2_intwise(ushort *p1, ushort *p2, int length) return true; } +#ifdef __SSE2__ +static bool equals2_sse2(ushort *p1, ushort *p2, int len) +{ + if (len > 8) { + while (len > 8) { + __m128i q1 = _mm_loadu_si128((__m128i *)p1); + __m128i q2 = _mm_loadu_si128((__m128i *)p2); + __m128i cmp = _mm_cmpeq_epi16(q1, q2); + if (ushort(_mm_movemask_epi8(cmp)) != 0xffff) + return false; + + len -= 8; + p1 += 8; + p2 += 8; + } + } + + return equals2_shortwise(p1, p2, len); +} +#endif + void tst_QString::equals2_data() const { QTest::addColumn("algorithm"); @@ -227,6 +248,9 @@ void tst_QString::equals2_data() const QTest::newRow("bytewise") << 1; QTest::newRow("shortwise") << 2; QTest::newRow("intwise") << 3; +#ifdef __SSE2__ + QTest::newRow("sse2") << 4; +#endif } void tst_QString::equals2() const @@ -274,6 +298,9 @@ void tst_QString::equals2() const equals2_bytewise, // 1 equals2_shortwise, // 1 equals2_intwise, // 3 +#ifdef __SSE2__ + equals2_sse2, // 4 +#endif 0 }; diff --git a/tests/benchmarks/corelib/tools/qstring/qstring.pro b/tests/benchmarks/corelib/tools/qstring/qstring.pro index fa4310e..388e3c2 100644 --- a/tests/benchmarks/corelib/tools/qstring/qstring.pro +++ b/tests/benchmarks/corelib/tools/qstring/qstring.pro @@ -14,3 +14,4 @@ wince*:{ DEFINES += SRCDIR=\\\"$$PWD/\\\" } +sse2:QMAKE_CXXFLAGS += -msse2 -- cgit v0.12 From 531a8f198c152e1135db103f22bab648a314926e Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Thu, 12 Aug 2010 21:18:49 +0200 Subject: Add an SSE2 comparison with prolog The prolog tries to align p1 to a multiple of 16, so as to run aligned loads, which are faster. Unfortunately, my tests so far indicate that the prolog ends up taking longer than the benefit of having aligned loads. --- tests/benchmarks/corelib/tools/qstring/main.cpp | 38 +++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/tests/benchmarks/corelib/tools/qstring/main.cpp b/tests/benchmarks/corelib/tools/qstring/main.cpp index 5210034..4e5d1c0 100644 --- a/tests/benchmarks/corelib/tools/qstring/main.cpp +++ b/tests/benchmarks/corelib/tools/qstring/main.cpp @@ -238,6 +238,42 @@ static bool equals2_sse2(ushort *p1, ushort *p2, int len) return equals2_shortwise(p1, p2, len); } + +static inline +#ifdef Q_CC_GNU +__attribute__((always_inline)) +#endif +bool prolog_align(ushort *&p1, ushort *&p2, int &len) +{ + const ushort *end = (ushort*) ((quintptr(p1) + 15) & ~15); + if (end > p1 + len) + end = p1 + len; + for ( ; p1 != end; ++p1, ++p2, --len) + if (*p1 != *p2) + return false; + return true; +} + +static bool equals2_sse2_aligning(ushort *p1, ushort *p2, int len) +{ + if (len > 8) { + if (!prolog_align(p1, p2, len)) + return false; + while (len > 8) { + __m128i q1 = _mm_load_si128((__m128i *)p1); + __m128i q2 = _mm_loadu_si128((__m128i *)p2); + __m128i cmp = _mm_cmpeq_epi16(q1, q2); + if (ushort(_mm_movemask_epi8(cmp)) != 0xffff) + return false; + + len -= 8; + p1 += 8; + p2 += 8; + } + } + + return equals2_shortwise(p1, p2, len); +} #endif void tst_QString::equals2_data() const @@ -250,6 +286,7 @@ void tst_QString::equals2_data() const QTest::newRow("intwise") << 3; #ifdef __SSE2__ QTest::newRow("sse2") << 4; + QTest::newRow("sse2_aligning") << 5; #endif } @@ -300,6 +337,7 @@ void tst_QString::equals2() const equals2_intwise, // 3 #ifdef __SSE2__ equals2_sse2, // 4 + equals2_sse2_aligning, // 5 #endif 0 }; -- cgit v0.12 From 7790cf5b2922a7adf684dc0b7cd0fc1583c0684a Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Thu, 12 Aug 2010 23:12:21 +0200 Subject: Add an SSSE3 version that uses palignr to align. Instead of using a non-SIMD method for aligning, we instead load more bytes from p1 and use the PALIGNR instruction to realign to what we want. The result is that it's bit slower than the non-SIMD comparison, due to the complexity. For strings over 8 QChars wide, it's only slightly worse than the non-SIMD comparison. --- tests/benchmarks/corelib/tools/qstring/main.cpp | 110 +++++++++++++++++++++ tests/benchmarks/corelib/tools/qstring/qstring.pro | 3 +- 2 files changed, 112 insertions(+), 1 deletion(-) diff --git a/tests/benchmarks/corelib/tools/qstring/main.cpp b/tests/benchmarks/corelib/tools/qstring/main.cpp index 4e5d1c0..e1800c0 100644 --- a/tests/benchmarks/corelib/tools/qstring/main.cpp +++ b/tests/benchmarks/corelib/tools/qstring/main.cpp @@ -274,6 +274,110 @@ static bool equals2_sse2_aligning(ushort *p1, ushort *p2, int len) return equals2_shortwise(p1, p2, len); } + +template static inline bool equals2_ssse3_alignr(__m128i *m1, __m128i *m2, int len) +{ + __m128i lower = _mm_load_si128(m1); + while (len > 8) { + __m128i upper = _mm_load_si128(m1 + 1); + __m128i correct; + correct = _mm_alignr_epi8(upper, lower, N); + + __m128i q2 = _mm_loadu_si128(m2); + __m128i cmp = _mm_cmpeq_epi16(correct, q2); + if (ushort(_mm_movemask_epi8(cmp)) != 0xffff) + return false; + + len -= 8; + ++m2; + ++m1; + lower = upper; + } + + // tail + return len == 0 || equals2_shortwise((ushort *)m1 + N / 2, (ushort*)m2, len); +} + +static inline bool equals2_ssse3_aligned(__m128i *m1, __m128i *m2, int len) +{ + while (len > 8) { + __m128i q2 = _mm_loadu_si128(m2); + __m128i cmp = _mm_cmpeq_epi16(*m1, q2); + if (ushort(_mm_movemask_epi8(cmp)) != 0xffff) + return false; + + len -= 8; + ++m1; + ++m2; + } + return len == 0 || equals2_shortwise((ushort *)m1, (ushort *)m2, len); +} + +//#ifdef __SSSE3__ +static bool equals2_ssse3(ushort *p1, ushort *p2, int len) +{ + // p1 & 0xf can be: + // 0, 2, 4, 6, 8, 10, 12, 14 + // If it's 0, we're aligned + // If it's not, then we're interested in the 16 - (p1 & 0xf) bytes only + + if (len > 8) { + // find the last aligned position below the p1 memory + __m128i *m1 = (__m128i *)(quintptr(p1) & ~0xf); + __m128i *m2 = (__m128i *)p2; + uchar diff = quintptr(p1) - quintptr(m1); + + // diff contains the number of extra bytes + if (diff < 8) { + if (diff < 4) { + if (diff == 0) + return equals2_ssse3_aligned(m1, m2, len); + else // diff == 2 + return equals2_ssse3_alignr<2>(m1, m2, len); + } else { + if (diff == 4) + return equals2_ssse3_alignr<4>(m1, m2, len); + else // diff == 6 + return equals2_ssse3_alignr<6>(m1, m2, len); + } + } else { + if (diff < 12) { + if (diff == 8) + return equals2_ssse3_alignr<8>(m1, m2, len); + else // diff == 10 + return equals2_ssse3_alignr<10>(m1, m2, len); + } else { + if (diff == 12) + return equals2_ssse3_alignr<12>(m1, m2, len); + else // diff == 14 + return equals2_ssse3_alignr<14>(m1, m2, len); + } + } + +// switch (diff) { +// case 0: +// return equals2_ssse3_aligned(m1, m2, len); +// case 2: +// return equals2_ssse3_alignr<2>(m1, m2, len); +// case 4: +// return equals2_ssse3_alignr<4>(m1, m2, len); +// case 6: +// return equals2_ssse3_alignr<6>(m1, m2, len); +// case 8: +// return equals2_ssse3_alignr<8>(m1, m2, len); +// case 10: +// return equals2_ssse3_alignr<10>(m1, m2, len); +// case 12: +// return equals2_ssse3_alignr<12>(m1, m2, len); +// case 14: +// return equals2_ssse3_alignr<14>(m1, m2, len); +// } + } + + // tail + return equals2_shortwise(p1, p2, len); +} +//#endif #endif void tst_QString::equals2_data() const @@ -287,6 +391,9 @@ void tst_QString::equals2_data() const #ifdef __SSE2__ QTest::newRow("sse2") << 4; QTest::newRow("sse2_aligning") << 5; +#ifdef __SSSE3__ + QTest::newRow("ssse3") << 6; +#endif #endif } @@ -338,6 +445,9 @@ void tst_QString::equals2() const #ifdef __SSE2__ equals2_sse2, // 4 equals2_sse2_aligning, // 5 +#ifdef __SSSE3__ + equals2_ssse3, // 6 +#endif #endif 0 }; diff --git a/tests/benchmarks/corelib/tools/qstring/qstring.pro b/tests/benchmarks/corelib/tools/qstring/qstring.pro index 388e3c2..bc6254c 100644 --- a/tests/benchmarks/corelib/tools/qstring/qstring.pro +++ b/tests/benchmarks/corelib/tools/qstring/qstring.pro @@ -14,4 +14,5 @@ wince*:{ DEFINES += SRCDIR=\\\"$$PWD/\\\" } -sse2:QMAKE_CXXFLAGS += -msse2 +ssse3:QMAKE_FLAGS += -mssse3 +else:sse2:QMAKE_CXXFLAGS += -msse2 -- cgit v0.12 From a9dae34157aeef00512bea49f11a8dd1895f676b Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Fri, 13 Aug 2010 00:59:27 +0200 Subject: Add an SSE4.2 version of the string comparison It's currently slightly worse than SSE2 with prolog aligning (i.e., it's no good) --- tests/benchmarks/corelib/tools/qstring/main.cpp | 41 ++++++++++++++++++++++ tests/benchmarks/corelib/tools/qstring/qstring.pro | 3 +- 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/tests/benchmarks/corelib/tools/qstring/main.cpp b/tests/benchmarks/corelib/tools/qstring/main.cpp index e1800c0..1c55f82 100644 --- a/tests/benchmarks/corelib/tools/qstring/main.cpp +++ b/tests/benchmarks/corelib/tools/qstring/main.cpp @@ -378,6 +378,41 @@ static bool equals2_ssse3(ushort *p1, ushort *p2, int len) return equals2_shortwise(p1, p2, len); } //#endif + +//#ifdef __SSE4_1__ +static bool equals2_sse4(ushort *p1, ushort *p2, int len) +{ + // We use the pcmpestrm instruction searching for differences (negative polarity) + // it will reset CF if it's all equal + // it will reset OF if the first char is equal + // it will set ZF & SF if the length is less than 8 (which means we've done the last operation) + // the three possible conditions are: + // difference found: CF = 1 + // all equal, not finished: CF = ZF = SF = 0 + // all equal, finished: CF = 0, ZF = SF = 1 + len += 8; + asm ( + "0:\n\t" + "movdqu (%[p1]), %%xmm0\n\t" // load 8 ushorts + "movdqu (%[p2]), %%xmm1\n\t" + "addl $16, %[p2]\n\t" + "addl $16, %[p1]\n\t" + "subl $8, %[len]\n\t" + "movl %[len], %%edx\n\t" + "pcmpestrm %[mode], %%xmm1, %%xmm0\n\t" + "ja 0b\n\t" + "1:\n\t" + "mov $0, %[len]\n\t" + "setnc %%al\n\t" + : [len] "+a" (len) + : [p1] "r" (p1), + [p2] "r" (p2), + [mode] "K" (_SIDD_UWORD_OPS | _SIDD_CMP_EQUAL_EACH | _SIDD_NEGATIVE_POLARITY | _SIDD_UNIT_MASK) + : "%edx", "%xmm0", "%xmm1" + ); + return len; +} +//#endif #endif void tst_QString::equals2_data() const @@ -393,6 +428,9 @@ void tst_QString::equals2_data() const QTest::newRow("sse2_aligning") << 5; #ifdef __SSSE3__ QTest::newRow("ssse3") << 6; +#ifdef __SSE4_1__ + QTest::newRow("sse4.2") << 7; +#endif #endif #endif } @@ -447,6 +485,9 @@ void tst_QString::equals2() const equals2_sse2_aligning, // 5 #ifdef __SSSE3__ equals2_ssse3, // 6 +#ifdef __SSE4_1__ + equals2_sse4, // 7 +#endif #endif #endif 0 diff --git a/tests/benchmarks/corelib/tools/qstring/qstring.pro b/tests/benchmarks/corelib/tools/qstring/qstring.pro index bc6254c..44fb46b 100644 --- a/tests/benchmarks/corelib/tools/qstring/qstring.pro +++ b/tests/benchmarks/corelib/tools/qstring/qstring.pro @@ -14,5 +14,6 @@ wince*:{ DEFINES += SRCDIR=\\\"$$PWD/\\\" } -ssse3:QMAKE_FLAGS += -mssse3 +sse4:QMAKE_CXXFLAGS += -msse4 +else:ssse3:QMAKE_FLAGS += -mssse3 else:sse2:QMAKE_CXXFLAGS += -msse2 -- cgit v0.12 From ca9d0f597fe6212aa89fa2d6d45b27bae147d195 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Fri, 13 Aug 2010 01:37:47 +0200 Subject: Slightly better version that saves EBX in an XMM register --- tests/benchmarks/corelib/tools/qstring/main.cpp | 35 ++++++++++++++----------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/tests/benchmarks/corelib/tools/qstring/main.cpp b/tests/benchmarks/corelib/tools/qstring/main.cpp index 1c55f82..fb65f65 100644 --- a/tests/benchmarks/corelib/tools/qstring/main.cpp +++ b/tests/benchmarks/corelib/tools/qstring/main.cpp @@ -390,27 +390,32 @@ static bool equals2_sse4(ushort *p1, ushort *p2, int len) // difference found: CF = 1 // all equal, not finished: CF = ZF = SF = 0 // all equal, finished: CF = 0, ZF = SF = 1 - len += 8; + bool result; asm ( + "movd %%ebx, %%xmm1\n\t" + "sub %[p1], %[p2]\n\t" + "mov %[p1], %%ebx\n\t" + "sub $16, %%ebx\n\t" + "add $8, %[len]\n\t" "0:\n\t" - "movdqu (%[p1]), %%xmm0\n\t" // load 8 ushorts - "movdqu (%[p2]), %%xmm1\n\t" - "addl $16, %[p2]\n\t" - "addl $16, %[p1]\n\t" - "subl $8, %[len]\n\t" - "movl %[len], %%edx\n\t" - "pcmpestrm %[mode], %%xmm1, %%xmm0\n\t" + "add $16, %%ebx\n\t" + "sub $8, %[len]\n\t" + "movdqu (%%ebx), %%xmm0\n\t" + "mov %[len], %%edx\n\t" + "pcmpestrm %[mode], (%[p2],%%ebx), %%xmm0\n\t" "ja 0b\n\t" - "1:\n\t" - "mov $0, %[len]\n\t" + "1:\n\t" + "mov $0, %%eax\n\t" "setnc %%al\n\t" - : [len] "+a" (len) - : [p1] "r" (p1), + "movd %%xmm1, %%ebx\n\t" + : [result] "=a" (result) + : [len] "0" (len), + [p1] "d" (p1), [p2] "r" (p2), - [mode] "K" (_SIDD_UWORD_OPS | _SIDD_CMP_EQUAL_EACH | _SIDD_NEGATIVE_POLARITY | _SIDD_UNIT_MASK) - : "%edx", "%xmm0", "%xmm1" + [mode] "K" (_SIDD_UWORD_OPS | _SIDD_CMP_EQUAL_EACH | _SIDD_NEGATIVE_POLARITY) + : "%xmm0", "%xmm1" ); - return len; + return result; } //#endif #endif -- cgit v0.12 From 64a6ce5fb031f151994f77b9d9abea52bb9e00d3 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Tue, 17 Aug 2010 20:20:28 +0200 Subject: Add a script to generate real-world data from applications --- .../corelib/tools/qstring/generatelist.pl | 200 +++++++++++++++++++++ 1 file changed, 200 insertions(+) create mode 100644 tests/benchmarks/corelib/tools/qstring/generatelist.pl diff --git a/tests/benchmarks/corelib/tools/qstring/generatelist.pl b/tests/benchmarks/corelib/tools/qstring/generatelist.pl new file mode 100644 index 0000000..ed4c8eb --- /dev/null +++ b/tests/benchmarks/corelib/tools/qstring/generatelist.pl @@ -0,0 +1,200 @@ +#!/usr/bin/perl +## Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +## All rights reserved. +## Contact: Nokia Corporation (qt-info@nokia.com) +## +## This file is part of the QtCore module of the Qt Toolkit. +## +## $QT_BEGIN_LICENSE:LGPL$ +## No Commercial Usage +## This file contains pre-release code and may not be distributed. +## You may use this file in accordance with the terms and conditions +## contained in the Technology Preview License Agreement accompanying +## this package. +## +## GNU Lesser General Public License Usage +## Alternatively, this file may be used under the terms of the GNU Lesser +## General Public License version 2.1 as published by the Free Software +## Foundation and appearing in the file LICENSE.LGPL included in the +## packaging of this file. Please review the following information to +## ensure the GNU Lesser General Public License version 2.1 requirements +## will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +## +## In addition, as a special exception, Nokia gives you certain additional +## rights. These rights are described in the Nokia Qt LGPL Exception +## version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +## +## If you have questions regarding the use of this file, please contact +## Nokia at qt-info@nokia.com. +## +## +## +## +## +## +## +## +## $QT_END_LICENSE$ +# +# Parses a file (passed as argument) that contains a dump of pairs of +# strings and generates C source code including said data. +# +# The format of the file is: +# LEN = \n\n +# where: +# LEN the literal string "LEN" +# the length of the data, in 16-bit words +# the literal string "SAME" or "DIFF" +# the alignment or pointer value of the first data +# the alignment or pointer value of the second data +# the first data +# the second data +# \n newline +# +# The C code to write this data would be: +# fprintf(out, "LEN = %d %s %d %d\n", len, +# (p1 == p2) : "SAME" : "DIFF", +# (int)p1 & 0xfff, (int)p2 & 0xfff); +# fwrite(p1, 2, len, out); +# fwrite(p2, 2, len, out); +# fwrite("\n", 1, 1, out); + +sub printUshortArray($$$) { + $str = $_[0]; + $align = $_[1] & 0x1f; + $offset = $_[2]; + + die if ($align & 1) != 0; + $align /= 2; + + $len = (length $str) / 2; + $headpadding = $align & 0x7; + $tailpadding = 8 - (($len + $headpadding) & 0x7); + $multiplecachelines = ($align + $len) > 0x20; + + if ($multiplecachelines) { + # if this string crosses into a new cacheline, then + # replicate the result + $headpadding |= ($offset & ~0x1f); + $headpadding += 0x20 + if ($headpadding < $offset); + $headpadding -= $offset; + ++$cachelinecrosses; + } + for $i (1..$headpadding) { + print 65536-$i,","; + } + print "\n " if ($headpadding > 0); + print " " if ($headpadding == 0); + + for ($i = 0; $i < $len * 2; $i += 2) { + print " ", ord(substr($str, $i, 1)) + + ord(substr($str, $i + 1, 1)) * 256, + ","; + } + print "\n " if ($tailpadding > 0); + + for $i (1..$tailpadding) { + print 65536-$i, ","; + } + print " // ", $offset + $headpadding + $len + $tailpadding; + print "+" if $multiplecachelines; + + return ($offset + $headpadding, $offset + $headpadding + $len + $tailpadding); +} + +print "static const ushort stringCollectionData[] __attribute__((aligned(16))) = { \n"; +$count = 0; +$offset = 0; +$totalsize = 0; +$maxlen = 0; +$cachelinecrosses = 0; + +open IN, "<" . $ARGV[0]; +while (1) { + $line = readline(*IN); + last unless defined($line); + $line =~ /LEN = (\d+) (\w+) (\d+) (\d+)/; + $len = $1; + $data[$count]->{len} = $len; + $sameptr = $2; + $data[$count]->{align1} = $3 - 0; + $data[$count]->{align2} = $4 - 0; + + # statistics + $alignhistogram{$3 & 0xf}++; + $alignhistogram{$4 & 0xf}++; + $samealignments{$3 & 0xf}++ if ($3 & 0xf) == ($4 & 0xf); + + read IN, $a, $len * 2; + read IN, $b, $len * 2; + + ; # Eat the newline + + if ($len == 0) { + $data[$count]->{offset1} = $offset; + $data[$count]->{offset2} = $data[$count]->{offset1}; + ++$data[$count]->{offset2} if ($sameptr eq "DIFF"); + } else { + print " // #$count\n"; + print " "; + ($data[$count]->{offset1}, $offset) = + printUshortArray($a, $data[$count]->{align1}, $offset); + print "\n "; + die if ($offset & 0x7) != 0; + + if ($sameptr eq "DIFF") { + ($data[$count]->{offset2}, $offset) = + printUshortArray($b, $data[$count]->{align2}, $offset); + print "\n\n"; + } else { + $data[$count]->{offset2} = $data[$count]->{offset1}; + print "\n\n"; + } + } + ++$count; + + $totalsize += $len; + $maxlen = $len if $len > $maxlen; +} +print "\n};\n"; +close IN; + +print "static struct StringCollection\n"; +print "{\n"; +print " int len;\n"; +print " int offset1, offset2;\n"; +print " ushort align1, align2;\n"; +print "} stringCollection[] = {\n"; + +for $i (0..$count-1) { + print " {", + $data[$i]->{len}, ", ", + $data[$i]->{offset1}, ", ", + $data[$i]->{offset2}, ", ", + $data[$i]->{align1}, ", ", + $data[$i]->{align2}, + "}, // #$i\n"; + next if $data[$i]->{len} == 0; + die if (($data[$i]->{offset1} & 0x7) != ($data[$i]->{align1} & 0xf)/2); + die if (($data[$i]->{offset2} & 0x7) != ($data[$i]->{align2} & 0xf)/2); +} +print "};\n"; + +print "static const int stringCollectionCount = $count;\n"; +print "static const int stringCollectionMaxLen = $maxlen;\n"; +printf "// average comparison length: %.4f\n", ($totalsize * 1.0 / $count); +printf "// cache-line crosses: %d (%.1f%%)\n", + $cachelinecrosses, ($cachelinecrosses * 100.0 / $count / 2); + +print "// alignment histogram:\n"; +for $key (sort { $a <=> $b } keys(%alignhistogram)) { + $value = $alignhistogram{$key}; + $samealigned = $samealignments{$key}; + printf "// 0xXXX%x = %d (%.1f%%) strings, %d (%.1f%%) of which same-aligned\n", + $key, $value, $value * 100.0 / ($count*2), + $samealigned, $samealigned * 100.0 / $value; + $samealignedtotal += $samealigned; +} +printf "// total = %d (100%) strings, %d (%.1f%%) of which same-aligned\n", + $count * 2, $samealignedtotal, $samealignedtotal * 100 / $count / 2; -- cgit v0.12 From c58293407519e7413cb6493f831ef69cf2323030 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Tue, 17 Aug 2010 20:32:27 +0200 Subject: Major improvements to the comparison functions. Also use the real-world data that I collected. The resulting files are quite large, so I've added to Git only the smallest dump (apparently Teambuilder scanning the environment for "TEAMBUILDER="). --- tests/benchmarks/corelib/tools/qstring/data.cpp | 1283 +++++++++++++++++++++++ tests/benchmarks/corelib/tools/qstring/main.cpp | 675 ++++++++---- 2 files changed, 1770 insertions(+), 188 deletions(-) create mode 100644 tests/benchmarks/corelib/tools/qstring/data.cpp diff --git a/tests/benchmarks/corelib/tools/qstring/data.cpp b/tests/benchmarks/corelib/tools/qstring/data.cpp new file mode 100644 index 0000000..89f50d0 --- /dev/null +++ b/tests/benchmarks/corelib/tools/qstring/data.cpp @@ -0,0 +1,1283 @@ +static const ushort stringCollectionData[] __attribute__((aligned(16))) = { + // #0 + 65535, + 99, 111, 109, 112, 105, 108, 101, 114, 32, 118, 101, 114, 115, 105, 111, 110, 115, 47, + 65535,65534,65533,65532,65531, // 24 + 65535,65534,65533,65532,65531, + 99, 111, 109, 112, 105, 108, 101, 114, 32, 118, 101, 114, 115, 105, 111, 110, 115, 47, + 65535, // 48 + + // #1 + 65535,65534,65533,65532,65531, + 99, 111, 109, 112, 105, 108, 101, 114, 32, 118, 101, 114, 115, 105, 111, 110, 115, 47, + 65535, // 72 + 65535,65534,65533,65532,65531, + 67, 111, 109, 112, 105, 108, 101, 114, 32, 86, 101, 114, 115, 105, 111, 110, 115, 47, + 65535, // 96 + + // #2 + 65535, + 99, 111, 109, 112, 105, 108, 101, 114, 32, 116, 105, 109, 101, 115, 116, 97, 109, 112, 115, 47, + 65535,65534,65533, // 120 + 65535,65534,65533,65532,65531, + 99, 111, 109, 112, 105, 108, 101, 114, 32, 116, 105, 109, 101, 115, 116, 97, 109, 112, 115, 47, + 65535,65534,65533,65532,65531,65530,65529, // 152 + + // #3 + 65535,65534,65533,65532,65531, + 99, 111, 109, 112, 105, 108, 101, 114, 32, 116, 105, 109, 101, 115, 116, 97, 109, 112, 115, 47, + 65535,65534,65533,65532,65531,65530,65529, // 184 + 65535, + 67, 111, 109, 112, 105, 108, 101, 114, 32, 84, 105, 109, 101, 115, 116, 97, 109, 112, 115, 47, + 65535,65534,65533, // 208 + + // #4 + 65535,65534,65533,65532,65531,65530,65529,65528,65527,65526,65525,65524,65523,65522,65521,65520,65519, + 47, 118, 97, 114, 47, 116, 109, 112, 47, 116, 101, 97, 109, 98, 117, 105, 108, 100, 101, 114, 45, 116, 109, 97, 99, 105, 101, 105, 114, 47, 99, 108, 105, 101, 110, 116, 47, 99, 111, 109, 112, 105, 108, 101, 114, 115, 46, 99, 111, 110, 102, + 65535,65534,65533,65532, // 280+ + + + // #5 + 65535,65534,65533,65532,65531,65530,65529,65528,65527,65526,65525,65524,65523, + 47, 118, 97, 114, 47, 116, 109, 112, 47, 116, 101, 97, 109, 98, 117, 105, 108, 100, 101, 114, 45, 116, 109, 97, 99, 105, 101, 105, 114, 47, 99, 108, 105, 101, 110, 116, 47, 99, 111, 109, 112, 105, 108, 101, 114, 115, 46, 99, 111, 110, 102, + 65535,65534,65533,65532,65531,65530,65529,65528, // 352+ + 65535, + 47, 118, 97, 114, 47, 116, 109, 112, 47, 116, 101, 97, 109, 98, 117, 105, 108, 100, 101, 114, 45, 116, 109, 97, 99, 105, 101, 105, 114, 47, 99, 108, 105, 101, 110, 116, 47, 99, 111, 109, 112, 105, 108, 101, 114, 115, 46, 99, 111, 110, 102, + 65535,65534,65533,65532, // 408+ + + // #6 + 65535,65534,65533,65532,65531,65530,65529,65528,65527, + 47, 118, 97, 114, 47, 116, 109, 112, 47, 116, 101, 97, 109, 98, 117, 105, 108, 100, 101, 114, 45, 116, 109, 97, 99, 105, 101, 105, 114, 47, 99, 108, 105, 101, 110, 116, 47, 99, 111, 109, 112, 105, 108, 101, 114, 115, 46, 99, 111, 110, 102, + 65535,65534,65533,65532, // 472+ + + + // #7 + 65535, + 97, 114, 99, 104, 105, 118, 101, 100, 32, 99, 111, 109, 112, 105, 108, 101, 114, 115, 47, + 65535,65534,65533,65532, // 496 + 65535,65534,65533,65532,65531, + 97, 114, 99, 104, 105, 118, 101, 100, 32, 99, 111, 109, 112, 105, 108, 101, 114, 115, 47, + 65535,65534,65533,65532,65531,65530,65529,65528, // 528 + + // #8 + 65535,65534,65533,65532,65531, + 97, 114, 99, 104, 105, 118, 101, 100, 32, 99, 111, 109, 112, 105, 108, 101, 114, 115, 47, + 65535,65534,65533,65532,65531,65530,65529,65528, // 560 + 65535,65534,65533,65532,65531, + 65, 114, 99, 104, 105, 118, 101, 100, 32, 67, 111, 109, 112, 105, 108, 101, 114, 115, 47, + 65535,65534,65533,65532,65531,65530,65529,65528, // 592 + + // #9 + 65535,65534,65533,65532,65531,65530,65529,65528,65527,65526,65525,65524,65523,65522,65521,65520,65519, + 47, 118, 97, 114, 47, 116, 109, 112, 47, 116, 101, 97, 109, 98, 117, 105, 108, 100, 101, 114, 45, 116, 109, 97, 99, 105, 101, 105, 114, 47, 99, 108, 105, 101, 110, 116, 47, 99, 111, 109, 112, 105, 108, 101, 114, 115, 46, 99, 111, 110, 102, + 65535,65534,65533,65532, // 664+ + 65535,65534,65533,65532,65531,65530,65529,65528,65527,65526,65525,65524,65523, + 47, 118, 97, 114, 47, 116, 109, 112, 47, 116, 101, 97, 109, 98, 117, 105, 108, 100, 101, 114, 45, 116, 109, 97, 99, 105, 101, 105, 114, 47, 99, 108, 105, 101, 110, 116, 47, 99, 111, 109, 112, 105, 108, 101, 114, 115, 46, 99, 111, 110, 102, + 65535,65534,65533,65532,65531,65530,65529,65528, // 736+ + + // #10 + 65535,65534,65533,65532,65531, + 76, 105, 110, 117, 120, + 65535,65534,65533,65532,65531,65530, // 752 + 65535, + 76, 105, 110, 117, 120, + 65535,65534, // 760 + + // #11 + 65535,65534,65533,65532,65531, + 105, 51, 56, 54, + 65535,65534,65533,65532,65531,65530,65529, // 776 + 65535,65534,65533,65532,65531, + 105, 51, 56, 54, + 65535,65534,65533,65532,65531,65530,65529, // 792 + + // #12 + 65535, + 105, 99, 99, + 65535,65534,65533,65532, // 800 + 65535,65534,65533,65532,65531, + 103, 43, 43, + 65535,65534,65533,65532,65531,65530,65529,65528, // 816 + + // #13 + 65535, + 76, 105, 110, 117, 120, + 65535,65534, // 824 + 65535, + 76, 105, 110, 117, 120, + 65535,65534, // 832 + + // #14 + 65535, + 105, 51, 56, 54, + 65535,65534,65533, // 840 + 65535,65534,65533,65532,65531, + 105, 51, 56, 54, + 65535,65534,65533,65532,65531,65530,65529, // 856 + + // #15 + 65535, + 76, 105, 110, 117, 120, + 65535,65534, // 864 + 65535, + 76, 105, 110, 117, 120, + 65535,65534, // 872 + + // #16 + 65535, + 105, 51, 56, 54, + 65535,65534,65533, // 880 + 65535,65534,65533,65532,65531, + 105, 51, 56, 54, + 65535,65534,65533,65532,65531,65530,65529, // 896 + + // #17 + 65535, + 103, 99, 99, + 65535,65534,65533,65532, // 904 + 65535,65534,65533,65532,65531, + 103, 43, 43, + 65535,65534,65533,65532,65531,65530,65529,65528, // 920 + + // #18 + 65535,65534,65533,65532,65531, + 76, 105, 110, 117, 120, + 65535,65534,65533,65532,65531,65530, // 936 + 65535, + 76, 105, 110, 117, 120, + 65535,65534, // 944 + + // #19 + 65535,65534,65533,65532,65531, + 105, 51, 56, 54, + 65535,65534,65533,65532,65531,65530,65529, // 960 + 65535,65534,65533,65532,65531, + 105, 51, 56, 54, + 65535,65534,65533,65532,65531,65530,65529, // 976 + + // #20 + 65535, + 103, 43, 43, + 65535,65534,65533,65532, // 984 + 65535,65534,65533,65532,65531, + 103, 43, 43, + 65535,65534,65533,65532,65531,65530,65529,65528, // 1000 + + // #21 + 65535,65534,65533,65532,65531, + 52, 46, 52, 46, 51, + 65535,65534,65533,65532,65531,65530, // 1016 + 65535,65534,65533,65532,65531, + 52, 46, 52, 46, 51, + 65535,65534,65533,65532,65531,65530, // 1032 + + // #22 + 65535, + 76, 105, 110, 117, 120, + 65535,65534, // 1040 + 65535, + 76, 105, 110, 117, 120, + 65535,65534, // 1048 + + // #23 + 65535,65534,65533,65532,65531, + 105, 51, 56, 54, + 65535,65534,65533,65532,65531,65530,65529, // 1064 + 65535,65534,65533,65532,65531, + 105, 51, 56, 54, + 65535,65534,65533,65532,65531,65530,65529, // 1080 + + // #24 + 65535, + 47, 117, 115, 114, 47, 98, 105, 110, 47, 103, 43, 43, + 65535,65534,65533, // 1096 + 65535, + 47, 117, 115, 114, 47, 98, 105, 110, 47, 103, 43, 43, + 65535,65534,65533, // 1112 + + // #25 + 65535, + 76, 105, 110, 117, 120, + 65535,65534, // 1120 + 65535, + 76, 105, 110, 117, 120, + 65535,65534, // 1128 + + // #26 + 65535, + 105, 51, 56, 54, + 65535,65534,65533, // 1136 + 65535,65534,65533,65532,65531, + 105, 51, 56, 54, + 65535,65534,65533,65532,65531,65530,65529, // 1152 + + // #27 + 65535, + 105, 99, 99, + 65535,65534,65533,65532, // 1160 + 65535,65534,65533,65532,65531, + 103, 43, 43, + 65535,65534,65533,65532,65531,65530,65529,65528, // 1176 + + // #28 + 65535, + 76, 105, 110, 117, 120, + 65535,65534, // 1184 + 65535, + 76, 105, 110, 117, 120, + 65535,65534, // 1192 + + // #29 + 65535, + 105, 51, 56, 54, + 65535,65534,65533, // 1200 + 65535,65534,65533,65532,65531, + 105, 51, 56, 54, + 65535,65534,65533,65532,65531,65530,65529, // 1216 + + // #30 + 65535,65534,65533,65532,65531, + 76, 105, 110, 117, 120, + 65535,65534,65533,65532,65531,65530, // 1232 + 65535, + 76, 105, 110, 117, 120, + 65535,65534, // 1240 + + // #31 + 65535,65534,65533,65532,65531, + 105, 51, 56, 54, + 65535,65534,65533,65532,65531,65530,65529, // 1256 + 65535,65534,65533,65532,65531, + 105, 51, 56, 54, + 65535,65534,65533,65532,65531,65530,65529, // 1272 + + // #32 + 65535,65534,65533,65532,65531, + 76, 105, 110, 117, 120, + 65535,65534,65533,65532,65531,65530, // 1288 + 65535, + 76, 105, 110, 117, 120, + 65535,65534, // 1296 + + // #33 + 65535,65534,65533,65532,65531, + 105, 51, 56, 54, + 65535,65534,65533,65532,65531,65530,65529, // 1312 + 65535,65534,65533,65532,65531, + 105, 51, 56, 54, + 65535,65534,65533,65532,65531,65530,65529, // 1328 + + // #34 + 65535, + 45, 109, 97, 114, 99, 104, 61, 99, 111, 114, 101, 50, + 65535,65534,65533, // 1344 + 65535, + 116, 98, 51, 54, 57, 54, 56, 95, 50, 46, 105, 105, + 65535,65534,65533, // 1360 + + // #35 + 65535,65534,65533,65532,65531, + 45, 102, 108, 111, 111, 112, 45, 98, 108, 111, 99, 107, + 65535,65534,65533,65532,65531,65530,65529, // 1384 + 65535, + 116, 98, 51, 54, 57, 54, 56, 95, 50, 46, 105, 105, + 65535,65534,65533, // 1400 + + // #36 + 65535,65534,65533,65532,65531, + 116, 98, 51, 54, 57, 54, 56, 95, 50, 46, 105, 105, + 65535,65534,65533,65532,65531,65530,65529, // 1424 + 65535, + 116, 98, 51, 54, 57, 54, 56, 95, 50, 46, 105, 105, + 65535,65534,65533, // 1440 + + // #37 + 65535,65534,65533,65532,65531, + 45, 109, 115, 115, 101, 52, + 65535,65534,65533,65532,65531, // 1456 + 65535,65534,65533,65532,65531, + 108, 101, 110, 103, 116, 104, + 65535,65534,65533,65532,65531, // 1472 + + // #38 + 65535,65534,65533,65532,65531, + 116, 98, 51, 54, 57, 54, 56, 95, 49, 46, 111, + 65535,65534,65533,65532,65531,65530,65529,65528, // 1496 + 65535,65534,65533,65532,65531, + 116, 98, 51, 54, 57, 54, 56, 95, 49, 46, 111, + 65535,65534,65533,65532,65531,65530,65529,65528, // 1520 + + // #39 + 65535,65534,65533,65532,65531, + 68, 69, 83, 75, 84, 79, 80, 95, 83, 69, 83, 83, + 65535,65534,65533,65532,65531,65530,65529, // 1544 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 1560 + + // #40 + 65535,65534,65533,65532,65531, + 76, 67, 95, 83, 79, 85, 82, 67, 69, 68, 61, 49, + 65535,65534,65533,65532,65531,65530,65529, // 1584 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 1600 + + // #41 + 65535,65534,65533,65532,65531, + 81, 84, 68, 73, 82, 61, 47, 104, 111, 109, 101, 47, + 65535,65534,65533,65532,65531,65530,65529, // 1624 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 1640 + + // #42 + 65535, + 76, 67, 95, 67, 84, 89, 80, 69, 61, 112, 116, 95, + 65535,65534,65533, // 1656 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 1672 + + // #43 + 65535, + 71, 84, 75, 95, 82, 67, 95, 70, 73, 76, 69, 83, + 65535,65534,65533, // 1688 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 1704 + + // #44 + 65535, + 88, 77, 79, 68, 73, 70, 73, 69, 82, 83, 61, 64, + 65535,65534,65533, // 1720 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 1736 + + // #45 + 65535, + 83, 72, 69, 76, 76, 61, 47, 98, 105, 110, 47, 122, + 65535,65534,65533, // 1752 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 1768 + + // #46 + 65535,65534,65533,65532,65531, + 85, 61, 64, 123, 117, 112, 115, 116, 114, 101, 97, 109, + 65535,65534,65533,65532,65531,65530,65529, // 1792 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 1808 + + // #47 + 65535, + 95, 61, 47, 117, 115, 114, 47, 98, 105, 110, 47, 105, + 65535,65534,65533, // 1824 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 1840 + + // #48 + 65535, + 88, 68, 71, 95, 67, 79, 78, 70, 73, 71, 95, 68, + 65535,65534,65533, // 1856 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 1872 + + // #49 + 65535,65534,65533,65532,65531, + 83, 65, 86, 69, 72, 73, 83, 84, 61, 49, 48, 48, + 65535,65534,65533,65532,65531,65530,65529, // 1896 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 1912 + + // #50 + 65535, + 75, 68, 69, 95, 77, 85, 76, 84, 73, 72, 69, 65, + 65535,65534,65533, // 1928 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 1944 + + // #51 + 65535,65534,65533,65532,65531, + 77, 65, 76, 76, 79, 67, 95, 67, 72, 69, 67, 75, + 65535,65534,65533,65532,65531,65530,65529, // 1968 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 1984 + + // #52 + 65535,65534,65533,65532,65531, + 72, 73, 83, 84, 67, 79, 78, 84, 82, 79, 76, 61, + 65535,65534,65533,65532,65531,65530,65529, // 2008 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 2024 + + // #53 + 65535,65534,65533,65532,65531, + 88, 68, 71, 95, 68, 65, 84, 65, 95, 68, 73, 82, + 65535,65534,65533,65532,65531,65530,65529, // 2048 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 2064 + + // #54 + 65535,65534,65533,65532,65531, + 88, 68, 77, 95, 77, 65, 78, 65, 71, 69, 68, 61, + 65535,65534,65533,65532,65531,65530,65529, // 2088 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 2104 + + // #55 + 65535, + 76, 67, 95, 67, 79, 76, 76, 65, 84, 69, 61, 112, + 65535,65534,65533, // 2120 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 2136 + + // #56 + 65535, + 81, 84, 95, 80, 76, 85, 71, 73, 78, 95, 80, 65, + 65535,65534,65533, // 2152 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 2168 + + // #57 + 65535, + 83, 67, 82, 69, 69, 78, 68, 73, 82, 61, 47, 104, + 65535,65534,65533, // 2184 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 2200 + + // #58 + 65535,65534,65533,65532,65531, + 76, 69, 83, 83, 79, 80, 69, 78, 61, 124, 47, 117, + 65535,65534,65533,65532,65531,65530,65529, // 2224 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 2240 + + // #59 + 65535, + 76, 67, 95, 78, 65, 77, 69, 61, 110, 98, 95, 78, + 65535,65534,65533, // 2256 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 2272 + + // #60 + 65535,65534,65533,65532,65531, + 80, 52, 67, 76, 73, 69, 78, 84, 61, 116, 109, 97, + 65535,65534,65533,65532,65531,65530,65529, // 2296 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 2312 + + // #61 + 65535, + 80, 65, 84, 72, 61, 47, 104, 111, 109, 101, 47, 116, + 65535,65534,65533, // 2328 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 2344 + + // #62 + 65535,65534,65533,65532,65531, + 71, 80, 71, 95, 65, 71, 69, 78, 84, 95, 73, 78, + 65535,65534,65533,65532,65531,65530,65529, // 2368 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 2384 + + // #63 + 65535,65534,65533,65532,65531, + 88, 67, 85, 82, 83, 79, 82, 95, 84, 72, 69, 77, + 65535,65534,65533,65532,65531,65530,65529, // 2408 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 2424 + + // #64 + 65535,65534,65533,65532,65531, + 83, 69, 83, 83, 73, 79, 78, 95, 77, 65, 78, 65, + 65535,65534,65533,65532,65531,65530,65529, // 2448 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 2464 + + // #65 + 65535, + 81, 84, 83, 82, 67, 68, 73, 82, 61, 47, 104, 111, + 65535,65534,65533, // 2480 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 2496 + + // #66 + 65535,65534,65533,65532,65531, + 87, 73, 78, 68, 79, 87, 73, 68, 61, 52, 54, 49, + 65535,65534,65533,65532,65531,65530,65529, // 2520 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 2536 + + // #67 + 65535,65534,65533,65532,65531, + 76, 67, 95, 77, 69, 83, 83, 65, 71, 69, 83, 61, + 65535,65534,65533,65532,65531,65530,65529, // 2560 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 2576 + + // #68 + 65535, + 76, 67, 95, 78, 85, 77, 69, 82, 73, 67, 61, 110, + 65535,65534,65533, // 2592 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 2608 + + // #69 + 65535, + 71, 84, 75, 50, 95, 82, 67, 95, 70, 73, 76, 69, + 65535,65534,65533, // 2624 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 2640 + + // #70 + 65535, + 80, 82, 79, 70, 73, 76, 69, 72, 79, 77, 69, 61, + 65535,65534,65533, // 2656 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 2672 + + // #71 + 65535,65534,65533,65532,65531, + 68, 77, 95, 67, 79, 78, 84, 82, 79, 76, 61, 47, + 65535,65534,65533,65532,65531,65530,65529, // 2696 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 2712 + + // #72 + 65535, + 76, 83, 95, 67, 79, 76, 79, 82, 83, 61, 114, 115, + 65535,65534,65533, // 2728 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 2744 + + // #73 + 65535,65534,65533,65532,65531, + 83, 83, 72, 95, 65, 85, 84, 72, 95, 83, 79, 67, + 65535,65534,65533,65532,65531,65530,65529, // 2768 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 2784 + + // #74 + 65535,65534,65533,65532,65531, + 75, 68, 69, 68, 73, 82, 83, 61, 47, 104, 111, 109, + 65535,65534,65533,65532,65531,65530,65529, // 2808 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 2824 + + // #75 + 65535,65534,65533,65532,65531, + 76, 68, 95, 80, 82, 69, 76, 79, 65, 68, 61, 47, + 65535,65534,65533,65532,65531,65530,65529, // 2848 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 2864 + + // #76 + 65535,65534,65533,65532,65531, + 88, 67, 85, 82, 83, 79, 82, 95, 80, 65, 84, 72, + 65535,65534,65533,65532,65531,65530,65529, // 2888 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 2904 + + // #77 + 65535, + 115, 114, 99, 100, 105, 114, 61, 47, 104, 111, 109, 101, + 65535,65534,65533, // 2920 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 2936 + + // #78 + 65535,65534,65533,65532,65531, + 72, 79, 77, 69, 61, 47, 104, 111, 109, 101, 47, 116, + 65535,65534,65533,65532,65531,65530,65529, // 2960 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 2976 + + // #79 + 65535, + 81, 84, 52, 68, 79, 67, 68, 73, 82, 61, 47, 117, + 65535,65534,65533, // 2992 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 3008 + + // #80 + 65535,65534,65533,65532,65531, + 80, 87, 68, 61, 47, 104, 111, 109, 101, 47, 116, 109, + 65535,65534,65533,65532,65531,65530,65529, // 3032 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 3048 + + // #81 + 65535,65534,65533,65532,65531, + 75, 68, 69, 95, 83, 69, 83, 83, 73, 79, 78, 95, + 65535,65534,65533,65532,65531,65530,65529, // 3072 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 3088 + + // #82 + 65535, + 73, 78, 83, 73, 68, 69, 95, 83, 80, 69, 67, 73, + 65535,65534,65533, // 3104 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 3120 + + // #83 + 65535, + 83, 83, 72, 95, 65, 71, 69, 78, 84, 95, 80, 73, + 65535,65534,65533, // 3136 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 3152 + + // #84 + 65535, + 80, 75, 71, 95, 67, 79, 78, 70, 73, 71, 95, 80, + 65535,65534,65533, // 3168 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 3184 + + // #85 + 65535,65534,65533,65532,65531, + 68, 66, 85, 83, 95, 83, 69, 83, 83, 73, 79, 78, + 65535,65534,65533,65532,65531,65530,65529, // 3208 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 3224 + + // #86 + 65535, + 76, 68, 95, 76, 73, 66, 82, 65, 82, 89, 95, 80, + 65535,65534,65533, // 3240 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 3256 + + // #87 + 65535,65534,65533,65532,65531, + 80, 52, 85, 83, 69, 82, 61, 116, 106, 109, 97, 99, + 65535,65534,65533,65532,65531,65530,65529, // 3280 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 3296 + + // #88 + 65535,65534,65533,65532,65531, + 81, 84, 69, 83, 84, 95, 67, 79, 76, 79, 82, 69, + 65535,65534,65533,65532,65531,65530,65529, // 3320 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 3336 + + // #89 + 65535,65534,65533,65532,65531, + 88, 68, 71, 95, 83, 69, 83, 83, 73, 79, 78, 95, + 65535,65534,65533,65532,65531,65530,65529, // 3360 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 3376 + + // #90 + 65535,65534,65533,65532,65531, + 76, 69, 83, 83, 75, 69, 89, 61, 47, 101, 116, 99, + 65535,65534,65533,65532,65531,65530,65529, // 3400 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 3416 + + // #91 + 65535, + 76, 79, 71, 78, 65, 77, 69, 61, 116, 109, 97, 99, + 65535,65534,65533, // 3432 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 3448 + + // #92 + 65535, + 71, 95, 70, 73, 76, 69, 78, 65, 77, 69, 95, 69, + 65535,65534,65533, // 3464 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 3480 + + // #93 + 65535, + 75, 68, 69, 95, 70, 85, 76, 76, 95, 83, 69, 83, + 65535,65534,65533, // 3496 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 3512 + + // #94 + 65535,65534,65533,65532,65531, + 72, 79, 83, 84, 78, 65, 77, 69, 61, 108, 111, 116, + 65535,65534,65533,65532,65531,65530,65529, // 3536 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 3552 + + // #95 + 65535,65534,65533,65532,65531, + 76, 67, 95, 84, 73, 77, 69, 61, 112, 116, 95, 66, + 65535,65534,65533,65532,65531,65530,65529, // 3576 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 3592 + + // #96 + 65535, + 83, 83, 72, 95, 65, 83, 75, 80, 65, 83, 83, 61, + 65535,65534,65533, // 3608 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 3624 + + // #97 + 65535,65534,65533,65532,65531, + 72, 73, 83, 84, 70, 73, 76, 69, 61, 47, 104, 111, + 65535,65534,65533,65532,65531,65530,65529, // 3648 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 3664 + + // #98 + 65535, + 75, 79, 78, 83, 79, 76, 69, 95, 68, 66, 85, 83, + 65535,65534,65533, // 3680 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 3696 + + // #99 + 65535, + 77, 65, 75, 69, 61, 47, 117, 115, 114, 47, 98, 105, + 65535,65534,65533, // 3712 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 3728 + + // #100 + 65535, + 67, 65, 78, 66, 69, 82, 82, 65, 95, 68, 82, 73, + 65535,65534,65533, // 3744 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 3760 + + // #101 + 65535, + 71, 67, 79, 78, 70, 95, 84, 77, 80, 68, 73, 82, + 65535,65534,65533, // 3776 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 3792 + + // #102 + 65535,65534,65533,65532,65531, + 85, 83, 69, 82, 61, 116, 109, 97, 99, 105, 101, 105, + 65535,65534,65533,65532,65531,65530,65529, // 3816 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 3832 + + // #103 + 65535, + 111, 98, 106, 100, 105, 114, 61, 47, 104, 111, 109, 101, + 65535,65534,65533, // 3848 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 3864 + + // #104 + 65535,65534,65533,65532,65531, + 76, 67, 95, 77, 79, 78, 69, 84, 65, 82, 89, 61, + 65535,65534,65533,65532,65531,65530,65529, // 3888 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 3904 + + // #105 + 65535,65534,65533,65532,65531, + 81, 84, 76, 73, 66, 61, 47, 117, 115, 114, 47, 108, + 65535,65534,65533,65532,65531,65530,65529, // 3928 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 3944 + + // #106 + 65535,65534,65533,65532,65531, + 76, 67, 95, 84, 69, 76, 69, 80, 72, 79, 78, 69, + 65535,65534,65533,65532,65531,65530,65529, // 3968 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 3984 + + // #107 + 65535, + 80, 89, 84, 72, 79, 78, 68, 79, 78, 84, 87, 82, + 65535,65534,65533, // 4000 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 4016 + + // #108 + 65535,65534,65533,65532,65531, + 84, 77, 80, 68, 73, 82, 61, 47, 116, 109, 112, 47, + 65535,65534,65533,65532,65531,65530,65529, // 4040 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 4056 + + // #109 + 65535,65534,65533,65532,65531, + 65, 82, 77, 76, 77, 68, 95, 76, 73, 67, 69, 78, + 65535,65534,65533,65532,65531,65530,65529, // 4080 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 4096 + + // #110 + 65535, + 80, 89, 84, 72, 79, 78, 80, 65, 84, 72, 61, 47, + 65535,65534,65533, // 4112 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 4128 + + // #111 + 65535,65534,65533,65532,65531, + 77, 65, 75, 69, 70, 76, 65, 71, 83, 61, 119, 32, + 65535,65534,65533,65532,65531,65530,65529, // 4152 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 4168 + + // #112 + 65535, + 77, 70, 76, 65, 71, 83, 61, 45, 119, 32, 45, 45, + 65535,65534,65533, // 4184 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 4200 + + // #113 + 65535, + 77, 65, 73, 76, 61, 47, 118, 97, 114, 47, 115, 112, + 65535,65534,65533, // 4216 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 4232 + + // #114 + 65535,65534,65533,65532,65531, + 83, 72, 69, 76, 76, 95, 83, 69, 83, 83, 73, 79, + 65535,65534,65533,65532,65531,65530,65529, // 4256 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 4272 + + // #115 + 65535, + 75, 68, 69, 68, 73, 82, 61, 47, 104, 111, 109, 101, + 65535,65534,65533, // 4288 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 4304 + + // #116 + 65535,65534,65533,65532,65531, + 76, 69, 83, 83, 67, 72, 65, 82, 83, 69, 84, 61, + 65535,65534,65533,65532,65531,65530,65529, // 4328 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 4344 + + // #117 + 65535,65534,65533,65532,65531, + 76, 67, 95, 80, 65, 80, 69, 82, 61, 110, 98, 95, + 65535,65534,65533,65532,65531,65530,65529, // 4368 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 4384 + + // #118 + 65535, + 66, 82, 79, 87, 83, 69, 82, 61, 47, 117, 115, 114, + 65535,65534,65533, // 4400 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 4416 + + // #119 + 65535, + 77, 69, 84, 65, 95, 67, 76, 65, 83, 83, 61, 100, + 65535,65534,65533, // 4432 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 4448 + + // #120 + 65535,65534,65533,65532,65531, + 77, 68, 86, 95, 77, 69, 78, 85, 95, 83, 84, 89, + 65535,65534,65533,65532,65531,65530,65529, // 4472 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 4488 + + // #121 + 65535,65534,65533,65532,65531, + 67, 79, 76, 79, 82, 70, 71, 66, 71, 61, 49, 53, + 65535,65534,65533,65532,65531,65530,65529, // 4512 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 4528 + + // #122 + 65535,65534,65533,65532,65531, + 80, 89, 84, 72, 79, 78, 83, 84, 65, 82, 84, 85, + 65535,65534,65533,65532,65531,65530,65529, // 4552 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 4568 + + // #123 + 65535, + 76, 67, 95, 77, 69, 65, 83, 85, 82, 69, 77, 69, + 65535,65534,65533, // 4584 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 4600 + + // #124 + 65535,65534,65533,65532,65531, + 69, 68, 73, 84, 79, 82, 61, 47, 117, 115, 114, 47, + 65535,65534,65533,65532,65531,65530,65529, // 4624 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 4640 + + // #125 + 65535,65534,65533,65532,65531, + 69, 78, 95, 84, 66, 61, 109, 111, 99, 58, 117, 105, + 65535,65534,65533,65532,65531,65530,65529, // 4664 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 4680 + + // #126 + 65535, + 72, 73, 83, 84, 83, 73, 90, 69, 61, 49, 48, 48, + 65535,65534,65533, // 4696 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 4712 + + // #127 + 65535,65534,65533,65532,65531, + 71, 83, 95, 76, 73, 66, 61, 47, 104, 111, 109, 101, + 65535,65534,65533,65532,65531,65530,65529, // 4736 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 4752 + + // #128 + 65535,65534,65533,65532,65531, + 78, 76, 83, 80, 65, 84, 72, 61, 47, 117, 115, 114, + 65535,65534,65533,65532,65531,65530,65529, // 4776 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 4792 + + // #129 + 65535,65534,65533,65532,65531, + 87, 73, 78, 68, 79, 87, 80, 65, 84, 72, 61, 55, + 65535,65534,65533,65532,65531,65530,65529, // 4816 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 4832 + + // #130 + 65535,65534,65533,65532,65531, + 75, 79, 78, 83, 79, 76, 69, 95, 68, 66, 85, 83, + 65535,65534,65533,65532,65531,65530,65529, // 4856 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 4872 + + // #131 + 65535, + 76, 67, 95, 73, 68, 69, 78, 84, 73, 70, 73, 67, + 65535,65534,65533, // 4888 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 4904 + + // #132 + 65535, + 73, 78, 80, 85, 84, 82, 67, 61, 47, 101, 116, 99, + 65535,65534,65533, // 4920 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 4936 + + // #133 + 65535,65534,65533,65532,65531, + 81, 84, 73, 78, 67, 61, 47, 117, 115, 114, 47, 108, + 65535,65534,65533,65532,65531,65530,65529, // 4960 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 4976 + + // #134 + 65535, + 76, 67, 95, 65, 68, 68, 82, 69, 83, 83, 61, 110, + 65535,65534,65533, // 4992 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 5008 + + // #135 + 65535,65534,65533,65532,65531, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 95, + 65535,65534,65533,65532,65531,65530,65529, // 5032 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 5048 + + // #136 + 65535, + 76, 65, 78, 71, 61, 112, 116, 95, 66, 82, 46, 85, + 65535,65534,65533, // 5064 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 5080 + + // #137 + 65535, + 80, 52, 80, 79, 82, 84, 61, 112, 52, 46, 116, 114, + 65535,65534,65533, // 5096 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 5112 + + // #138 + 65535,65534,65533,65532,65531, + 80, 73, 76, 79, 84, 80, 79, 82, 84, 61, 117, 115, + 65535,65534,65533,65532,65531,65530,65529, // 5136 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 5152 + + // #139 + 65535, + 75, 68, 69, 95, 83, 69, 83, 83, 73, 79, 78, 95, + 65535,65534,65533, // 5168 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 5184 + + // #140 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 5200 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 5216 + + +}; +static struct StringCollection +{ + int len; + int offset1, offset2; + ushort align1, align2; +} stringCollection[] = { + {18, 1, 29, 3666, 106}, // #0 + {18, 53, 77, 106, 1978}, // #1 + {20, 97, 125, 2850, 3210}, // #2 + {20, 157, 185, 3210, 3138}, // #3 + {51, 225, 225, 3362, 3362}, // #4 + {51, 293, 353, 1434, 3362}, // #5 + {51, 417, 417, 3362, 3362}, // #6 + {19, 473, 501, 2850, 10}, // #7 + {19, 533, 565, 10, 442}, // #8 + {51, 609, 677, 3362, 1434}, // #9 + {5, 741, 753, 2666, 2066}, // #10 + {4, 765, 781, 2362, 3930}, // #11 + {3, 793, 805, 3330, 2138}, // #12 + {5, 817, 825, 738, 2066}, // #13 + {4, 833, 845, 434, 3930}, // #14 + {5, 857, 865, 3842, 2066}, // #15 + {4, 873, 885, 3538, 3930}, // #16 + {3, 897, 909, 3330, 2138}, // #17 + {5, 925, 937, 1898, 2066}, // #18 + {4, 949, 965, 1594, 3930}, // #19 + {3, 977, 989, 3330, 2138}, // #20 + {5, 1005, 1021, 2218, 762}, // #21 + {5, 1033, 1041, 3346, 2066}, // #22 + {4, 1053, 1069, 3082, 3930}, // #23 + {12, 1081, 1097, 2082, 962}, // #24 + {5, 1113, 1121, 3362, 2066}, // #25 + {4, 1129, 1141, 322, 3930}, // #26 + {3, 1153, 1165, 2050, 2138}, // #27 + {5, 1177, 1185, 1538, 2066}, // #28 + {4, 1193, 1205, 1234, 3930}, // #29 + {5, 1221, 1233, 554, 2066}, // #30 + {4, 1245, 1261, 250, 3930}, // #31 + {5, 1277, 1289, 2858, 2066}, // #32 + {4, 1301, 1317, 2554, 3930}, // #33 + {12, 1329, 1345, 2194, 1762}, // #34 + {12, 1365, 1385, 2170, 1762}, // #35 + {12, 1405, 1425, 2314, 1762}, // #36 + {6, 1445, 1461, 3626, 666}, // #37 + {11, 1477, 1501, 3882, 842}, // #38 + {12, 1525, 1545, 1722, 2930}, // #39 + {12, 1565, 1585, 1914, 2930}, // #40 + {12, 1605, 1625, 442, 2930}, // #41 + {12, 1641, 1657, 626, 2930}, // #42 + {12, 1673, 1689, 946, 2930}, // #43 + {12, 1705, 1721, 738, 2930}, // #44 + {12, 1737, 1753, 2066, 2930}, // #45 + {12, 1773, 1793, 1210, 2930}, // #46 + {12, 1809, 1825, 1426, 2930}, // #47 + {12, 1841, 1857, 1650, 2930}, // #48 + {12, 1877, 1897, 1530, 2930}, // #49 + {12, 1913, 1929, 1858, 2930}, // #50 + {12, 1949, 1969, 2106, 2930}, // #51 + {12, 1989, 2009, 2202, 2930}, // #52 + {12, 2029, 2049, 2490, 2930}, // #53 + {12, 2069, 2089, 2794, 2930}, // #54 + {12, 2105, 2121, 2322, 2930}, // #55 + {12, 2137, 2153, 2834, 2930}, // #56 + {12, 2169, 2185, 1266, 2930}, // #57 + {12, 2205, 2225, 2538, 2930}, // #58 + {12, 2241, 2257, 2706, 2930}, // #59 + {12, 2277, 2297, 3402, 2930}, // #60 + {12, 2313, 2329, 146, 2930}, // #61 + {12, 2349, 2369, 3690, 2930}, // #62 + {12, 2389, 2409, 810, 2930}, // #63 + {12, 2429, 2449, 1178, 2930}, // #64 + {12, 2465, 2481, 1442, 2930}, // #65 + {12, 2501, 2521, 3546, 2930}, // #66 + {12, 2541, 2561, 1930, 2930}, // #67 + {12, 2577, 2593, 1634, 2930}, // #68 + {12, 2609, 2625, 1986, 2930}, // #69 + {12, 2641, 2657, 1970, 2930}, // #70 + {12, 2677, 2697, 1834, 2930}, // #71 + {12, 2713, 2729, 1474, 2930}, // #72 + {12, 2749, 2769, 2250, 2930}, // #73 + {12, 2789, 2809, 2458, 2930}, // #74 + {12, 2829, 2849, 2618, 2930}, // #75 + {12, 2869, 2889, 3066, 2930}, // #76 + {12, 2905, 2921, 3330, 2930}, // #77 + {12, 2941, 2961, 1706, 2930}, // #78 + {12, 2977, 2993, 2802, 2930}, // #79 + {12, 3013, 3033, 3770, 2930}, // #80 + {12, 3053, 3073, 3594, 2930}, // #81 + {12, 3089, 3105, 2, 2930}, // #82 + {12, 3121, 3137, 2962, 2930}, // #83 + {12, 3153, 3169, 290, 2930}, // #84 + {12, 3189, 3209, 794, 2930}, // #85 + {12, 3225, 3241, 1058, 2930}, // #86 + {12, 3261, 3281, 2394, 2930}, // #87 + {12, 3301, 3321, 138, 2930}, // #88 + {12, 3341, 3361, 1482, 2930}, // #89 + {12, 3381, 3401, 570, 2930}, // #90 + {12, 3417, 3433, 674, 2930}, // #91 + {12, 3449, 3465, 1282, 2930}, // #92 + {12, 3481, 3497, 1746, 2930}, // #93 + {12, 3517, 3537, 1866, 2930}, // #94 + {12, 3557, 3577, 1978, 2930}, // #95 + {12, 3593, 3609, 3954, 2930}, // #96 + {12, 3629, 3649, 2570, 2930}, // #97 + {12, 3665, 3681, 2754, 2930}, // #98 + {12, 3697, 3713, 3666, 2930}, // #99 + {12, 3729, 3745, 34, 2930}, // #100 + {12, 3761, 3777, 2914, 2930}, // #101 + {12, 3797, 3817, 1194, 2930}, // #102 + {12, 3833, 3849, 3202, 2930}, // #103 + {12, 3869, 3889, 3018, 2930}, // #104 + {12, 3909, 3929, 202, 2930}, // #105 + {12, 3949, 3969, 3546, 2930}, // #106 + {12, 3985, 4001, 3682, 2930}, // #107 + {12, 4021, 4041, 3466, 2930}, // #108 + {12, 4061, 4081, 4074, 2930}, // #109 + {12, 4097, 4113, 306, 2930}, // #110 + {12, 4133, 4153, 634, 2930}, // #111 + {12, 4169, 4185, 802, 2930}, // #112 + {12, 4201, 4217, 962, 2930}, // #113 + {12, 4237, 4257, 1114, 2930}, // #114 + {12, 4273, 4289, 1250, 2930}, // #115 + {12, 4309, 4329, 3898, 2930}, // #116 + {12, 4349, 4369, 1386, 2930}, // #117 + {12, 4385, 4401, 1586, 2930}, // #118 + {12, 4417, 4433, 1730, 2930}, // #119 + {12, 4453, 4473, 1914, 2930}, // #120 + {12, 4493, 4513, 1498, 2930}, // #121 + {12, 4533, 4553, 2138, 2930}, // #122 + {12, 4569, 4585, 2290, 2930}, // #123 + {12, 4605, 4625, 2426, 2930}, // #124 + {12, 4645, 4665, 2666, 2930}, // #125 + {12, 4681, 4697, 2050, 2930}, // #126 + {12, 4717, 4737, 2874, 2930}, // #127 + {12, 4757, 4777, 3018, 2930}, // #128 + {12, 4797, 4817, 1834, 2930}, // #129 + {12, 4837, 4857, 3178, 2930}, // #130 + {12, 4873, 4889, 3314, 2930}, // #131 + {12, 4905, 4921, 2546, 2930}, // #132 + {12, 4941, 4961, 3546, 2930}, // #133 + {12, 4977, 4993, 3682, 2930}, // #134 + {12, 5013, 5033, 3802, 2930}, // #135 + {12, 5049, 5065, 3922, 2930}, // #136 + {12, 5081, 5097, 4018, 2930}, // #137 + {12, 5117, 5137, 42, 2930}, // #138 + {12, 5153, 5169, 130, 2930}, // #139 + {12, 5185, 5201, 242, 2930}, // #140 +}; +static const int stringCollectionCount = 141; +static const int stringCollectionMaxLen = 51; +// average comparison length: 12.0922 +// cache-line crosses: 6 (2.1%) +// alignment histogram: +// 0xXXX2 = 188 (66.7%) strings, 57 (30.3%) of which same-aligned +// 0xXXXa = 94 (33.3%) strings, 10 (10.6%) of which same-aligned +// total = 282 (100%) strings, 67 (23.8%) of which same-aligned diff --git a/tests/benchmarks/corelib/tools/qstring/main.cpp b/tests/benchmarks/corelib/tools/qstring/main.cpp index fb65f65..88dc40b 100644 --- a/tests/benchmarks/corelib/tools/qstring/main.cpp +++ b/tests/benchmarks/corelib/tools/qstring/main.cpp @@ -48,8 +48,15 @@ #define SRCDIR "" #endif +#ifdef Q_OS_UNIX +#include +#include +#endif + #include +#include "data.cpp" + class tst_QString: public QObject { Q_OBJECT @@ -73,20 +80,8 @@ void tst_QString::equals() const } } -static ushort databuffer[4096]; - tst_QString::tst_QString() { - // populate databuffer with our seed, each byte 3 times in a row - // include the NUL! - static const char seed[] = "AAAAAAAAAEhlbGxvIFdvcmxkIAAAAAA="; - static const int repeat = 3; - int pos = 0; - for (ushort *p = databuffer; p < databuffer + (sizeof(databuffer) / sizeof(databuffer[0])); p += repeat) { - for (int j = 0; j < repeat; ++p, ++j) - *p = seed[pos]; - pos = (pos + 1) % sizeof(seed); - } } void tst_QString::equals_data() const @@ -148,13 +143,15 @@ void tst_QString::equals_data() const << QString::fromRawData(ptr + 1, 58) << QString::fromRawData(ptr + 3, 58); } -static bool equals2_memcmp_call(ushort *p1, ushort *p2, int len) +static bool equals2_memcmp_call(const ushort *p1, const ushort *p2, int len) { return memcmp(p1, p2, len * 2) == 0; } -static bool equals2_bytewise(ushort *p1, ushort *p2, int len) +static bool equals2_bytewise(const ushort *p1, const ushort *p2, int len) { + if (p1 == p2 || !len) + return true; uchar *b1 = (uchar *)p1; uchar *b2 = (uchar *)p2; len *= 2; @@ -164,17 +161,24 @@ static bool equals2_bytewise(ushort *p1, ushort *p2, int len) return true; } -static bool equals2_shortwise(ushort *p1, ushort *p2, int len) +static bool __attribute__((optimize("unroll-loops"))) equals2_shortwise(const ushort *p1, const ushort *p2, int len) { - register ushort * const end = p1 + len; - for ( ; p1 != end; ++p1, ++p2) - if (*p1 != *p2) + if (p1 == p2 || !len) + return true; +// for (register int counter; counter < len; ++counter) +// if (p1[counter] != p2[counter]) +// return false; + while (len--) { + if (p1[len] != p2[len]) return false; + } return true; } -static bool equals2_intwise(ushort *p1, ushort *p2, int length) +static bool equals2_intwise(const ushort *p1, const ushort *p2, int length) { + if (p1 == p2 || !length) + return true; register union { const quint16 *w; const quint32 *d; @@ -219,71 +223,204 @@ static bool equals2_intwise(ushort *p1, ushort *p2, int length) return true; } +static inline bool equals2_short_tail(const ushort *p1, const ushort *p2, int len) +{ + if (len) { + if (*p1 != *p2) + return false; + if (--len) { + if (p1[1] != p2[1]) + return false; + if (--len) { + if (p1[2] != p2[2]) + return false; + if (--len) { + if (p1[3] != p2[3]) + return false; + if (--len) { + if (p1[4] != p2[4]) + return false; + if (--len) { + if (p1[5] != p2[5]) + return false; + if (--len) { + if (p1[6] != p2[6]) + return false; + return p1[7] == p2[7]; + } + } + } + } + } + } + } + return true; +} + +#pragma GCC optimize("no-unroll-loops") #ifdef __SSE2__ -static bool equals2_sse2(ushort *p1, ushort *p2, int len) +static bool equals2_sse2_aligned(const ushort *p1, const ushort *p2, int len) { - if (len > 8) { + if (len >= 8) { + qptrdiff counter = 0; while (len > 8) { - __m128i q1 = _mm_loadu_si128((__m128i *)p1); - __m128i q2 = _mm_loadu_si128((__m128i *)p2); + __m128i q1 = _mm_load_si128((__m128i *)(p1 + counter)); + __m128i q2 = _mm_load_si128((__m128i *)(p2 + counter)); + __m128i cmp = _mm_cmpeq_epi16(q1, q2); + if (ushort(_mm_movemask_epi8(cmp)) != ushort(0xffff)) + return false; + + len -= 8; + counter += 8; + } + p1 += counter; + p2 += counter; + } + + return equals2_short_tail(p1, p2, len); +} + +static bool __attribute__((optimize("no-unroll-loops"))) equals2_sse2(const ushort *p1, const ushort *p2, int len) +{ + if (p1 == p2 || !len) + return true; + + if (len >= 8) { + qptrdiff counter = 0; + while (len >= 8) { + __m128i q1 = _mm_loadu_si128((__m128i *)(p1 + counter)); + __m128i q2 = _mm_loadu_si128((__m128i *)(p2 + counter)); __m128i cmp = _mm_cmpeq_epi16(q1, q2); if (ushort(_mm_movemask_epi8(cmp)) != 0xffff) return false; len -= 8; - p1 += 8; - p2 += 8; + counter += 8; } + p1 += counter; + p2 += counter; } - return equals2_shortwise(p1, p2, len); + return equals2_short_tail(p1, p2, len); } -static inline -#ifdef Q_CC_GNU -__attribute__((always_inline)) -#endif -bool prolog_align(ushort *&p1, ushort *&p2, int &len) +//static bool equals2_sse2(const ushort *p1, const ushort *p2, int len) +//{ +// register int val1 = quintptr(p1) & 0xf; +// register int val2 = quintptr(p2) & 0xf; +// if (false && val1 + val2 == 0) +// return equals2_sse2_aligned(p1, p2, len); +// else +// return equals2_sse2_unaligned(p1, p2, len); +//} + +static bool equals2_sse2_aligning(const ushort *p1, const ushort *p2, int len) { - const ushort *end = (ushort*) ((quintptr(p1) + 15) & ~15); - if (end > p1 + len) - end = p1 + len; - for ( ; p1 != end; ++p1, ++p2, --len) - if (*p1 != *p2) + if (len < 8) + return equals2_short_tail(p1, p2, len); + + qptrdiff counter = 0; + + // which one is easier to align, p1 or p2 ? + register int val1 = quintptr(p1) & 0xf; + register int val2 = quintptr(p2) & 0xf; + if (val1 && val2) { +#if 0 + // we'll align the one which requires the least number of steps + if (val1 > val2) { + qSwap(p1, p2); + val1 = val2; + } + + // val1 contains the number of bytes past the 16-aligned mark + // we must read 16-val1 bytes to align + val1 = 16 - val1; + if (val1 & 0x2) { + if (*p1 != *p2) + return false; + --len; + ++counter; + } + while (val1 & 12) { + if (*(uint*)p1 != *(uint*)p2) + return false; + --len; + counter += 2; + val1 -= 4; + } +#else + // we'll align the one closest to the 16-byte mark + if (val1 > val2) { + qSwap(p1, p2); + val1 = val2; + } + + // we're reading val1 bytes too many + __m128i q2 = _mm_loadu_si128((__m128i *)(p2 - val1/2)); + __m128i cmp = _mm_cmpeq_epi16(*(__m128i *)(p1 - val1/2), q2); + if (short(_mm_movemask_epi8(cmp)) >> val1 != short(-1)) return false; - return true; + + counter = 8 - val1/2; + len -= 8 - val1/2; +#endif + } else if (!val2) { + // p2 is already aligned + qSwap(p1, p2); + } + + // p1 is aligned + + while (len >= 8) { + __m128i q1 = _mm_load_si128((__m128i *)(p1 + counter)); + __m128i q2 = _mm_loadu_si128((__m128i *)(p2 + counter)); + __m128i cmp = _mm_cmpeq_epi16(q1, q2); + if (ushort(_mm_movemask_epi8(cmp)) != ushort(0xffff)) + return false; + + len -= 8; + counter += 8; + } + + // tail + return equals2_short_tail(p1 + counter, p2 + counter, len); } -static bool equals2_sse2_aligning(ushort *p1, ushort *p2, int len) +#ifdef __SSE3__ +static bool __attribute__((optimize("no-unroll-loops"))) equals2_sse3(const ushort *p1, const ushort *p2, int len) { - if (len > 8) { - if (!prolog_align(p1, p2, len)) - return false; - while (len > 8) { - __m128i q1 = _mm_load_si128((__m128i *)p1); - __m128i q2 = _mm_loadu_si128((__m128i *)p2); + if (p1 == p2 || !len) + return true; + + if (len >= 8) { + qptrdiff counter = 0; + while (len >= 8) { + __m128i q1 = _mm_lddqu_si128((__m128i *)(p1 + counter)); + __m128i q2 = _mm_lddqu_si128((__m128i *)(p2 + counter)); __m128i cmp = _mm_cmpeq_epi16(q1, q2); if (ushort(_mm_movemask_epi8(cmp)) != 0xffff) return false; len -= 8; - p1 += 8; - p2 += 8; + counter += 8; } + p1 += counter; + p2 += counter; } - return equals2_shortwise(p1, p2, len); + return equals2_short_tail(p1, p2, len); } -template static inline bool equals2_ssse3_alignr(__m128i *m1, __m128i *m2, int len) +#ifdef __SSSE3__ +template static __attribute__((optimize("unroll-loops"))) inline bool equals2_ssse3_alignr(__m128i *m1, __m128i *m2, int len) { __m128i lower = _mm_load_si128(m1); - while (len > 8) { + while (len >= 8) { __m128i upper = _mm_load_si128(m1 + 1); __m128i correct; correct = _mm_alignr_epi8(upper, lower, N); - __m128i q2 = _mm_loadu_si128(m2); + __m128i q2 = _mm_lddqu_si128(m2); __m128i cmp = _mm_cmpeq_epi16(correct, q2); if (ushort(_mm_movemask_epi8(cmp)) != 0xffff) return false; @@ -295,13 +432,13 @@ template static inline bool equals2_ssse3_alignr(__m128i *m1, __m128i *m2 } // tail - return len == 0 || equals2_shortwise((ushort *)m1 + N / 2, (ushort*)m2, len); + return len == 0 || equals2_short_tail((const ushort *)m1 + N / 2, (const ushort*)m2, len); } -static inline bool equals2_ssse3_aligned(__m128i *m1, __m128i *m2, int len) +static inline __attribute__((optimize("unroll-loops"))) bool equals2_ssse3_aligned(__m128i *m1, __m128i *m2, int len) { - while (len > 8) { - __m128i q2 = _mm_loadu_si128(m2); + while (len >= 8) { + __m128i q2 = _mm_lddqu_si128(m2); __m128i cmp = _mm_cmpeq_epi16(*m1, q2); if (ushort(_mm_movemask_epi8(cmp)) != 0xffff) return false; @@ -310,30 +447,30 @@ static inline bool equals2_ssse3_aligned(__m128i *m1, __m128i *m2, int len) ++m1; ++m2; } - return len == 0 || equals2_shortwise((ushort *)m1, (ushort *)m2, len); + return len == 0 || equals2_short_tail((const ushort *)m1, (const ushort *)m2, len); } -//#ifdef __SSSE3__ -static bool equals2_ssse3(ushort *p1, ushort *p2, int len) +static bool equals2_ssse3(const ushort *p1, const ushort *p2, int len) { // p1 & 0xf can be: // 0, 2, 4, 6, 8, 10, 12, 14 // If it's 0, we're aligned // If it's not, then we're interested in the 16 - (p1 & 0xf) bytes only - if (len > 8) { + if (len >= 8) { // find the last aligned position below the p1 memory __m128i *m1 = (__m128i *)(quintptr(p1) & ~0xf); __m128i *m2 = (__m128i *)p2; - uchar diff = quintptr(p1) - quintptr(m1); + qptrdiff diff = quintptr(p1) - quintptr(m1); // diff contains the number of extra bytes + if (diff == 10) + return equals2_ssse3_alignr<10>(m1, m2, len); + else if (diff == 2) + return equals2_ssse3_alignr<2>(m1, m2, len); if (diff < 8) { if (diff < 4) { - if (diff == 0) - return equals2_ssse3_aligned(m1, m2, len); - else // diff == 2 - return equals2_ssse3_alignr<2>(m1, m2, len); + return equals2_ssse3_aligned(m1, m2, len); } else { if (diff == 4) return equals2_ssse3_alignr<4>(m1, m2, len); @@ -342,10 +479,7 @@ static bool equals2_ssse3(ushort *p1, ushort *p2, int len) } } else { if (diff < 12) { - if (diff == 8) - return equals2_ssse3_alignr<8>(m1, m2, len); - else // diff == 10 - return equals2_ssse3_alignr<10>(m1, m2, len); + return equals2_ssse3_alignr<8>(m1, m2, len); } else { if (diff == 12) return equals2_ssse3_alignr<12>(m1, m2, len); @@ -353,34 +487,99 @@ static bool equals2_ssse3(ushort *p1, ushort *p2, int len) return equals2_ssse3_alignr<14>(m1, m2, len); } } + } + + // tail + return equals2_short_tail(p1, p2, len); +} + +template static inline bool equals2_ssse3_aligning_alignr(__m128i *m1, __m128i *m2, int len) +{ + __m128i lower = _mm_load_si128(m1); + while (len >= 8) { + __m128i upper = _mm_load_si128(m1 + 1); + __m128i correct; + correct = _mm_alignr_epi8(upper, lower, N); + + __m128i cmp = _mm_cmpeq_epi16(correct, *m2); + if (ushort(_mm_movemask_epi8(cmp)) != 0xffff) + return false; -// switch (diff) { -// case 0: -// return equals2_ssse3_aligned(m1, m2, len); -// case 2: -// return equals2_ssse3_alignr<2>(m1, m2, len); -// case 4: -// return equals2_ssse3_alignr<4>(m1, m2, len); -// case 6: -// return equals2_ssse3_alignr<6>(m1, m2, len); -// case 8: -// return equals2_ssse3_alignr<8>(m1, m2, len); -// case 10: -// return equals2_ssse3_alignr<10>(m1, m2, len); -// case 12: -// return equals2_ssse3_alignr<12>(m1, m2, len); -// case 14: -// return equals2_ssse3_alignr<14>(m1, m2, len); -// } + len -= 8; + ++m2; + ++m1; + lower = upper; } // tail - return equals2_shortwise(p1, p2, len); + return len == 0 || equals2_short_tail((const ushort *)m1 + N / 2, (const ushort*)m2, len); } -//#endif -//#ifdef __SSE4_1__ -static bool equals2_sse4(ushort *p1, ushort *p2, int len) +static bool equals2_ssse3_aligning(const ushort *p1, const ushort *p2, int len) +{ + if (len < 8) + return equals2_short_tail(p1, p2, len); + qptrdiff counter = 0; + + // which one is easier to align, p1 or p2 ? + { + register int val1 = quintptr(p1) & 0xf; + register int val2 = quintptr(p2) & 0xf; + if (val1 && val2) { + // we'll align the one closest to the 16-byte mark + if (val1 < val2) { + qSwap(p1, p2); + val2 = val1; + } + + // we're reading val1 bytes too many + __m128i q1 = _mm_lddqu_si128((__m128i *)(p1 - val2/2)); + __m128i cmp = _mm_cmpeq_epi16(q1, *(__m128i *)(p2 - val2/2)); + if (short(_mm_movemask_epi8(cmp)) >> val1 != short(-1)) + return false; + + counter = 8 - val2/2; + len -= 8 - val2/2; + } else if (!val1) { + // p1 is already aligned + qSwap(p1, p2); + } + } + + // p2 is aligned now + // we want to use palignr in the mis-alignment of p1 + __m128i *m1 = (__m128i *)(quintptr(p1 + counter) & ~0xf); + __m128i *m2 = (__m128i *)(p2 + counter); + register int val1 = quintptr(p1 + counter) - quintptr(m1); + + // val1 contains the number of extra bytes + if (val1 == 8) + return equals2_ssse3_aligning_alignr<8>(m1, m2, len); + if (val1 == 0) + return equals2_sse2_aligned(p1 + counter, p2 + counter, len); + if (val1 < 8) { + if (val1 < 4) { + return equals2_ssse3_aligning_alignr<2>(m1, m2, len); + } else { + if (val1 == 4) + return equals2_ssse3_aligning_alignr<4>(m1, m2, len); + else // diff == 6 + return equals2_ssse3_aligning_alignr<6>(m1, m2, len); + } + } else { + if (val1 < 12) { + return equals2_ssse3_aligning_alignr<10>(m1, m2, len); + } else { + if (val1 == 12) + return equals2_ssse3_aligning_alignr<12>(m1, m2, len); + else // diff == 14 + return equals2_ssse3_aligning_alignr<14>(m1, m2, len); + } + } +} + +#ifdef __SSE4_1__ +static bool equals2_sse4(const ushort *p1, const ushort *p2, int len) { // We use the pcmpestrm instruction searching for differences (negative polarity) // it will reset CF if it's all equal @@ -390,36 +589,150 @@ static bool equals2_sse4(ushort *p1, ushort *p2, int len) // difference found: CF = 1 // all equal, not finished: CF = ZF = SF = 0 // all equal, finished: CF = 0, ZF = SF = 1 + // We use the JA instruction that jumps if ZF = 0 and CF = 0 + if (p1 == p2 || !len) + return true; + + // This function may read some bytes past the end of p1 or p2 + // It is safe to do that, as long as those extra bytes (beyond p1+len and p2+len) + // are on the same page as the last valid byte. + // If len is a multiple of 8, we'll never load invalid bytes. + if (len & 7) { + // The last load would load (len & ~7) valid bytes and (8 - (len & ~7)) invalid bytes. + // So we can't do the last load if any of those bytes is in a different + // page. That is, if: + // pX + len is on a different page from pX + (len & ~7) + 8 + // + // that is, if second-to-last load ended up less than 16 bytes from the page end: + // pX + (len & ~7) is the last ushort read in the second-to-last load + if (len < 8) + return equals2_short_tail(p1, p2, len); + if ((quintptr(p1 + (len & ~7)) & 0xfff) > 0xff0 || + (quintptr(p2 + (len & ~7)) & 0xfff) > 0xff0) { + + // yes, so we mustn't do the final 128-bit load + bool result; + asm ( + "sub %[p1], %[p2]\n\t" + "sub $16, %[p1]\n\t" + "add $8, %[len]\n\t" + + // main loop: + "0:\n\t" + "add $16, %[p1]\n\t" + "sub $8, %[len]\n\t" + "jz 1f\n\t" + "lddqu (%[p1]), %%xmm0\n\t" + "mov %[len], %%edx\n\t" + "pcmpestri %[mode], (%[p2],%[p1]), %%xmm0\n\t" + + "jna 1f\n\t" + "add $16, %[p1]\n\t" + "sub $8, %[len]\n\t" + "jz 1f\n\t" + "lddqu (%[p1]), %%xmm0\n\t" + "mov %[len], %%edx\n\t" + "pcmpestri %[mode], (%[p2],%[p1]), %%xmm0\n\t" + + "ja 0b\n\t" + "1:\n\t" + "setnc %[result]\n\t" + : [result] "=a" (result), + [p1] "+r" (p1), + [p2] "+r" (p2) + : [len] "0" (len & ~7), + [mode] "i" (_SIDD_UWORD_OPS | _SIDD_CMP_EQUAL_EACH | _SIDD_NEGATIVE_POLARITY) + : "%edx", "%ecx", "%xmm0" + ); + return result && equals2_short_tail(p1, (const ushort *)(quintptr(p1) + quintptr(p2)), len & 7); + } + } + +// const qptrdiff disp = p2 - p1; +// p1 -= 8; +// len += 8; +// while (true) { +// enum { Mode = _SIDD_UWORD_OPS | _SIDD_CMP_EQUAL_EACH | _SIDD_NEGATIVE_POLARITY }; + +// p1 += 8; +// len -= 8; +// if (!len) +// return true; + +// __m128i q1 = _mm_lddqu_si128((__m128i *)(p1 + disp)); +// __m128i *m2 = (__m128i *)p1; + +// bool cmp_a = _mm_cmpestra(q1, len, *m2, len, Mode); +// if (cmp_a) +// continue; +// return !_mm_cmpestrc(q1, len, *m2, len, Mode); +// } +// return true; bool result; asm ( - "movd %%ebx, %%xmm1\n\t" "sub %[p1], %[p2]\n\t" - "mov %[p1], %%ebx\n\t" - "sub $16, %%ebx\n\t" + "sub $16, %[p1]\n\t" "add $8, %[len]\n\t" - "0:\n\t" - "add $16, %%ebx\n\t" + + "0:\n\t" + "add $16, %[p1]\n\t" "sub $8, %[len]\n\t" - "movdqu (%%ebx), %%xmm0\n\t" + "jz 1f\n\t" + "lddqu (%[p2],%[p1]), %%xmm0\n\t" "mov %[len], %%edx\n\t" - "pcmpestrm %[mode], (%[p2],%%ebx), %%xmm0\n\t" + "pcmpestri %[mode], (%[p1]), %%xmm0\n\t" + + "jna 1f\n\t" + "add $16, %[p1]\n\t" + "sub $8, %[len]\n\t" + "jz 1f\n\t" + "lddqu (%[p2],%[p1]), %%xmm0\n\t" + "mov %[len], %%edx\n\t" + "pcmpestri %[mode], (%[p1]), %%xmm0\n\t" + "ja 0b\n\t" - "1:\n\t" - "mov $0, %%eax\n\t" - "setnc %%al\n\t" - "movd %%xmm1, %%ebx\n\t" + + "1:\n\t" + "setnc %[result]\n\t" : [result] "=a" (result) : [len] "0" (len), - [p1] "d" (p1), + [p1] "r" (p1), [p2] "r" (p2), - [mode] "K" (_SIDD_UWORD_OPS | _SIDD_CMP_EQUAL_EACH | _SIDD_NEGATIVE_POLARITY) - : "%xmm0", "%xmm1" + [mode] "i" (_SIDD_UWORD_OPS | _SIDD_CMP_EQUAL_EACH | _SIDD_NEGATIVE_POLARITY) + : "%edx", "%ecx", "%xmm0" ); return result; } -//#endif + +#endif +#endif +#endif #endif +typedef bool (* FuncPtr)(const ushort *, const ushort *, int); +static const FuncPtr func[] = { + equals2_memcmp_call, // 0 + equals2_bytewise, // 1 + equals2_shortwise, // 1 + equals2_intwise, // 3 +#ifdef __SSE2__ + equals2_sse2, // 4 + equals2_sse2_aligning, // 5 +#ifdef __SSE3__ + equals2_sse3, // 6 +#ifdef __SSSE3__ + equals2_ssse3, // 7 + equals2_ssse3, // 8 +#ifdef __SSE4_1__ + equals2_sse4, // 9 +#endif +#endif +#endif +#endif + 0 +}; +static const int functionCount = sizeof(func)/sizeof(func[0]) - 1; + void tst_QString::equals2_data() const { QTest::addColumn("algorithm"); @@ -431,108 +744,94 @@ void tst_QString::equals2_data() const #ifdef __SSE2__ QTest::newRow("sse2") << 4; QTest::newRow("sse2_aligning") << 5; +#ifdef __SSE3__ + QTest::newRow("sse3") << 6; #ifdef __SSSE3__ - QTest::newRow("ssse3") << 6; + QTest::newRow("ssse3") << 7; + QTest::newRow("ssse3_aligning") << 8; #ifdef __SSE4_1__ - QTest::newRow("sse4.2") << 7; + QTest::newRow("sse4.2") << 9; +#endif #endif #endif #endif } -void tst_QString::equals2() const +static void __attribute__((noinline)) equals2_selftest() { - static const short positions[] = { - 190, 1719, 2149, 1752, - 158, 244, 365, 1117, - 254, 265, 1047, 1785, - 1435, 552, 1476, 2030, - // 16 - 421, 1840, 2209, 232, - 1389, 907, 1500, 1479, - 1152, 541, 655, 1960, - 1642, 299, 740, 1995, - // 32 - 1946, 1407, 1272, 1946, - 1459, 1851, 1717, 1484, - 1761, 1630, 1377, 1675, - 629, 341, 661, 244 - // 48 - }; - // the length list must not contain 0 - static const int lens[] = { - 11, // 0 - 40, - 28, - 38, - 9, - 52, // 5 - 48, - 38, - 29, - 7, - 2, // 10 - 49, - 41, - 5, - 20, - 62 // 15 +#ifdef Q_OS_UNIX + const long pagesize = sysconf(_SC_PAGESIZE); + void *page1, *page3; + ushort *page2; + page1 = mmap(0, pagesize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + page2 = (ushort *)mmap(0, pagesize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_POPULATE, -1, 0); + page3 = mmap(0, pagesize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + + Q_ASSERT(quintptr(page2) == quintptr(page1) + pagesize || quintptr(page2) == quintptr(page1) - pagesize); + Q_ASSERT(quintptr(page3) == quintptr(page2) + pagesize || quintptr(page3) == quintptr(page2) - pagesize); + munmap(page1, pagesize); + munmap(page3, pagesize); + + // populate our page + for (uint i = 0; i < pagesize / sizeof(long long); ++i) + ((long long *)page2)[i] = Q_INT64_C(0x0041004100410041); + + // the following should crash: + //page2[-1] = 0xdead; + //page2[pagesize / sizeof(ushort) + 1] = 0xbeef; + + static const ushort needle[] = { + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41 }; - typedef bool (* FuncPtr)(ushort *, ushort *, int); - static const FuncPtr func[] = { - equals2_memcmp_call, // 0 - equals2_bytewise, // 1 - equals2_shortwise, // 1 - equals2_intwise, // 3 -#ifdef __SSE2__ - equals2_sse2, // 4 - equals2_sse2_aligning, // 5 -#ifdef __SSSE3__ - equals2_ssse3, // 6 -#ifdef __SSE4_1__ - equals2_sse4, // 7 -#endif -#endif + for (int algo = 0; algo < functionCount; ++algo) { + // boundary condition test: + for (int i = 0; i < 8; ++i) { + (func[algo])(page2 + i, needle, sizeof needle / 2); + (func[algo])(page2 - i - 1 - sizeof(needle)/2 + pagesize/2, needle, sizeof needle/2); + } + } + + munmap(page2, pagesize); #endif - 0 - }; + for (int algo = 0; algo < functionCount; ++algo) { + for (int i = 0; i < stringCollectionCount; ++i) { + const ushort *p1 = stringCollectionData + stringCollection[i].offset1; + const ushort *p2 = stringCollectionData + stringCollection[i].offset2; + bool expected = memcmp(p1, p2, stringCollection[i].len * 2) == 0; + + bool result = (func[algo])(p1, p2, stringCollection[i].len); + if (expected != result) + qWarning().nospace() + << "algo=" << algo + << " i=" << i + << " failed (" << result << "!=" << expected + << "); strings were " + << QByteArray((char*)p1, stringCollection[i].len).toHex() + << " and " + << QByteArray((char*)p2, stringCollection[i].len).toHex(); + } + } +} + +void tst_QString::equals2() const +{ QFETCH(int, algorithm); if (algorithm == -1) { - for (uint pos1 = 0; pos1 < sizeof positions / sizeof positions[0]; ++pos1) - for (uint pos2 = 0; pos2 < (sizeof positions / sizeof positions[0]) - 32; ++pos2) - for (uint len = 0; len < sizeof lens / sizeof lens[0]; ++len) { - ushort *p1 = databuffer + positions[pos1]; - ushort *p2 = databuffer + positions[pos2]; - bool expected = memcmp(p1, p2, lens[len] * 2) == 0; - - for (uint algo = 0; algo < -1 + (sizeof func / sizeof func[0]); ++algo) { - bool result = (func[algo])(p1, p2, lens[len]); - if (expected != result) - qWarning().nospace() - << "algo=" << algo - << " pos1=" << positions[pos1] - << " pos2=" << positions[pos2] - << " len=" << lens[len] - << " failed (" << result << "!=" << expected - << "); strings were " - << QByteArray((char*)p1, lens[len]).toHex() - << " and " - << QByteArray((char*)p2, lens[len]).toHex(); - } - - } + equals2_selftest(); return; } QBENCHMARK { - for (uint pos1 = 0; pos1 < sizeof positions / sizeof positions[0]; ++pos1) - for (uint pos2 = 0; pos2 < (sizeof positions / sizeof positions[0]) - 32; ++pos2) - for (uint len = 0; len < sizeof lens / sizeof lens[0]; ++len) { - bool result = (func[algorithm])(databuffer + positions[pos1], databuffer + positions[pos2], lens[len]); - Q_UNUSED(result); - } + for (int i = 0; i < stringCollectionCount; ++i) { + const ushort *p1 = stringCollectionData + stringCollection[i].offset1; + const ushort *p2 = stringCollectionData + stringCollection[i].offset2; + bool result = (func[algorithm])(p1, p2, stringCollection[i].len); + Q_UNUSED(result); + } } } -- cgit v0.12 From 8063e04f3bf6e46ec972b6cafea39454a47e16de Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Tue, 17 Aug 2010 20:34:54 +0200 Subject: Update comments in QString about alignment performance. This commit makes no code change at all. Write down the conclusions from experimenting with the x86 SIMD instructions for faster string comparison routines. Long story short: we're already pretty good. The SSE4.2 string instructions are probably more useful for "implicit-length mode" (that is, the end of the string is marked by a NUL), rather than QString's "explicit-length mode". --- src/corelib/tools/qstring.cpp | 63 ++++++++++++++++++++++++++++++++----------- src/corelib/tools/qstring.h | 1 + 2 files changed, 49 insertions(+), 15 deletions(-) diff --git a/src/corelib/tools/qstring.cpp b/src/corelib/tools/qstring.cpp index 2fd9a0b..d940bf8 100644 --- a/src/corelib/tools/qstring.cpp +++ b/src/corelib/tools/qstring.cpp @@ -173,7 +173,7 @@ static int ucstricmp(const ushort *a, const ushort *ae, const uchar *b) return 1; } -// Unicode case-insensitive comparison +// Unicode case-sensitive comparison static int ucstrcmp(const QChar *a, int alen, const QChar *b, int blen) { if (a == b && alen == blen) @@ -202,22 +202,55 @@ static int ucstrnicmp(const ushort *a, const ushort *b, int l) return ucstricmp(a, a + l, b, b + l); } +// Benchmarking indicates that doing memcmp is much slower than +// executing the comparison ourselves. +// +// The profiling was done on a population of calls to qMemEquals, generated +// during a run of the demo browser. The profile of the data (32-bit x86 +// Linux) was: +// +// total number of comparisons: 21353 +// longest string compared: 95 +// average comparison length: 14.8786 +// cache-line crosses: 5661 (13.3%) +// alignment histogram: +// 0xXXX0 = 512 (1.2%) strings, 0 (0.0%) of which same-aligned +// 0xXXX2 = 15087 (35.3%) strings, 5145 (34.1%) of which same-aligned +// 0xXXX4 = 525 (1.2%) strings, 0 (0.0%) of which same-aligned +// 0xXXX6 = 557 (1.3%) strings, 6 (1.1%) of which same-aligned +// 0xXXX8 = 509 (1.2%) strings, 0 (0.0%) of which same-aligned +// 0xXXXa = 24358 (57.0%) strings, 9901 (40.6%) of which same-aligned +// 0xXXXc = 557 (1.3%) strings, 0 (0.0%) of which same-aligned +// 0xXXXe = 601 (1.4%) strings, 15 (2.5%) of which same-aligned +// total = 42706 (100%) strings, 15067 (35.3%) of which same-aligned +// +// 92% of the strings have alignment of 2 or 10, which is due to malloc on +// 32-bit Linux returning values aligned to 8 bytes, and offsetof(array, QString::Data) == 18. +// +// The profile on 64-bit will be different since offsetof(array, QString::Data) == 26. +// +// The benchmark results were, for a Core-i7 @ 2.67 GHz 32-bit, compiled with -O3 -funroll-loops: +// 16-bit loads only: 872,301 CPU ticks [Qt 4.5 / memcmp] +// 32- and 16-bit loads: 773,362 CPU ticks [Qt 4.6] +// SSE2 "movdqu" 128-bit loads: 618,736 CPU ticks +// SSE3 "lddqu" 128-bit loads: 619,954 CPU ticks +// SSSE3 "palignr" corrections: 852,147 CPU ticks +// SSE4.2 "pcmpestrm": 738,702 CPU ticks +// +// The same benchmark on an Atom N450 @ 1.66 GHz, is: +// 16-bit loads only: 2,185,882 CPU ticks +// 32- and 16-bit loads: 1,805,060 CPU ticks +// SSE2 "movdqu" 128-bit loads: 2,529,843 CPU ticks +// SSE3 "lddqu" 128-bit loads: 2,514,858 CPU ticks +// SSSE3 "palignr" corrections: 2,160,325 CPU ticks +// SSE4.2 not available +// +// The conclusion we reach is that alignment the SSE2 unaligned code can gain +// 20% improvement in performance in some systems, but suffers a penalty due +// to the unaligned loads on others. + static bool qMemEquals(const quint16 *a, const quint16 *b, int length) { - // Benchmarking indicates that doing memcmp is much slower than - // executing the comparison ourselves. - // To make it even faster, we do a 32-bit comparison, comparing - // twice the amount of data as a normal word-by-word comparison. - // - // Benchmarking results on a 2.33 GHz Core2 Duo, with a 64-QChar - // block of data, with 4194304 iterations (per iteration): - // operation usec cpu ticks - // memcmp 330 710 - // 16-bit 79 167-171 - // 32-bit aligned 49 105-109 - // - // Testing also indicates that unaligned 32-bit loads are as - // performant as 32-bit aligned. if (a == b || !length) return true; diff --git a/src/corelib/tools/qstring.h b/src/corelib/tools/qstring.h index e52f59f..06e4d47 100644 --- a/src/corelib/tools/qstring.h +++ b/src/corelib/tools/qstring.h @@ -614,6 +614,7 @@ private: ushort asciiCache : 1; ushort capacity : 1; ushort reserved : 11; + // ### Qt5: try to ensure that "array" is aligned to 16 bytes on both 32- and 64-bit ushort array[1]; }; static Data shared_null; -- cgit v0.12 From d28522a1b0e2d1170751b2c559d13e6c96a2a54c Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Tue, 17 Aug 2010 22:47:32 +0200 Subject: Update the data generation script to use a non-including .cpp This speeds up the writing of algorithms, so I don't have to recompile megabytes of data dumps. --- tests/benchmarks/corelib/tools/qstring/data.h | 12 ++++++++++++ .../corelib/tools/qstring/generatelist.pl | 21 +++++++++------------ tests/benchmarks/corelib/tools/qstring/main.cpp | 2 +- tests/benchmarks/corelib/tools/qstring/qstring.pro | 2 +- 4 files changed, 23 insertions(+), 14 deletions(-) create mode 100644 tests/benchmarks/corelib/tools/qstring/data.h diff --git a/tests/benchmarks/corelib/tools/qstring/data.h b/tests/benchmarks/corelib/tools/qstring/data.h new file mode 100644 index 0000000..a23dae3 --- /dev/null +++ b/tests/benchmarks/corelib/tools/qstring/data.h @@ -0,0 +1,12 @@ +#include + +struct StringCollection +{ + int len; + int offset1, offset2; + ushort align1, align2; +}; + +extern const ushort stringCollectionData[]; +extern StringCollection stringCollection[]; +extern const int stringCollectionCount; diff --git a/tests/benchmarks/corelib/tools/qstring/generatelist.pl b/tests/benchmarks/corelib/tools/qstring/generatelist.pl index ed4c8eb..2777329 100644 --- a/tests/benchmarks/corelib/tools/qstring/generatelist.pl +++ b/tests/benchmarks/corelib/tools/qstring/generatelist.pl @@ -51,10 +51,10 @@ # the second data # \n newline # -# The C code to write this data would be: +# The code to write this data would be: # fprintf(out, "LEN = %d %s %d %d\n", len, -# (p1 == p2) : "SAME" : "DIFF", -# (int)p1 & 0xfff, (int)p2 & 0xfff); +# (p1 == p2) ? "SAME" : "DIFF", +# uint(quintptr(p1)) & 0xfff, uint(quintptr(p2)) & 0xfff); # fwrite(p1, 2, len, out); # fwrite(p2, 2, len, out); # fwrite("\n", 1, 1, out); @@ -103,7 +103,9 @@ sub printUshortArray($$$) { return ($offset + $headpadding, $offset + $headpadding + $len + $tailpadding); } -print "static const ushort stringCollectionData[] __attribute__((aligned(16))) = { \n"; +print "#include \"data.h\"\n\n"; + +print "const ushort stringCollectionData[] __attribute__((aligned(64))) = { \n"; $count = 0; $offset = 0; $totalsize = 0; @@ -160,12 +162,7 @@ while (1) { print "\n};\n"; close IN; -print "static struct StringCollection\n"; -print "{\n"; -print " int len;\n"; -print " int offset1, offset2;\n"; -print " ushort align1, align2;\n"; -print "} stringCollection[] = {\n"; +print "struct StringCollection stringCollection[] = {\n"; for $i (0..$count-1) { print " {", @@ -181,8 +178,8 @@ for $i (0..$count-1) { } print "};\n"; -print "static const int stringCollectionCount = $count;\n"; -print "static const int stringCollectionMaxLen = $maxlen;\n"; +print "const int stringCollectionCount = $count;\n"; +print "const int stringCollectionMaxLen = $maxlen;\n"; printf "// average comparison length: %.4f\n", ($totalsize * 1.0 / $count); printf "// cache-line crosses: %d (%.1f%%)\n", $cachelinecrosses, ($cachelinecrosses * 100.0 / $count / 2); diff --git a/tests/benchmarks/corelib/tools/qstring/main.cpp b/tests/benchmarks/corelib/tools/qstring/main.cpp index 88dc40b..a23244d 100644 --- a/tests/benchmarks/corelib/tools/qstring/main.cpp +++ b/tests/benchmarks/corelib/tools/qstring/main.cpp @@ -55,7 +55,7 @@ #include -#include "data.cpp" +#include "data.h" class tst_QString: public QObject { diff --git a/tests/benchmarks/corelib/tools/qstring/qstring.pro b/tests/benchmarks/corelib/tools/qstring/qstring.pro index 44fb46b..e8720e1 100644 --- a/tests/benchmarks/corelib/tools/qstring/qstring.pro +++ b/tests/benchmarks/corelib/tools/qstring/qstring.pro @@ -1,7 +1,7 @@ load(qttest_p4) TARGET = tst_bench_qstring QT -= gui -SOURCES += main.cpp +SOURCES += main.cpp data.cpp wince*:{ DEFINES += SRCDIR=\\\"\\\" -- cgit v0.12 From 47b98097ac26de6153c7a4894aaa110133e478dc Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Tue, 17 Aug 2010 23:52:07 +0200 Subject: Add the ucstrncmp benchmarks --- tests/benchmarks/corelib/tools/qstring/main.cpp | 136 ++++++++++++++++++++++++ 1 file changed, 136 insertions(+) diff --git a/tests/benchmarks/corelib/tools/qstring/main.cpp b/tests/benchmarks/corelib/tools/qstring/main.cpp index a23244d..3d88756 100644 --- a/tests/benchmarks/corelib/tools/qstring/main.cpp +++ b/tests/benchmarks/corelib/tools/qstring/main.cpp @@ -67,6 +67,8 @@ private slots: void equals_data() const; void equals2_data() const; void equals2() const; + void ucstrncmp_data() const; + void ucstrncmp() const; void fromUtf8() const; }; @@ -835,6 +837,140 @@ void tst_QString::equals2() const } } +static int ucstrncmp_shortwise(const ushort *a, const ushort *b, int l) +{ + while (l-- && *a == *b) + a++,b++; + if (l==-1) + return 0; + return *a - *b; +} + +static int ucstrncmp_intwise(const ushort *a, const ushort *b, int len) +{ + // do both strings have the same alignment? + if ((quintptr(a) & 2) == (quintptr(b) & 2)) { + // are we aligned to 4 bytes? + if (quintptr(a) & 2) { + if (*a != *b) + return *a - *b; + ++a; + ++b; + --len; + } + + const uint *p1 = (const uint *)a; + const uint *p2 = (const uint *)b; + quintptr counter = 0; + for ( ; len > 1 ; len -= 2, ++counter) { + if (p1[counter] != p2[counter]) { + // which ushort isn't equal? + int diff = a[2*counter] - b[2*counter]; + return diff ? diff : a[2*counter + 1] - b[2*counter + 1]; + } + } + + return len ? a[2*counter] - b[2*counter] : 0; + } else { + while (len-- && *a == *b) + a++,b++; + if (len==-1) + return 0; + return *a - *b; + } +} + +typedef int (* UcstrncmpFunction)(const ushort *, const ushort *, int); +Q_DECLARE_METATYPE(UcstrncmpFunction) + +void tst_QString::ucstrncmp_data() const +{ + QTest::addColumn("function"); + QTest::newRow("selftest") << UcstrncmpFunction(0); + QTest::newRow("shortwise") << &ucstrncmp_shortwise; + QTest::newRow("intwise") << &ucstrncmp_intwise; +} + +void tst_QString::ucstrncmp() const +{ + QFETCH(UcstrncmpFunction, function); + if (!function) { + static const UcstrncmpFunction func[] = { + &ucstrncmp_shortwise, + &ucstrncmp_intwise + }; + static const int functionCount = sizeof func / sizeof func[0]; + +#ifdef Q_OS_UNIX + const long pagesize = sysconf(_SC_PAGESIZE); + void *page1, *page3; + ushort *page2; + page1 = mmap(0, pagesize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + page2 = (ushort *)mmap(0, pagesize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_POPULATE, -1, 0); + page3 = mmap(0, pagesize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + + Q_ASSERT(quintptr(page2) == quintptr(page1) + pagesize || quintptr(page2) == quintptr(page1) - pagesize); + Q_ASSERT(quintptr(page3) == quintptr(page2) + pagesize || quintptr(page3) == quintptr(page2) - pagesize); + munmap(page1, pagesize); + munmap(page3, pagesize); + + // populate our page + for (uint i = 0; i < pagesize / sizeof(long long); ++i) + ((long long *)page2)[i] = Q_INT64_C(0x0041004100410041); + + // the following should crash: + //page2[-1] = 0xdead; + //page2[pagesize / sizeof(ushort) + 1] = 0xbeef; + + static const ushort needle[] = { + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41 + }; + + for (int algo = 0; algo < functionCount; ++algo) { + // boundary condition test: + for (int i = 0; i < 8; ++i) { + (func[algo])(page2 + i, needle, sizeof needle / 2); + (func[algo])(page2 - i - 1 - sizeof(needle)/2 + pagesize/2, needle, sizeof needle/2); + } + } + + munmap(page2, pagesize); +#endif + + for (int algo = 0; algo < functionCount; ++algo) { + for (int i = 0; i < stringCollectionCount; ++i) { + const ushort *p1 = stringCollectionData + stringCollection[i].offset1; + const ushort *p2 = stringCollectionData + stringCollection[i].offset2; + int expected = ucstrncmp_shortwise(p1, p2, stringCollection[i].len); + expected = qBound(-1, expected, 1); + + int result = (func[algo])(p1, p2, stringCollection[i].len); + result = qBound(-1, result, 1); + if (expected != result) + qWarning().nospace() + << "algo=" << algo + << " i=" << i + << " failed (" << result << "!=" << expected + << "); strings were " + << QByteArray((char*)p1, stringCollection[i].len).toHex() + << " and " + << QByteArray((char*)p2, stringCollection[i].len).toHex(); + } + } + return; + } + + QBENCHMARK { + for (int i = 0; i < stringCollectionCount; ++i) { + const ushort *p1 = stringCollectionData + stringCollection[i].offset1; + const ushort *p2 = stringCollectionData + stringCollection[i].offset2; + (function)(p1, p2, stringCollection[i].len); + } + } +} + void tst_QString::fromUtf8() const { QFile file(SRCDIR "utf-8.txt"); -- cgit v0.12 From 2bd9d7fbec0bb61298ba0f48a93a4a186b558a38 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Wed, 18 Aug 2010 10:52:27 +0200 Subject: Add an SSE2-optimised version of ucstrncmp First results make it 34% faster than current ucstrncmp, 16% faster than the 32-bit version. --- tests/benchmarks/corelib/tools/qstring/main.cpp | 39 ++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/tests/benchmarks/corelib/tools/qstring/main.cpp b/tests/benchmarks/corelib/tools/qstring/main.cpp index 3d88756..f338e49 100644 --- a/tests/benchmarks/corelib/tools/qstring/main.cpp +++ b/tests/benchmarks/corelib/tools/qstring/main.cpp @@ -880,6 +880,41 @@ static int ucstrncmp_intwise(const ushort *a, const ushort *b, int len) } } +#ifdef __SSE2__ +static inline int bsf_nonzero(register long val) +{ + int result; +# ifdef Q_CC_GNU + // returns the first non-zero bit on a non-zero reg + asm ("bsf %1, %0" : "=r" (result) : "r" (val)); + return result; +# elif defined(Q_CC_MSVC) + _BitScanForward(&result, val); + return result; +# endif +} + +static __attribute__((optimize("no-unroll-loops"))) int ucstrncmp_sse2(const ushort *a, const ushort *b, int len) +{ + qptrdiff counter = 0; + while (len >= 8) { + __m128i m1 = _mm_loadu_si128((__m128i *)(a + counter)); + __m128i m2 = _mm_loadu_si128((__m128i *)(b + counter)); + __m128i cmp = _mm_cmpeq_epi16(m1, m2); + ushort mask = ~uint(_mm_movemask_epi8(cmp)); + if (mask) { + // which ushort isn't equal? + counter += bsf_nonzero(mask)/2; + return a[counter] - b[counter]; + } + + counter += 8; + len -= 8; + } + return ucstrncmp_shortwise(a + counter, b + counter, len); +} +#endif + typedef int (* UcstrncmpFunction)(const ushort *, const ushort *, int); Q_DECLARE_METATYPE(UcstrncmpFunction) @@ -889,6 +924,7 @@ void tst_QString::ucstrncmp_data() const QTest::newRow("selftest") << UcstrncmpFunction(0); QTest::newRow("shortwise") << &ucstrncmp_shortwise; QTest::newRow("intwise") << &ucstrncmp_intwise; + QTest::newRow("sse2") << &ucstrncmp_sse2; } void tst_QString::ucstrncmp() const @@ -897,7 +933,8 @@ void tst_QString::ucstrncmp() const if (!function) { static const UcstrncmpFunction func[] = { &ucstrncmp_shortwise, - &ucstrncmp_intwise + &ucstrncmp_intwise, + &ucstrncmp_sse2 }; static const int functionCount = sizeof func / sizeof func[0]; -- cgit v0.12 From 6f913f94c6b6aaf8514bc62d4f9939ac44e211fb Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Wed, 18 Aug 2010 11:07:51 +0200 Subject: Add a version of ucstrncmp with SSE2 with aligning. This is a different technique of aligning. Instead of reading some bytes before the string, we will read some bytes of the string twice. Best results are only 2% improvement over the unaligned SSE2 on a Core-i7. --- tests/benchmarks/corelib/tools/qstring/main.cpp | 44 ++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/tests/benchmarks/corelib/tools/qstring/main.cpp b/tests/benchmarks/corelib/tools/qstring/main.cpp index f338e49..608e2bc 100644 --- a/tests/benchmarks/corelib/tools/qstring/main.cpp +++ b/tests/benchmarks/corelib/tools/qstring/main.cpp @@ -913,6 +913,46 @@ static __attribute__((optimize("no-unroll-loops"))) int ucstrncmp_sse2(const ush } return ucstrncmp_shortwise(a + counter, b + counter, len); } + +static __attribute__((optimize("no-unroll-loops"))) int ucstrncmp_sse2_aligning(const ushort *a, const ushort *b, int len) +{ + if (len >= 8) { + __m128i m1 = _mm_loadu_si128((__m128i *)a); + __m128i m2 = _mm_loadu_si128((__m128i *)b); + __m128i cmp = _mm_cmpeq_epi16(m1, m2); + ushort mask = ~uint(_mm_movemask_epi8(cmp)); + if (mask) { + // which ushort isn't equal? + int counter = bsf_nonzero(mask)/2; + return a[counter] - b[counter]; + } + + + // now align to do 16-byte loads + int diff = 8 - (quintptr(a) & 0xf)/2; + len -= diff; + a += diff; + b += diff; + } + + qptrdiff counter = 0; + while (len >= 8) { + __m128i m1 = _mm_load_si128((__m128i *)(a + counter)); + __m128i m2 = _mm_loadu_si128((__m128i *)(b + counter)); + __m128i cmp = _mm_cmpeq_epi16(m1, m2); + ushort mask = ~uint(_mm_movemask_epi8(cmp)); + if (mask) { + // which ushort isn't equal? + counter += bsf_nonzero(mask)/2; + return a[counter] - b[counter]; + } + + counter += 8; + len -= 8; + } + return ucstrncmp_shortwise(a + counter, b + counter, len); +} + #endif typedef int (* UcstrncmpFunction)(const ushort *, const ushort *, int); @@ -925,6 +965,7 @@ void tst_QString::ucstrncmp_data() const QTest::newRow("shortwise") << &ucstrncmp_shortwise; QTest::newRow("intwise") << &ucstrncmp_intwise; QTest::newRow("sse2") << &ucstrncmp_sse2; + QTest::newRow("sse2_aligning") << &ucstrncmp_sse2_aligning; } void tst_QString::ucstrncmp() const @@ -934,7 +975,8 @@ void tst_QString::ucstrncmp() const static const UcstrncmpFunction func[] = { &ucstrncmp_shortwise, &ucstrncmp_intwise, - &ucstrncmp_sse2 + &ucstrncmp_sse2, + &ucstrncmp_sse2_aligning }; static const int functionCount = sizeof func / sizeof func[0]; -- cgit v0.12 From 6cea948a0ceabe5493bb2a75f236b008b47fd71e Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Wed, 18 Aug 2010 12:26:36 +0200 Subject: Optimise the tail comparison of ucstrncmp --- tests/benchmarks/corelib/tools/qstring/main.cpp | 38 +++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/tests/benchmarks/corelib/tools/qstring/main.cpp b/tests/benchmarks/corelib/tools/qstring/main.cpp index 608e2bc..0b7254f 100644 --- a/tests/benchmarks/corelib/tools/qstring/main.cpp +++ b/tests/benchmarks/corelib/tools/qstring/main.cpp @@ -881,6 +881,40 @@ static int ucstrncmp_intwise(const ushort *a, const ushort *b, int len) } #ifdef __SSE2__ +static inline int ucstrncmp_short_tail(const ushort *p1, const ushort *p2, int len) +{ + if (len) { + if (*p1 != *p2) + return *p1 - *p2; + if (--len) { + if (p1[1] != p2[1]) + return p1[1] - p2[1]; + if (--len) { + if (p1[2] != p2[2]) + return p1[2] - p2[2]; + if (--len) { + if (p1[3] != p2[3]) + return p1[3] - p2[3]; + if (--len) { + if (p1[4] != p2[4]) + return p1[4] - p2[4]; + if (--len) { + if (p1[5] != p2[5]) + return p1[5] - p2[5]; + if (--len) { + if (p1[6] != p2[6]) + return p1[6] - p2[6]; + return p1[7] - p2[7]; + } + } + } + } + } + } + } + return 0; +} + static inline int bsf_nonzero(register long val) { int result; @@ -911,7 +945,7 @@ static __attribute__((optimize("no-unroll-loops"))) int ucstrncmp_sse2(const ush counter += 8; len -= 8; } - return ucstrncmp_shortwise(a + counter, b + counter, len); + return ucstrncmp_short_tail(a + counter, b + counter, len); } static __attribute__((optimize("no-unroll-loops"))) int ucstrncmp_sse2_aligning(const ushort *a, const ushort *b, int len) @@ -950,7 +984,7 @@ static __attribute__((optimize("no-unroll-loops"))) int ucstrncmp_sse2_aligning( counter += 8; len -= 8; } - return ucstrncmp_shortwise(a + counter, b + counter, len); + return ucstrncmp_short_tail(a + counter, b + counter, len); } #endif -- cgit v0.12 From 08fa99c43897b16f8be924090316f5a4db548c10 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Wed, 18 Aug 2010 12:26:53 +0200 Subject: Add an SSSE3 version of ucstrncmp --- tests/benchmarks/corelib/tools/qstring/main.cpp | 80 ++++++++++++++++++++++++- 1 file changed, 79 insertions(+), 1 deletion(-) diff --git a/tests/benchmarks/corelib/tools/qstring/main.cpp b/tests/benchmarks/corelib/tools/qstring/main.cpp index 0b7254f..3c3d1ad 100644 --- a/tests/benchmarks/corelib/tools/qstring/main.cpp +++ b/tests/benchmarks/corelib/tools/qstring/main.cpp @@ -987,6 +987,82 @@ static __attribute__((optimize("no-unroll-loops"))) int ucstrncmp_sse2_aligning( return ucstrncmp_short_tail(a + counter, b + counter, len); } +static __attribute__((optimize("no-unroll-loops"))) int ucstrncmp_sse2_aligned(const ushort *a, const ushort *b, int len) +{ + qptrdiff counter = 0; + while (len >= 8) { + __m128i m1 = _mm_load_si128((__m128i *)(a + counter)); + __m128i m2 = _mm_load_si128((__m128i *)(b + counter)); + __m128i cmp = _mm_cmpeq_epi16(m1, m2); + ushort mask = ~uint(_mm_movemask_epi8(cmp)); + if (mask) { + // which ushort isn't equal? + counter += bsf_nonzero(mask)/2; + return a[counter] - b[counter]; + } + + counter += 8; + len -= 8; + } + return ucstrncmp_short_tail(a + counter, b + counter, len); +} + +template static __attribute__((optimize("no-unroll-loops"))) int ucstrncmp_ssse3_alignr(const ushort *a, const ushort *b, int len) +{ + qptrdiff counter = 0; + __m128i lower, upper; + upper = _mm_load_si128((__m128i *)a); + + do { + lower = upper; + upper = _mm_load_si128((__m128i *)(a + counter) + 1); + __m128i merged = _mm_alignr_epi8(upper, lower, N); + + __m128i m2 = _mm_lddqu_si128((__m128i *)(b + counter)); + __m128i cmp = _mm_cmpeq_epi16(merged, m2); + ushort mask = ~uint(_mm_movemask_epi8(cmp)); + if (mask) { + // which ushort isn't equal? + counter += bsf_nonzero(mask)/2; + return a[counter + N/2] - b[counter]; + } + + counter += 8; + len -= 8; + } while (len >= 8); + + return ucstrncmp_short_tail(a + counter + N/2, b + counter, len); +} + +static int ucstrncmp_ssse3(const ushort *a, const ushort *b, int len) +{ + if (len >= 8) { + int val = quintptr(a) & 0xf; + a -= val/2; + + if (val == 10) + return ucstrncmp_ssse3_alignr<10>(a, b, len); + else if (val == 2) + return ucstrncmp_ssse3_alignr<2>(a, b, len); + if (val < 8) { + if (val < 4) + return ucstrncmp_sse2_aligned(a, b, len); + else if (val == 4) + return ucstrncmp_ssse3_alignr<4>(a, b, len); + else + return ucstrncmp_ssse3_alignr<6>(a, b, len); + } else { + if (val < 12) + return ucstrncmp_ssse3_alignr<8>(a, b, len); + else if (val == 12) + return ucstrncmp_ssse3_alignr<12>(a, b, len); + else + return ucstrncmp_ssse3_alignr<14>(a, b, len); + } + } + return ucstrncmp_short_tail(a, b, len); +} + #endif typedef int (* UcstrncmpFunction)(const ushort *, const ushort *, int); @@ -1000,6 +1076,7 @@ void tst_QString::ucstrncmp_data() const QTest::newRow("intwise") << &ucstrncmp_intwise; QTest::newRow("sse2") << &ucstrncmp_sse2; QTest::newRow("sse2_aligning") << &ucstrncmp_sse2_aligning; + QTest::newRow("ssse3") << &ucstrncmp_ssse3; } void tst_QString::ucstrncmp() const @@ -1010,7 +1087,8 @@ void tst_QString::ucstrncmp() const &ucstrncmp_shortwise, &ucstrncmp_intwise, &ucstrncmp_sse2, - &ucstrncmp_sse2_aligning + &ucstrncmp_sse2_aligning, + &ucstrncmp_ssse3 }; static const int functionCount = sizeof func / sizeof func[0]; -- cgit v0.12 From 4f891889118d4bcc417382a0a646f3683c621b10 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Wed, 18 Aug 2010 12:36:07 +0200 Subject: Add an ucstrncmp that uses SSSE3 with aligning. The results on i7 are 32% improvement over current code, 13% improvement over 4-byte loads, 6% over the unaligned SSSE3 loads. However, it's about 2.5% slower than pure SSE2 code due to complexity. The results on Atom are 30% improvement over current code, 7% over 4-byte loads, 15% over pure unaligned SSE2 and 9% over unaligned SSSE3. --- tests/benchmarks/corelib/tools/qstring/main.cpp | 53 ++++++++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) diff --git a/tests/benchmarks/corelib/tools/qstring/main.cpp b/tests/benchmarks/corelib/tools/qstring/main.cpp index 3c3d1ad..d40b9bc 100644 --- a/tests/benchmarks/corelib/tools/qstring/main.cpp +++ b/tests/benchmarks/corelib/tools/qstring/main.cpp @@ -1063,6 +1063,55 @@ static int ucstrncmp_ssse3(const ushort *a, const ushort *b, int len) return ucstrncmp_short_tail(a, b, len); } +static int ucstrncmp_ssse3_aligning(const ushort *a, const ushort *b, int len) +{ + if (len >= 8) { + __m128i m1 = _mm_loadu_si128((__m128i *)a); + __m128i m2 = _mm_loadu_si128((__m128i *)b); + __m128i cmp = _mm_cmpeq_epi16(m1, m2); + ushort mask = ~uint(_mm_movemask_epi8(cmp)); + if (mask) { + // which ushort isn't equal? + int counter = bsf_nonzero(mask)/2; + return a[counter] - b[counter]; + } + + + // now 'b' align to do 16-byte loads + int diff = 8 - (quintptr(b) & 0xf)/2; + len -= diff; + a += diff; + b += diff; + } + + if (len < 8) + return ucstrncmp_short_tail(a, b, len); + + // 'b' is aligned + int val = quintptr(a) & 0xf; + a -= val/2; + + if (val == 8) + return ucstrncmp_ssse3_alignr<8>(a, b, len); + else if (val == 0) + return ucstrncmp_sse2_aligned(a, b, len); + if (val < 8) { + if (val < 4) + return ucstrncmp_ssse3_alignr<2>(a, b, len); + else if (val == 4) + return ucstrncmp_ssse3_alignr<4>(a, b, len); + else + return ucstrncmp_ssse3_alignr<6>(a, b, len); + } else { + if (val < 12) + return ucstrncmp_ssse3_alignr<10>(a, b, len); + else if (val == 12) + return ucstrncmp_ssse3_alignr<12>(a, b, len); + else + return ucstrncmp_ssse3_alignr<14>(a, b, len); + } +} + #endif typedef int (* UcstrncmpFunction)(const ushort *, const ushort *, int); @@ -1077,6 +1126,7 @@ void tst_QString::ucstrncmp_data() const QTest::newRow("sse2") << &ucstrncmp_sse2; QTest::newRow("sse2_aligning") << &ucstrncmp_sse2_aligning; QTest::newRow("ssse3") << &ucstrncmp_ssse3; + QTest::newRow("ssse3_aligning") << &ucstrncmp_ssse3_aligning; } void tst_QString::ucstrncmp() const @@ -1088,7 +1138,8 @@ void tst_QString::ucstrncmp() const &ucstrncmp_intwise, &ucstrncmp_sse2, &ucstrncmp_sse2_aligning, - &ucstrncmp_ssse3 + &ucstrncmp_ssse3, + &ucstrncmp_ssse3_aligning }; static const int functionCount = sizeof func / sizeof func[0]; -- cgit v0.12 From 5e8d8f82d38ce5a1b30d5d90ecb6bc096d52f4d8 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Wed, 18 Aug 2010 12:47:31 +0200 Subject: Update the SSSE3-with-alignment function to use aligned loads. This results in no change on the Core-i7, but another 2.6% on the Atom (so it's now 8% better than 4-byte loads and 31% better than current code) --- tests/benchmarks/corelib/tools/qstring/main.cpp | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/tests/benchmarks/corelib/tools/qstring/main.cpp b/tests/benchmarks/corelib/tools/qstring/main.cpp index d40b9bc..e11d92e 100644 --- a/tests/benchmarks/corelib/tools/qstring/main.cpp +++ b/tests/benchmarks/corelib/tools/qstring/main.cpp @@ -1007,7 +1007,9 @@ static __attribute__((optimize("no-unroll-loops"))) int ucstrncmp_sse2_aligned(c return ucstrncmp_short_tail(a + counter, b + counter, len); } -template static __attribute__((optimize("no-unroll-loops"))) int ucstrncmp_ssse3_alignr(const ushort *a, const ushort *b, int len) +typedef __m128i (* MMLoadFunction)(const __m128i *); +template +static inline __attribute__((optimize("no-unroll-loops"))) int ucstrncmp_ssse3_alignr(const ushort *a, const ushort *b, int len) { qptrdiff counter = 0; __m128i lower, upper; @@ -1018,7 +1020,7 @@ template static __attribute__((optimize("no-unroll-loops"))) int ucstrncm upper = _mm_load_si128((__m128i *)(a + counter) + 1); __m128i merged = _mm_alignr_epi8(upper, lower, N); - __m128i m2 = _mm_lddqu_si128((__m128i *)(b + counter)); + __m128i m2 = LoadFunction((__m128i *)(b + counter)); __m128i cmp = _mm_cmpeq_epi16(merged, m2); ushort mask = ~uint(_mm_movemask_epi8(cmp)); if (mask) { @@ -1092,23 +1094,23 @@ static int ucstrncmp_ssse3_aligning(const ushort *a, const ushort *b, int len) a -= val/2; if (val == 8) - return ucstrncmp_ssse3_alignr<8>(a, b, len); + return ucstrncmp_ssse3_alignr<8, _mm_load_si128>(a, b, len); else if (val == 0) return ucstrncmp_sse2_aligned(a, b, len); if (val < 8) { if (val < 4) - return ucstrncmp_ssse3_alignr<2>(a, b, len); + return ucstrncmp_ssse3_alignr<2, _mm_load_si128>(a, b, len); else if (val == 4) - return ucstrncmp_ssse3_alignr<4>(a, b, len); + return ucstrncmp_ssse3_alignr<4, _mm_load_si128>(a, b, len); else - return ucstrncmp_ssse3_alignr<6>(a, b, len); + return ucstrncmp_ssse3_alignr<6, _mm_load_si128>(a, b, len); } else { if (val < 12) - return ucstrncmp_ssse3_alignr<10>(a, b, len); + return ucstrncmp_ssse3_alignr<10, _mm_load_si128>(a, b, len); else if (val == 12) - return ucstrncmp_ssse3_alignr<12>(a, b, len); + return ucstrncmp_ssse3_alignr<12, _mm_load_si128>(a, b, len); else - return ucstrncmp_ssse3_alignr<14>(a, b, len); + return ucstrncmp_ssse3_alignr<14, _mm_load_si128>(a, b, len); } } -- cgit v0.12 From 637d94620c86172714ab11a258f6c5d4d02c272b Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Wed, 18 Aug 2010 13:59:58 +0200 Subject: Small fixup --- tests/benchmarks/corelib/tools/qstring/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/benchmarks/corelib/tools/qstring/main.cpp b/tests/benchmarks/corelib/tools/qstring/main.cpp index e11d92e..6f9c333 100644 --- a/tests/benchmarks/corelib/tools/qstring/main.cpp +++ b/tests/benchmarks/corelib/tools/qstring/main.cpp @@ -987,7 +987,7 @@ static __attribute__((optimize("no-unroll-loops"))) int ucstrncmp_sse2_aligning( return ucstrncmp_short_tail(a + counter, b + counter, len); } -static __attribute__((optimize("no-unroll-loops"))) int ucstrncmp_sse2_aligned(const ushort *a, const ushort *b, int len) +static inline __attribute__((optimize("no-unroll-loops"))) int ucstrncmp_sse2_aligned(const ushort *a, const ushort *b, int len) { qptrdiff counter = 0; while (len >= 8) { -- cgit v0.12 From 410d836b5b4f029e9bc08a0ed3304df2e4a944a5 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Thu, 19 Aug 2010 11:59:34 +0200 Subject: Add the beginnings of a new SSSE3-based aligning algorithm --- tests/benchmarks/corelib/tools/qstring/main.cpp | 84 ++++++++++++++++++++++++- 1 file changed, 83 insertions(+), 1 deletion(-) diff --git a/tests/benchmarks/corelib/tools/qstring/main.cpp b/tests/benchmarks/corelib/tools/qstring/main.cpp index 6f9c333..4c4d921 100644 --- a/tests/benchmarks/corelib/tools/qstring/main.cpp +++ b/tests/benchmarks/corelib/tools/qstring/main.cpp @@ -1114,6 +1114,86 @@ static int ucstrncmp_ssse3_aligning(const ushort *a, const ushort *b, int len) } } +static inline __attribute__((optimize("no-unroll-loops"))) +int ucstrncmp_ssse3_aligning2_aligned(const ushort *a, const ushort *b, int len) +{ + // len >= 8 + // align(b) == align(a) + + // round down the alignment so align(b) == align(a) == 0 + // calculate how many garbage bytes we'll read on the first load + // corresponds to how many bits we must ignore from movemask's result + int garbage = (quintptr(b) & 0xf); + a -= garbage / 2; + b -= garbage / 2; + + __m128i m1 = _mm_load_si128((const __m128i *)a); + __m128i m2 = _mm_load_si128((const __m128i *)b); + __m128i cmp = _mm_cmpeq_epi16(m1, m2); + int mask = short(_mm_movemask_epi8(cmp)); // force sign extension + mask >>= garbage; + if (~mask) { + // which ushort isn't equal? + int counter = (garbage + bsf_nonzero(~mask))/2; + return a[counter] - b[counter]; + } + + // the first 16-garbage bytes (8-garbage/2 ushorts) were equal + len -= 8 - garbage/2; + return ucstrncmp_sse2_aligned(a + 8, b + 8, len); +} + +template static inline __attribute__((optimize("no-unroll-loops"))) +int ucstrncmp_ssse3_aligning2_alignr(const ushort *a, const ushort *b, int len) +{ + return ucstrncmp_intwise(a, b, len); +} + +static int ucstrncmp_ssse3_aligning2(const ushort *a, const ushort *b, int len) +{ + // Different strategy from above: instead of doing two unaligned loads + // when trying to align, we'll only do aligned loads and round down the + // addresses of a and b. This means the first load will contain garbage + // in the beginning of the string, which we'll shift out of the way + // (after _mm_movemask_epi8) + + if (len < 16) + return ucstrncmp_intwise(a, b, len); + + // both a and b are misaligned + // we'll call the alignr function with the alignment *difference* between the two + int val = (quintptr(b) & 0xf) - (quintptr(a) & 0xf); + int sign = 1; + if (val < 0) { + val = -val; + qSwap(a, b); + sign = -1; + } + + // from this point on, b has the shortest alignment + // and align(a) = align(b) + val + + if (val == 8) + return ucstrncmp_ssse3_aligning2_alignr<8>(a, b, len) * sign; + else if (val == 0) + return ucstrncmp_ssse3_aligning2_aligned(a, b, len) * sign; + if (val < 8) { + if (val < 4) + return ucstrncmp_ssse3_aligning2_alignr<2>(a, b, len) * sign; + else if (val == 4) + return ucstrncmp_ssse3_aligning2_alignr<4>(a, b, len) * sign; + else + return ucstrncmp_ssse3_aligning2_alignr<6>(a, b, len) * sign; + } else { + if (val < 12) + return ucstrncmp_ssse3_aligning2_alignr<10>(a, b, len) * sign; + else if (val == 12) + return ucstrncmp_ssse3_aligning2_alignr<12>(a, b, len) * sign; + else + return ucstrncmp_ssse3_aligning2_alignr<14>(a, b, len) * sign; + } +} + #endif typedef int (* UcstrncmpFunction)(const ushort *, const ushort *, int); @@ -1129,6 +1209,7 @@ void tst_QString::ucstrncmp_data() const QTest::newRow("sse2_aligning") << &ucstrncmp_sse2_aligning; QTest::newRow("ssse3") << &ucstrncmp_ssse3; QTest::newRow("ssse3_aligning") << &ucstrncmp_ssse3_aligning; + QTest::newRow("ssse3_aligning2") << &ucstrncmp_ssse3_aligning2; } void tst_QString::ucstrncmp() const @@ -1141,7 +1222,8 @@ void tst_QString::ucstrncmp() const &ucstrncmp_sse2, &ucstrncmp_sse2_aligning, &ucstrncmp_ssse3, - &ucstrncmp_ssse3_aligning + &ucstrncmp_ssse3_aligning, + &ucstrncmp_ssse3_aligning2 }; static const int functionCount = sizeof func / sizeof func[0]; -- cgit v0.12 From 3cfd8330d5252d6ca9439882cb4a0f2246cccfc0 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Thu, 19 Aug 2010 15:09:49 +0200 Subject: Improve on the SSSE3 with alternate aligning function. Even though this function *only* does aligned loads, it's worse than the other function --- tests/benchmarks/corelib/tools/qstring/main.cpp | 139 +++++++++++++++++------- 1 file changed, 101 insertions(+), 38 deletions(-) diff --git a/tests/benchmarks/corelib/tools/qstring/main.cpp b/tests/benchmarks/corelib/tools/qstring/main.cpp index 4c4d921..d2861b6 100644 --- a/tests/benchmarks/corelib/tools/qstring/main.cpp +++ b/tests/benchmarks/corelib/tools/qstring/main.cpp @@ -259,7 +259,7 @@ static inline bool equals2_short_tail(const ushort *p1, const ushort *p2, int le return true; } -#pragma GCC optimize("no-unroll-loops") +#pragma GCC optimize("unroll-loops off") #ifdef __SSE2__ static bool equals2_sse2_aligned(const ushort *p1, const ushort *p2, int len) { @@ -989,7 +989,7 @@ static __attribute__((optimize("no-unroll-loops"))) int ucstrncmp_sse2_aligning( static inline __attribute__((optimize("no-unroll-loops"))) int ucstrncmp_sse2_aligned(const ushort *a, const ushort *b, int len) { - qptrdiff counter = 0; + quintptr counter = 0; while (len >= 8) { __m128i m1 = _mm_load_si128((__m128i *)(a + counter)); __m128i m2 = _mm_load_si128((__m128i *)(b + counter)); @@ -1007,8 +1007,29 @@ static inline __attribute__((optimize("no-unroll-loops"))) int ucstrncmp_sse2_al return ucstrncmp_short_tail(a + counter, b + counter, len); } +static inline __attribute__((optimize("no-unroll-loops"))) int ucstrncmp_ssse3_alignr_aligned(const ushort *a, const ushort *b, int len) +{ + quintptr counter = 0; + while (len >= 8) { + __m128i m1 = _mm_load_si128((__m128i *)(a + counter)); + __m128i m2 = _mm_lddqu_si128((__m128i *)(b + counter)); + __m128i cmp = _mm_cmpeq_epi16(m1, m2); + ushort mask = ~uint(_mm_movemask_epi8(cmp)); + if (mask) { + // which ushort isn't equal? + counter += bsf_nonzero(mask)/2; + return a[counter] - b[counter]; + } + + counter += 8; + len -= 8; + } + return ucstrncmp_short_tail(a + counter, b + counter, len); +} + + typedef __m128i (* MMLoadFunction)(const __m128i *); -template +template static inline __attribute__((optimize("no-unroll-loops"))) int ucstrncmp_ssse3_alignr(const ushort *a, const ushort *b, int len) { qptrdiff counter = 0; @@ -1043,23 +1064,23 @@ static int ucstrncmp_ssse3(const ushort *a, const ushort *b, int len) a -= val/2; if (val == 10) - return ucstrncmp_ssse3_alignr<10>(a, b, len); + return ucstrncmp_ssse3_alignr<10, _mm_lddqu_si128>(a, b, len); else if (val == 2) - return ucstrncmp_ssse3_alignr<2>(a, b, len); + return ucstrncmp_ssse3_alignr<2, _mm_lddqu_si128>(a, b, len); if (val < 8) { if (val < 4) - return ucstrncmp_sse2_aligned(a, b, len); + return ucstrncmp_ssse3_alignr_aligned(a, b, len); else if (val == 4) - return ucstrncmp_ssse3_alignr<4>(a, b, len); + return ucstrncmp_ssse3_alignr<4, _mm_lddqu_si128>(a, b, len); else - return ucstrncmp_ssse3_alignr<6>(a, b, len); + return ucstrncmp_ssse3_alignr<6, _mm_lddqu_si128>(a, b, len); } else { if (val < 12) - return ucstrncmp_ssse3_alignr<8>(a, b, len); + return ucstrncmp_ssse3_alignr<8, _mm_lddqu_si128>(a, b, len); else if (val == 12) - return ucstrncmp_ssse3_alignr<12>(a, b, len); + return ucstrncmp_ssse3_alignr<12, _mm_lddqu_si128>(a, b, len); else - return ucstrncmp_ssse3_alignr<14>(a, b, len); + return ucstrncmp_ssse3_alignr<14, _mm_lddqu_si128>(a, b, len); } } return ucstrncmp_short_tail(a, b, len); @@ -1115,18 +1136,9 @@ static int ucstrncmp_ssse3_aligning(const ushort *a, const ushort *b, int len) } static inline __attribute__((optimize("no-unroll-loops"))) -int ucstrncmp_ssse3_aligning2_aligned(const ushort *a, const ushort *b, int len) +int ucstrncmp_ssse3_aligning2_aligned(const ushort *a, const ushort *b, int len, int garbage) { // len >= 8 - // align(b) == align(a) - - // round down the alignment so align(b) == align(a) == 0 - // calculate how many garbage bytes we'll read on the first load - // corresponds to how many bits we must ignore from movemask's result - int garbage = (quintptr(b) & 0xf); - a -= garbage / 2; - b -= garbage / 2; - __m128i m1 = _mm_load_si128((const __m128i *)a); __m128i m2 = _mm_load_si128((const __m128i *)b); __m128i cmp = _mm_cmpeq_epi16(m1, m2); @@ -1134,8 +1146,8 @@ int ucstrncmp_ssse3_aligning2_aligned(const ushort *a, const ushort *b, int len) mask >>= garbage; if (~mask) { // which ushort isn't equal? - int counter = (garbage + bsf_nonzero(~mask))/2; - return a[counter] - b[counter]; + uint counter = (garbage + bsf_nonzero(~mask)); + return a[counter/2] - b[counter/2]; } // the first 16-garbage bytes (8-garbage/2 ushorts) were equal @@ -1144,9 +1156,53 @@ int ucstrncmp_ssse3_aligning2_aligned(const ushort *a, const ushort *b, int len) } template static inline __attribute__((optimize("no-unroll-loops"))) -int ucstrncmp_ssse3_aligning2_alignr(const ushort *a, const ushort *b, int len) +int ucstrncmp_ssse3_aligning2_alignr(const ushort *a, const ushort *b, int len, int garbage) +{ + // len >= 8 + __m128i lower, upper, merged; + lower = _mm_load_si128((const __m128i*)a); + upper = _mm_load_si128((const __m128i*)(a + 8)); + merged = _mm_alignr_epi8(upper, lower, N); + + __m128i m2 = _mm_load_si128((const __m128i*)b); + __m128i cmp = _mm_cmpeq_epi16(merged, m2); + int mask = short(_mm_movemask_epi8(cmp)); // force sign extension + mask >>= garbage; + if (~mask) { + // which ushort isn't equal? + uint counter = (garbage + bsf_nonzero(~mask)); + return a[counter/2 + N/2] - b[counter/2]; + } + + // the first 16-garbage bytes (8-garbage/2 ushorts) were equal + quintptr counter = 8; + len -= 8 - garbage/2; + while (len >= 8) { + lower = upper; + upper = _mm_load_si128((__m128i *)(a + counter) + 1); + merged = _mm_alignr_epi8(upper, lower, N); + + m2 = _mm_load_si128((__m128i *)(b + counter)); + cmp = _mm_cmpeq_epi16(merged, m2); + ushort mask = ~uint(_mm_movemask_epi8(cmp)); + if (mask) { + // which ushort isn't equal? + counter += bsf_nonzero(mask)/2; + return a[counter + N/2] - b[counter]; + } + + counter += 8; + len -= 8; + } + + return ucstrncmp_short_tail(a + counter + N/2, b + counter, len); +} + +static inline int conditional_invert(int result, bool invert) { - return ucstrncmp_intwise(a, b, len); + if (invert) + return -result; + return result; } static int ucstrncmp_ssse3_aligning2(const ushort *a, const ushort *b, int len) @@ -1157,40 +1213,47 @@ static int ucstrncmp_ssse3_aligning2(const ushort *a, const ushort *b, int len) // in the beginning of the string, which we'll shift out of the way // (after _mm_movemask_epi8) - if (len < 16) + if (len < 8) return ucstrncmp_intwise(a, b, len); // both a and b are misaligned // we'll call the alignr function with the alignment *difference* between the two - int val = (quintptr(b) & 0xf) - (quintptr(a) & 0xf); - int sign = 1; + int val = (quintptr(a) & 0xf) - (quintptr(b) & 0xf); + bool invert = false; if (val < 0) { val = -val; - qSwap(a, b); - sign = -1; + //qSwap(a, b); + asm ("xchg %0, %1" : "+r" (a), "+r" (b)); + invert = true; } // from this point on, b has the shortest alignment // and align(a) = align(b) + val + // round down the alignment so align(b) == align(a) == 0 + int garbage = (quintptr(b) & 0xf); + a = (const ushort*)(quintptr(a) & ~0xf); + b = (const ushort*)(quintptr(b) & ~0xf); + // now the first load of b will load 'garbage' extra bytes + // and the first load of a will load 'garbage + val' extra bytes if (val == 8) - return ucstrncmp_ssse3_aligning2_alignr<8>(a, b, len) * sign; + return conditional_invert(ucstrncmp_ssse3_aligning2_alignr<8>(a, b, len, garbage), invert); else if (val == 0) - return ucstrncmp_ssse3_aligning2_aligned(a, b, len) * sign; + return conditional_invert(ucstrncmp_ssse3_aligning2_aligned(a, b, len, garbage), invert); if (val < 8) { if (val < 4) - return ucstrncmp_ssse3_aligning2_alignr<2>(a, b, len) * sign; + return conditional_invert(ucstrncmp_ssse3_aligning2_alignr<2>(a, b, len, garbage), invert); else if (val == 4) - return ucstrncmp_ssse3_aligning2_alignr<4>(a, b, len) * sign; + return conditional_invert(ucstrncmp_ssse3_aligning2_alignr<4>(a, b, len, garbage), invert); else - return ucstrncmp_ssse3_aligning2_alignr<6>(a, b, len) * sign; + return conditional_invert(ucstrncmp_ssse3_aligning2_alignr<6>(a, b, len, garbage), invert); } else { if (val < 12) - return ucstrncmp_ssse3_aligning2_alignr<10>(a, b, len) * sign; + return conditional_invert(ucstrncmp_ssse3_aligning2_alignr<10>(a, b, len, garbage), invert); else if (val == 12) - return ucstrncmp_ssse3_aligning2_alignr<12>(a, b, len) * sign; + return conditional_invert(ucstrncmp_ssse3_aligning2_alignr<12>(a, b, len, garbage), invert); else - return ucstrncmp_ssse3_aligning2_alignr<14>(a, b, len) * sign; + return conditional_invert(ucstrncmp_ssse3_aligning2_alignr<14>(a, b, len, garbage), invert); } } -- cgit v0.12 From 469210fdf9287dc8a4933e0761bbff91a031045f Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Tue, 24 Aug 2010 12:14:41 +0200 Subject: Don't try to compile the SSE2 and SSSE3 code with compilers that don't support them (e.g. ARM) --- tests/benchmarks/corelib/tools/qstring/main.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/tests/benchmarks/corelib/tools/qstring/main.cpp b/tests/benchmarks/corelib/tools/qstring/main.cpp index d2861b6..3b86792 100644 --- a/tests/benchmarks/corelib/tools/qstring/main.cpp +++ b/tests/benchmarks/corelib/tools/qstring/main.cpp @@ -163,7 +163,7 @@ static bool equals2_bytewise(const ushort *p1, const ushort *p2, int len) return true; } -static bool __attribute__((optimize("unroll-loops"))) equals2_shortwise(const ushort *p1, const ushort *p2, int len) +static bool equals2_shortwise(const ushort *p1, const ushort *p2, int len) { if (p1 == p2 || !len) return true; @@ -259,7 +259,7 @@ static inline bool equals2_short_tail(const ushort *p1, const ushort *p2, int le return true; } -#pragma GCC optimize("unroll-loops off") +//#pragma GCC optimize("no-unroll-loops") #ifdef __SSE2__ static bool equals2_sse2_aligned(const ushort *p1, const ushort *p2, int len) { @@ -1155,7 +1155,7 @@ int ucstrncmp_ssse3_aligning2_aligned(const ushort *a, const ushort *b, int len, return ucstrncmp_sse2_aligned(a + 8, b + 8, len); } -template static inline __attribute__((optimize("no-unroll-loops"))) +template static inline __attribute__((optimize("no-unroll-loops"),always_inline)) int ucstrncmp_ssse3_aligning2_alignr(const ushort *a, const ushort *b, int len, int garbage) { // len >= 8 @@ -1268,11 +1268,15 @@ void tst_QString::ucstrncmp_data() const QTest::newRow("selftest") << UcstrncmpFunction(0); QTest::newRow("shortwise") << &ucstrncmp_shortwise; QTest::newRow("intwise") << &ucstrncmp_intwise; +#ifdef __SSE2__ QTest::newRow("sse2") << &ucstrncmp_sse2; QTest::newRow("sse2_aligning") << &ucstrncmp_sse2_aligning; +#ifdef __SSSE3__ QTest::newRow("ssse3") << &ucstrncmp_ssse3; QTest::newRow("ssse3_aligning") << &ucstrncmp_ssse3_aligning; QTest::newRow("ssse3_aligning2") << &ucstrncmp_ssse3_aligning2; +#endif +#endif } void tst_QString::ucstrncmp() const @@ -1282,11 +1286,15 @@ void tst_QString::ucstrncmp() const static const UcstrncmpFunction func[] = { &ucstrncmp_shortwise, &ucstrncmp_intwise, +#ifdef __SSE2__ &ucstrncmp_sse2, &ucstrncmp_sse2_aligning, +#ifdef __SSSE3__ &ucstrncmp_ssse3, &ucstrncmp_ssse3_aligning, &ucstrncmp_ssse3_aligning2 +#endif +#endif }; static const int functionCount = sizeof func / sizeof func[0]; -- cgit v0.12 From 9a468f59472e8978aa18b75e9786718a8823bbec Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Tue, 24 Aug 2010 12:15:36 +0200 Subject: Unroll the SSSE3 code even more to avoid the need to keep an extra variable for inverting the result On 32-bit, we're out of registers already, so this variable ended up in memory --- tests/benchmarks/corelib/tools/qstring/main.cpp | 88 +++++++++++++++---------- 1 file changed, 53 insertions(+), 35 deletions(-) diff --git a/tests/benchmarks/corelib/tools/qstring/main.cpp b/tests/benchmarks/corelib/tools/qstring/main.cpp index 3b86792..9616052 100644 --- a/tests/benchmarks/corelib/tools/qstring/main.cpp +++ b/tests/benchmarks/corelib/tools/qstring/main.cpp @@ -1218,42 +1218,60 @@ static int ucstrncmp_ssse3_aligning2(const ushort *a, const ushort *b, int len) // both a and b are misaligned // we'll call the alignr function with the alignment *difference* between the two - int val = (quintptr(a) & 0xf) - (quintptr(b) & 0xf); - bool invert = false; - if (val < 0) { - val = -val; - //qSwap(a, b); - asm ("xchg %0, %1" : "+r" (a), "+r" (b)); - invert = true; - } - - // from this point on, b has the shortest alignment - // and align(a) = align(b) + val - // round down the alignment so align(b) == align(a) == 0 - int garbage = (quintptr(b) & 0xf); - a = (const ushort*)(quintptr(a) & ~0xf); - b = (const ushort*)(quintptr(b) & ~0xf); - - // now the first load of b will load 'garbage' extra bytes - // and the first load of a will load 'garbage + val' extra bytes - if (val == 8) - return conditional_invert(ucstrncmp_ssse3_aligning2_alignr<8>(a, b, len, garbage), invert); - else if (val == 0) - return conditional_invert(ucstrncmp_ssse3_aligning2_aligned(a, b, len, garbage), invert); - if (val < 8) { - if (val < 4) - return conditional_invert(ucstrncmp_ssse3_aligning2_alignr<2>(a, b, len, garbage), invert); - else if (val == 4) - return conditional_invert(ucstrncmp_ssse3_aligning2_alignr<4>(a, b, len, garbage), invert); - else - return conditional_invert(ucstrncmp_ssse3_aligning2_alignr<6>(a, b, len, garbage), invert); + int offset = (quintptr(a) & 0xf) - (quintptr(b) & 0xf); + if (offset >= 0) { + // from this point on, b has the shortest alignment + // and align(a) = align(b) + offset + // round down the alignment so align(b) == align(a) == 0 + int garbage = (quintptr(b) & 0xf); + a = (const ushort*)(quintptr(a) & ~0xf); + b = (const ushort*)(quintptr(b) & ~0xf); + + // now the first load of b will load 'garbage' extra bytes + // and the first load of a will load 'garbage + offset' extra bytes + if (offset == 8) + return ucstrncmp_ssse3_aligning2_alignr<8>(a, b, len, garbage); + if (offset == 0) + return ucstrncmp_ssse3_aligning2_aligned(a, b, len, garbage); + if (offset < 8) { + if (offset < 4) + return ucstrncmp_ssse3_aligning2_alignr<2>(a, b, len, garbage); + else if (offset == 4) + return ucstrncmp_ssse3_aligning2_alignr<4>(a, b, len, garbage); + else + return ucstrncmp_ssse3_aligning2_alignr<6>(a, b, len, garbage); + } else { + if (offset < 12) + return ucstrncmp_ssse3_aligning2_alignr<10>(a, b, len, garbage); + else if (offset == 12) + return ucstrncmp_ssse3_aligning2_alignr<12>(a, b, len, garbage); + else + return ucstrncmp_ssse3_aligning2_alignr<14>(a, b, len, garbage); + } } else { - if (val < 12) - return conditional_invert(ucstrncmp_ssse3_aligning2_alignr<10>(a, b, len, garbage), invert); - else if (val == 12) - return conditional_invert(ucstrncmp_ssse3_aligning2_alignr<12>(a, b, len, garbage), invert); - else - return conditional_invert(ucstrncmp_ssse3_aligning2_alignr<14>(a, b, len, garbage), invert); + // same as above but inverted + int garbage = (quintptr(a) & 0xf); + a = (const ushort*)(quintptr(a) & ~0xf); + b = (const ushort*)(quintptr(b) & ~0xf); + + offset = -offset; + if (offset == 8) + return -ucstrncmp_ssse3_aligning2_alignr<8>(b, a, len, garbage); + if (offset < 8) { + if (offset < 4) + return -ucstrncmp_ssse3_aligning2_alignr<2>(b, a, len, garbage); + else if (offset == 4) + return -ucstrncmp_ssse3_aligning2_alignr<4>(b, a, len, garbage); + else + return -ucstrncmp_ssse3_aligning2_alignr<6>(b, a, len, garbage); + } else { + if (offset < 12) + return -ucstrncmp_ssse3_aligning2_alignr<10>(b, a, len, garbage); + else if (offset == 12) + return -ucstrncmp_ssse3_aligning2_alignr<12>(b, a, len, garbage); + else + return -ucstrncmp_ssse3_aligning2_alignr<14>(b, a, len, garbage); + } } } -- cgit v0.12 From 189a18eddfa7504a604060172a394bda60aeba10 Mon Sep 17 00:00:00 2001 From: Denis Dzyubenko Date: Tue, 24 Aug 2010 13:07:09 +0200 Subject: Fixed delivering gestures to a toplevel widget. If there is only one widget which is a toplevel, then gestures were not delivered to it because we assumed (wrong) that there is at least one child widget. Reviewed-by: Frederik Gladhorn --- src/gui/kernel/qgesturemanager.cpp | 5 +++-- tests/auto/gestures/tst_gestures.cpp | 5 +++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/gui/kernel/qgesturemanager.cpp b/src/gui/kernel/qgesturemanager.cpp index e768a21..cb4061e 100644 --- a/src/gui/kernel/qgesturemanager.cpp +++ b/src/gui/kernel/qgesturemanager.cpp @@ -595,8 +595,9 @@ void QGestureManager::deliverEvents(const QSet &gestures, if (gesture->hasHotSpot()) { // guess the target widget using the hotspot of the gesture QPoint pt = gesture->hotSpot().toPoint(); - if (QWidget *w = qApp->topLevelAt(pt)) { - target = w->childAt(w->mapFromGlobal(pt)); + if (QWidget *topLevel = qApp->topLevelAt(pt)) { + QWidget *child = topLevel->childAt(topLevel->mapFromGlobal(pt)); + target = child ? child : topLevel; } } else { // or use the context of the gesture diff --git a/tests/auto/gestures/tst_gestures.cpp b/tests/auto/gestures/tst_gestures.cpp index a968520..ddc3939 100644 --- a/tests/auto/gestures/tst_gestures.cpp +++ b/tests/auto/gestures/tst_gestures.cpp @@ -395,7 +395,12 @@ void tst_Gestures::customGesture() { GestureWidget widget; widget.grabGesture(CustomGesture::GestureType, Qt::DontStartGestureOnChildren); + widget.show(); + QTest::qWaitForWindowShown(&widget); + CustomEvent event; + event.hotSpot = widget.mapToGlobal(QPoint(5,5)); + event.hasHotSpot = true; sendCustomGesture(&event, &widget); static const int TotalGestureEventsCount = CustomGesture::SerialFinishedThreshold - CustomGesture::SerialStartedThreshold + 1; -- cgit v0.12 From 7a5fa8af2d0c3329dd1962d6b053388a960f8305 Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Thu, 19 Aug 2010 16:00:57 +0200 Subject: QGraphicsView: Fix assert that may occurs if there are 'empty' item to draw, and changed() signal connected Reviewed-by: bnilsen --- src/gui/graphicsview/qgraphicsscene.cpp | 4 +++- tests/auto/qgraphicsscene/tst_qgraphicsscene.cpp | 26 ++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index a98ce6f..3c23884 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -5126,7 +5126,9 @@ void QGraphicsScenePrivate::processDirtyItemsRecursive(QGraphicsItem *item, bool q->update(itemBoundingRect.translated(item->d_ptr->sceneTransform.dx(), item->d_ptr->sceneTransform.dy())); } else { - q->update(item->d_ptr->sceneTransform.mapRect(itemBoundingRect)); + QRectF rect = item->d_ptr->sceneTransform.mapRect(itemBoundingRect); + if (!rect.isEmpty()) + q->update(rect); } } else { QRectF dirtyRect; diff --git a/tests/auto/qgraphicsscene/tst_qgraphicsscene.cpp b/tests/auto/qgraphicsscene/tst_qgraphicsscene.cpp index 903977c..7ee2a48 100644 --- a/tests/auto/qgraphicsscene/tst_qgraphicsscene.cpp +++ b/tests/auto/qgraphicsscene/tst_qgraphicsscene.cpp @@ -276,6 +276,7 @@ private slots: void isActive(); void siblingIndexAlwaysValid(); void removeFullyTransparentItem(); + void zeroScale(); // task specific tests below me void task139710_bspTreeCrash(); @@ -4564,5 +4565,30 @@ void tst_QGraphicsScene::taskQTBUG_7863_paintIntoCacheWithTransparentParts() } } +void tst_QGraphicsScene::zeroScale() +{ + //should not crash + QGraphicsScene scene; + scene.setSceneRect(-100, -100, 100, 100); + QGraphicsView view(&scene); + + ChangedListener cl; + connect(&scene, SIGNAL(changed(const QList &)), &cl, SLOT(changed(const QList &))); + + QGraphicsRectItem *rect1 = new QGraphicsRectItem(0, 0, 0.0000001, 0.00000001); + scene.addItem(rect1); + rect1->setRotation(82); + rect1->setScale(0.00000001); + + QApplication::processEvents(); + QCOMPARE(cl.changes.count(), 1); + QGraphicsRectItem *rect2 = new QGraphicsRectItem(-0.0000001, -0.0000001, 0.0000001, 0.0000001); + rect2->setScale(0.00000001); + scene.addItem(rect2); + rect1->setPos(20,20); + QApplication::processEvents(); + QCOMPARE(cl.changes.count(), 2); +} + QTEST_MAIN(tst_QGraphicsScene) #include "tst_qgraphicsscene.moc" -- cgit v0.12 From db1a70b33ce03197111556344542e931e9345839 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Fri, 20 Aug 2010 23:18:50 +0200 Subject: Split the CPU-detection code into multiple functions for readability Reviewed-By: Benjamin Poulain --- src/corelib/tools/qsimd.cpp | 86 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 69 insertions(+), 17 deletions(-) diff --git a/src/corelib/tools/qsimd.cpp b/src/corelib/tools/qsimd.cpp index 8005d7d..d6e6c03 100644 --- a/src/corelib/tools/qsimd.cpp +++ b/src/corelib/tools/qsimd.cpp @@ -52,13 +52,9 @@ QT_BEGIN_NAMESPACE -uint qDetectCPUFeatures() -{ - static uint features = 0xffffffff; - if (features != 0xffffffff) - return features; - #if defined (Q_OS_WINCE) +static inline uint detectProcessorFeatures() +{ #if defined (ARM) if (IsProcessorFeaturePresent(PF_ARM_INTEL_WMMX)) { features = IWMMXT; @@ -78,7 +74,14 @@ uint qDetectCPUFeatures() #endif features = 0; return features; -#elif defined(QT_HAVE_IWMMXT) +} + +#elif defined(__arm__) || defined(__arm) || defined(QT_HAVE_IWMMXT) || defined(QT_HAVE_NEON) +static inline uint detectProcessorFeatures() +{ + uint features = 0; + +#if defined(QT_HAVE_IWMMXT) // runtime detection only available when running as a previlegied process static const bool doIWMMXT = !qgetenv("QT_NO_IWMMXT").toInt(); features = doIWMMXT ? IWMMXT : 0; @@ -87,13 +90,14 @@ uint qDetectCPUFeatures() static const bool doNEON = !qgetenv("QT_NO_NEON").toInt(); features = doNEON ? NEON : 0; return features; -#else - features = 0; -#if defined(__x86_64__) || defined(Q_OS_WIN64) - features = MMX|SSE|SSE2|CMOV; -#elif defined(__ia64__) - features = MMX|SSE|SSE2; +#endif +} + #elif defined(__i386__) || defined(_M_IX86) +static inline uint detectProcessorFeatures() +{ + uint features = 0; + unsigned int extended_result = 0; unsigned int feature_result = 0; uint result = 0; @@ -149,6 +153,7 @@ uint qDetectCPUFeatures() : : "%eax", "%ecx", "%edx" ); + #elif defined (Q_OS_WIN) _asm { push eax @@ -210,6 +215,7 @@ uint qDetectCPUFeatures() } #endif + // result now contains the standard feature bits if (result & (1u << 15)) features |= CMOV; @@ -236,9 +242,36 @@ uint qDetectCPUFeatures() if (feature_result & (1u << 28)) features |= AVX; -#endif // i386 +#if defined(QT_HAVE_MMX) + if (qgetenv("QT_NO_MMX").toInt()) + features ^= MMX; +#endif + if (qgetenv("QT_NO_MMXEXT").toInt()) + features ^= MMXEXT; + +#if defined(QT_HAVE_3DNOW) + if (qgetenv("QT_NO_3DNOW").toInt()) + features ^= MMX3DNOW; +#endif + if (qgetenv("QT_NO_3DNOWEXT").toInt()) + features ^= MMX3DNOWEXT; + +#if defined(QT_HAVE_SSE) + if (qgetenv("QT_NO_SSE").toInt()) + features ^= SSE; +#endif +#if defined(QT_HAVE_SSE2) + if (qgetenv("QT_NO_SSE2").toInt()) + features ^= SSE2; +#endif -#if defined(__x86_64__) || defined(Q_OS_WIN64) + return features; +} + +#elif defined(__x86_64) || defined(Q_OS_WIN64) +static inline uint detectProcessorFeatures() +{ + uint features = MMX|SSE|SSE2|CMOV; uint feature_result = 0; #if defined(Q_CC_GNU) @@ -282,7 +315,6 @@ uint qDetectCPUFeatures() features |= SSE4_2; if (feature_result & (1u << 28)) features |= AVX; -#endif // x86_64 #if defined(QT_HAVE_MMX) if (qgetenv("QT_NO_MMX").toInt()) @@ -306,9 +338,29 @@ uint qDetectCPUFeatures() if (qgetenv("QT_NO_SSE2").toInt()) features ^= SSE2; #endif +} - return features; +#elif defined(__ia64__) +static inline uint detectProcessorFeatures() +{ + return MMX|SSE|SSE2; +} + +#else +static inline uint detectProcessorFeatures() +{ + return 0; +} #endif + +uint qDetectCPUFeatures() +{ + static QBasicAtomicInt features = Q_BASIC_ATOMIC_INITIALIZER(-1); + if (features != -1) + return features; + + features = detectProcessorFeatures(); + return features; } QT_END_NAMESPACE -- cgit v0.12 From 5070c3ae331faf18f6997535356853cc61ef0ad7 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Tue, 24 Aug 2010 13:00:33 +0200 Subject: Detect CPU features on ARM by reading the ELF auxvec. Reviewed-by: Benjamin Poulain --- src/corelib/tools/qsimd.cpp | 45 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/src/corelib/tools/qsimd.cpp b/src/corelib/tools/qsimd.cpp index d6e6c03..a5ec3c5 100644 --- a/src/corelib/tools/qsimd.cpp +++ b/src/corelib/tools/qsimd.cpp @@ -50,6 +50,13 @@ #include #endif +#if defined(Q_OS_LINUX) && defined(__arm__) +#include "private/qcore_unix_p.h" + +#include +#include +#endif + QT_BEGIN_NAMESPACE #if defined (Q_OS_WINCE) @@ -81,16 +88,50 @@ static inline uint detectProcessorFeatures() { uint features = 0; +#if defined(Q_OS_LINUX) + int auxv = ::qt_safe_open("/proc/self/auxv", O_RDONLY); + if (auxv != -1) { + unsigned long vector[64]; + int nread; + while (features == 0) { + nread = ::qt_safe_read(auxv, (char *)vector, sizeof vector); + if (nread <= 0) { + // EOF or error + break; + } + + int max = nread / (sizeof vector[0]); + for (int i = 0; i < max; i += 2) + if (vector[i] == AT_HWCAP) { + if (vector[i+1] & HWCAP_IWMMXT) + features |= IWMMXT; + if (vector[i+1] & HWCAP_NEON) + features |= NEON; + break; + } + } + + if (qgetenv("QT_NO_IWMMXT").toInt()) + features ^= IWMMXT; + if (qgetenv("QT_NO_NEON").toInt()) + features ^= NEON; + + ::qt_safe_close(auxv); + return features; + } + // fall back if /proc/self/auxv wasn't found +#endif + #if defined(QT_HAVE_IWMMXT) // runtime detection only available when running as a previlegied process static const bool doIWMMXT = !qgetenv("QT_NO_IWMMXT").toInt(); features = doIWMMXT ? IWMMXT : 0; - return features; #elif defined(QT_HAVE_NEON) static const bool doNEON = !qgetenv("QT_NO_NEON").toInt(); features = doNEON ? NEON : 0; - return features; #endif + + return features; } #elif defined(__i386__) || defined(_M_IX86) -- cgit v0.12 From d9b567288f301e44abedebf5b9b553c2878f2c77 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Fri, 20 Aug 2010 23:19:54 +0200 Subject: Report the detected CPU features in the corelib boilerplate --- src/corelib/global/qlibraryinfo.cpp | 3 +++ src/corelib/tools/qsimd.cpp | 53 +++++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) diff --git a/src/corelib/global/qlibraryinfo.cpp b/src/corelib/global/qlibraryinfo.cpp index 7ebee3d..b4f5d0f 100644 --- a/src/corelib/global/qlibraryinfo.cpp +++ b/src/corelib/global/qlibraryinfo.cpp @@ -525,6 +525,9 @@ void qt_core_boilerplate() qt_configure_libraries_path_str + 12, qt_configure_headers_path_str + 12); + extern void qDumpCPUFeatures(); + qDumpCPUFeatures(); + #ifdef QT_EVAL extern void qt_core_eval_init(uint); qt_core_eval_init(1); diff --git a/src/corelib/tools/qsimd.cpp b/src/corelib/tools/qsimd.cpp index a5ec3c5..2472449 100644 --- a/src/corelib/tools/qsimd.cpp +++ b/src/corelib/tools/qsimd.cpp @@ -41,6 +41,7 @@ #include "qsimd_p.h" #include +#include #if defined(Q_OS_WINCE) #include @@ -404,4 +405,56 @@ uint qDetectCPUFeatures() return features; } +void qDumpCPUFeatures() +{ + /* + * Use kdesdk/scripts/generate_string_table.pl to update the table below. + * Here's the data: +mmx +mmxext +mmx3dnow +mmx3dnowext +sse +sse2 +cmov +iwmmxt +neon +sse3 +ssse3 +sse4.1 +sse4.2 +avx + */ + static const char features_string[] = + "mmx\0" + "mmxext\0" + "mmx3dnow\0" + "mmx3dnowext\0" + "sse\0" + "sse2\0" + "cmov\0" + "iwmmxt\0" + "neon\0" + "sse3\0" + "ssse3\0" + "sse4.1\0" + "sse4.2\0" + "avx\0" + "\0"; + + static const int features_indices[] = { + 0, 4, 11, 20, 32, 36, 41, 46, + 53, 58, 63, 69, 76, 83, -1 + }; + const int features_count = (sizeof features_indices - 1) / (sizeof features_indices[0]); + + uint features = qDetectCPUFeatures(); + printf("Processor features: "); + for (int i = 0; i < features_count; ++i) { + if (features & (1 << i)) + printf(" %s", features_string + features_indices[i]); + } + puts(""); +} + QT_END_NAMESPACE -- cgit v0.12 From ebf9d5dd5174b7c82fec83b56d71a59d5277bd51 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Tue, 24 Aug 2010 13:52:09 +0200 Subject: Properly implement the CPU feature disabling in qsimd.cpp. Don't use ^=, since that might enable a feature that wasn't detected. The new use is: export QT_NO_CPU_FEATURE=" []" Reviewed-by: Benjamin Poulain --- src/corelib/tools/qsimd.cpp | 157 +++++++++++++++++--------------------------- 1 file changed, 60 insertions(+), 97 deletions(-) diff --git a/src/corelib/tools/qsimd.cpp b/src/corelib/tools/qsimd.cpp index 2472449..c34644c 100644 --- a/src/corelib/tools/qsimd.cpp +++ b/src/corelib/tools/qsimd.cpp @@ -112,11 +112,6 @@ static inline uint detectProcessorFeatures() } } - if (qgetenv("QT_NO_IWMMXT").toInt()) - features ^= IWMMXT; - if (qgetenv("QT_NO_NEON").toInt()) - features ^= NEON; - ::qt_safe_close(auxv); return features; } @@ -125,11 +120,9 @@ static inline uint detectProcessorFeatures() #if defined(QT_HAVE_IWMMXT) // runtime detection only available when running as a previlegied process - static const bool doIWMMXT = !qgetenv("QT_NO_IWMMXT").toInt(); - features = doIWMMXT ? IWMMXT : 0; + features = IWMMXT; #elif defined(QT_HAVE_NEON) - static const bool doNEON = !qgetenv("QT_NO_NEON").toInt(); - features = doNEON ? NEON : 0; + features = NEON; #endif return features; @@ -284,29 +277,6 @@ static inline uint detectProcessorFeatures() if (feature_result & (1u << 28)) features |= AVX; -#if defined(QT_HAVE_MMX) - if (qgetenv("QT_NO_MMX").toInt()) - features ^= MMX; -#endif - if (qgetenv("QT_NO_MMXEXT").toInt()) - features ^= MMXEXT; - -#if defined(QT_HAVE_3DNOW) - if (qgetenv("QT_NO_3DNOW").toInt()) - features ^= MMX3DNOW; -#endif - if (qgetenv("QT_NO_3DNOWEXT").toInt()) - features ^= MMX3DNOWEXT; - -#if defined(QT_HAVE_SSE) - if (qgetenv("QT_NO_SSE").toInt()) - features ^= SSE; -#endif -#if defined(QT_HAVE_SSE2) - if (qgetenv("QT_NO_SSE2").toInt()) - features ^= SSE2; -#endif - return features; } @@ -358,28 +328,7 @@ static inline uint detectProcessorFeatures() if (feature_result & (1u << 28)) features |= AVX; -#if defined(QT_HAVE_MMX) - if (qgetenv("QT_NO_MMX").toInt()) - features ^= MMX; -#endif - if (qgetenv("QT_NO_MMXEXT").toInt()) - features ^= MMXEXT; - -#if defined(QT_HAVE_3DNOW) - if (qgetenv("QT_NO_3DNOW").toInt()) - features ^= MMX3DNOW; -#endif - if (qgetenv("QT_NO_3DNOWEXT").toInt()) - features ^= MMX3DNOWEXT; - -#if defined(QT_HAVE_SSE) - if (qgetenv("QT_NO_SSE").toInt()) - features ^= SSE; -#endif -#if defined(QT_HAVE_SSE2) - if (qgetenv("QT_NO_SSE2").toInt()) - features ^= SSE2; -#endif + return features; } #elif defined(__ia64__) @@ -395,64 +344,78 @@ static inline uint detectProcessorFeatures() } #endif +/* + * Use kdesdk/scripts/generate_string_table.pl to update the table below. + * Here's the data (don't forget the ONE leading space): + mmx + mmxext + mmx3dnow + mmx3dnowext + sse + sse2 + cmov + iwmmxt + neon + sse3 + ssse3 + sse4.1 + sse4.2 + avx + */ + +// begin generated +static const char features_string[] = + " mmx\0" + " mmxext\0" + " mmx3dnow\0" + " mmx3dnowext\0" + " sse\0" + " sse2\0" + " cmov\0" + " iwmmxt\0" + " neon\0" + " sse3\0" + " ssse3\0" + " sse4.1\0" + " sse4.2\0" + " avx\0" + "\0"; + +static const int features_indices[] = { + 0, 5, 13, 23, 36, 41, 47, 53, + 61, 67, 73, 80, 88, 96, -1 +}; +// end generated + +const int features_count = (sizeof features_indices - 1) / (sizeof features_indices[0]); + uint qDetectCPUFeatures() { static QBasicAtomicInt features = Q_BASIC_ATOMIC_INITIALIZER(-1); if (features != -1) return features; - features = detectProcessorFeatures(); + uint f = detectProcessorFeatures(); + QByteArray disable = qgetenv("QT_NO_CPU_FEATURE"); + if (!disable.isEmpty()) { + disable.prepend(' '); + for (int i = 0; i < features_count; ++i) { + if (disable.contains(features_string + features_indices[i])) + f &= ~(1 << i); + } + } + + features = f; return features; } void qDumpCPUFeatures() { - /* - * Use kdesdk/scripts/generate_string_table.pl to update the table below. - * Here's the data: -mmx -mmxext -mmx3dnow -mmx3dnowext -sse -sse2 -cmov -iwmmxt -neon -sse3 -ssse3 -sse4.1 -sse4.2 -avx - */ - static const char features_string[] = - "mmx\0" - "mmxext\0" - "mmx3dnow\0" - "mmx3dnowext\0" - "sse\0" - "sse2\0" - "cmov\0" - "iwmmxt\0" - "neon\0" - "sse3\0" - "ssse3\0" - "sse4.1\0" - "sse4.2\0" - "avx\0" - "\0"; - - static const int features_indices[] = { - 0, 4, 11, 20, 32, 36, 41, 46, - 53, 58, 63, 69, 76, 83, -1 - }; - const int features_count = (sizeof features_indices - 1) / (sizeof features_indices[0]); - uint features = qDetectCPUFeatures(); printf("Processor features: "); for (int i = 0; i < features_count; ++i) { if (features & (1 << i)) - printf(" %s", features_string + features_indices[i]); + printf("%s", features_string + features_indices[i]); } puts(""); } -- cgit v0.12 From acf678e57ed088f3e56a551cac6c7c3322005750 Mon Sep 17 00:00:00 2001 From: Gunnar Sletta Date: Wed, 19 May 2010 07:18:27 +0200 Subject: Use binarysort to find items. Task: http://bugreports.qt.nokia.com/browse/QTBUG-231 Reviwed-by: Eskil --- src/gui/text/qtextengine.cpp | 19 ++++++++++++------- src/gui/text/qtextlayout.cpp | 24 +++++++++++++++++------- 2 files changed, 29 insertions(+), 14 deletions(-) diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp index 5670e29..8d6dd6c 100644 --- a/src/gui/text/qtextengine.cpp +++ b/src/gui/text/qtextengine.cpp @@ -1561,14 +1561,19 @@ bool QTextEngine::isRightToLeft() const int QTextEngine::findItem(int strPos) const { itemize(); - - // ##### use binary search - int item; - for (item = layoutData->items.size()-1; item > 0; --item) { - if (layoutData->items[item].position <= strPos) - break; + int left = 0; + int right = layoutData->items.size()-1; + while(left <= right) { + int middle = ((right-left)/2)+left; + if (strPos > layoutData->items[middle].position) + left = middle+1; + else if(strPos < layoutData->items[middle].position) + right = middle-1; + else { + return middle; + } } - return item; + return right; } QFixed QTextEngine::width(int from, int len) const diff --git a/src/gui/text/qtextlayout.cpp b/src/gui/text/qtextlayout.cpp index 5a11c87..f07c35e 100644 --- a/src/gui/text/qtextlayout.cpp +++ b/src/gui/text/qtextlayout.cpp @@ -1217,7 +1217,7 @@ void QTextLayout::draw(QPainter *p, const QPointF &pos, const QVectorlayoutData->items.size()-1; newItem > 0; --newItem) { - if (eng->layoutData->items[newItem].position <= line.from) + int newItem = -1; + int left = 0; + int right = eng->layoutData->items.size()-1; + while(left <= right) { + int middle = ((right-left)/2)+left; + if (line.from > eng->layoutData->items[middle].position) + left = middle+1; + else if(line.from < eng->layoutData->items[middle].position) + right = middle-1; + else { + newItem = middle; break; + } } + if (newItem == -1) + newItem = right; LB_DEBUG("from: %d: item=%d, total %d, width available %f", line.from, newItem, eng->layoutData->items.size(), line.width.toReal()); @@ -1960,7 +1970,7 @@ void QTextLine::layout_helper(int maxGlyphs) } LB_DEBUG("reached end of line"); lbh.checkFullOtherwiseExtend(line); -found: +found: if (lbh.rightBearing > 0 && !lbh.whiteSpaceOrObject) // If right bearing has not yet been adjusted lbh.adjustRightBearing(); line.textAdvance = line.textWidth; -- cgit v0.12 From f3771c5d91995b2beaa73bd3e3c783b76a887b50 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Tue, 24 Aug 2010 15:06:39 +0200 Subject: Fix mispositioned text with QStaticText and OpenVG graphics system The OpenVG paint engine, like the OpenGL2 paint engine, supports caching the untransformed glyphs and transforming them as they are drawn. Since we would pretransform the positions of the glyphs, the transformation would be applied twice, thus making the glyphs appear in the wrong location when the painter had a transform set. Task-number: QTBUG-13049 Reviewed-by: Gunnar --- src/gui/painting/qpainter.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp index b694d9c..be90006 100644 --- a/src/gui/painting/qpainter.cpp +++ b/src/gui/painting/qpainter.cpp @@ -5862,10 +5862,13 @@ void QPainter::drawStaticText(const QPointF &topLeftPosition, const QStaticText return; } - if (d->extended->type() == QPaintEngine::OpenGL2 && !staticText_d->untransformedCoordinates) { + bool paintEngineSupportsTransformations = d->extended->type() == QPaintEngine::OpenGL2 + || d->extended->type() == QPaintEngine::OpenVG; + + if (paintEngineSupportsTransformations && !staticText_d->untransformedCoordinates) { staticText_d->untransformedCoordinates = true; staticText_d->needsRelayout = true; - } else if (d->extended->type() != QPaintEngine::OpenGL2 && staticText_d->untransformedCoordinates) { + } else if (!paintEngineSupportsTransformations && staticText_d->untransformedCoordinates) { staticText_d->untransformedCoordinates = false; staticText_d->needsRelayout = true; } -- cgit v0.12 From a55f392edc2145a071d0d59cb0fc69b0d5205a76 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Sat, 21 Aug 2010 00:57:07 +0200 Subject: Use QElapsedTimer for the benchlib tests. It's faster to calculate the time with it, since it doesn't need to convert to local time first. Reviewed-By: Harald Fernengel --- dist/changes-4.7.1 | 118 ++++++++++++++++++++++++++++++++++ src/testlib/qbenchmarkmeasurement_p.h | 4 +- 2 files changed, 120 insertions(+), 2 deletions(-) create mode 100644 dist/changes-4.7.1 diff --git a/dist/changes-4.7.1 b/dist/changes-4.7.1 new file mode 100644 index 0000000..c8b26c2 --- /dev/null +++ b/dist/changes-4.7.1 @@ -0,0 +1,118 @@ +Qt 4.7.1 is a bug-fix release. It maintains both forward and backward +compatibility (source and binary) with Qt 4.7.0. For more details, +refer to the online documentation included in this distribution. The +documentation is also available online: + + http://qt.nokia.com/doc/4.7 + +The Qt version 4.7 series is binary compatible with the 4.6.x series. +Applications compiled for 4.6 will continue to run with 4.7. + +Some of the changes listed in this file include issue tracking numbers +corresponding to tasks in the Qt Bug Tracker, the (now obsolete) Task +Tracker, or the Merge Request queue of the public source repository. + +Qt Bug Tracker: http://bugreports.qt.nokia.com +Task Tracker: http://qt.nokia.com/developer/task-tracker +Merge Request: http://qt.gitorious.org + +**************************************************************************** +* General * +**************************************************************************** + +Optimizations +------------- + + - Improved the benchmarking library's timing code + * Uses a faster access to the system clock + + * See list of Important Behavior Changes below + + +**************************************************************************** +* Library * +**************************************************************************** + +QtCore +------ + + +QtGui +----- + + +QtDBus +------ + + +QtMultimedia +------------ + + +QtNetwork +--------- + + +QtOpenGL +-------- + + +QtOpenVG +-------- + + +QtWebKit +-------- + + +QtSql +----- + + +QtSvg +----- + + +Qt Plugins +---------- + + + +**************************************************************************** +* Platform Specific Changes * +**************************************************************************** + +Qt for Unix (X11 and Mac OS X) +------------------------------ + + +Qt for Linux/X11 +---------------- + + +Qt for Windows +-------------- + + +Qt for Mac OS X +--------------- + + +Qt for Symbian +-------------- + + + +**************************************************************************** +* Tools * +**************************************************************************** + + - Designer + + - uic + +**************************************************************************** +* Important Behavior Changes * +**************************************************************************** + + diff --git a/src/testlib/qbenchmarkmeasurement_p.h b/src/testlib/qbenchmarkmeasurement_p.h index 932852c..20a3bc1 100644 --- a/src/testlib/qbenchmarkmeasurement_p.h +++ b/src/testlib/qbenchmarkmeasurement_p.h @@ -53,7 +53,7 @@ // We mean it. // -#include +#include #include "3rdparty/cycle_p.h" #include "qbenchmark.h" @@ -87,7 +87,7 @@ public: bool needsWarmupIteration(); QTest::QBenchmarkMetric metricType(); private: - QTime time; + QElapsedTimer time; }; #ifdef HAVE_TICK_COUNTER // defined in 3rdparty/cycle_p.h -- cgit v0.12 From e9e6be0de1e1691b9d10cc9524aabf5d493858d6 Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Tue, 24 Aug 2010 14:23:40 +0200 Subject: QDeclarativeEngineDebugServer: make it a singleton. It is already a singleton, just formalize it so it can be used in other files than qdeclarativeengine.cpp This also remove the global olbject QDeclarativeEngineDebugServer::m_engines Reviewed-by: Lasse Holmstedt --- src/declarative/qml/qdeclarativeengine.cpp | 7 ++----- src/declarative/qml/qdeclarativeenginedebug.cpp | 8 +++++++- src/declarative/qml/qdeclarativeenginedebug_p.h | 8 +++++--- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/declarative/qml/qdeclarativeengine.cpp b/src/declarative/qml/qdeclarativeengine.cpp index 4e45636..c5a5c18 100644 --- a/src/declarative/qml/qdeclarativeengine.cpp +++ b/src/declarative/qml/qdeclarativeengine.cpp @@ -438,8 +438,6 @@ void QDeclarativeEnginePrivate::clear(SimpleList &pss) pss.clear(); } -Q_GLOBAL_STATIC(QDeclarativeEngineDebugServer, qmlEngineDebugServer); - void QDeclarativePrivate::qdeclarativeelement_destructor(QObject *o) { QObjectPrivate *p = QObjectPrivate::get(o); @@ -481,9 +479,8 @@ void QDeclarativeEnginePrivate::init() if (QCoreApplication::instance()->thread() == q->thread() && QDeclarativeEngineDebugServer::isDebuggingEnabled()) { - qmlEngineDebugServer(); isDebugging = true; - QDeclarativeEngineDebugServer::addEngine(q); + QDeclarativeEngineDebugServer::instance()->addEngine(q); } } @@ -547,7 +544,7 @@ QDeclarativeEngine::~QDeclarativeEngine() { Q_D(QDeclarativeEngine); if (d->isDebugging) - QDeclarativeEngineDebugServer::remEngine(this); + QDeclarativeEngineDebugServer::instance()->remEngine(this); } /*! \fn void QDeclarativeEngine::quit() diff --git a/src/declarative/qml/qdeclarativeenginedebug.cpp b/src/declarative/qml/qdeclarativeenginedebug.cpp index 688e0fc..056d8a0 100644 --- a/src/declarative/qml/qdeclarativeenginedebug.cpp +++ b/src/declarative/qml/qdeclarativeenginedebug.cpp @@ -58,7 +58,13 @@ QT_BEGIN_NAMESPACE -QList QDeclarativeEngineDebugServer::m_engines; +Q_GLOBAL_STATIC(QDeclarativeEngineDebugServer, qmlEngineDebugServer); + +QDeclarativeEngineDebugServer *QDeclarativeEngineDebugServer::instance() +{ + return qmlEngineDebugServer(); +} + QDeclarativeEngineDebugServer::QDeclarativeEngineDebugServer(QObject *parent) : QDeclarativeDebugService(QLatin1String("QDeclarativeEngine"), parent), m_watch(new QDeclarativeWatcher(this)) diff --git a/src/declarative/qml/qdeclarativeenginedebug_p.h b/src/declarative/qml/qdeclarativeenginedebug_p.h index aa450f3..4704393 100644 --- a/src/declarative/qml/qdeclarativeenginedebug_p.h +++ b/src/declarative/qml/qdeclarativeenginedebug_p.h @@ -92,8 +92,10 @@ public: bool hasNotifySignal; }; - static void addEngine(QDeclarativeEngine *); - static void remEngine(QDeclarativeEngine *); + void addEngine(QDeclarativeEngine *); + void remEngine(QDeclarativeEngine *); + + static QDeclarativeEngineDebugServer *instance(); protected: virtual void messageReceived(const QByteArray &); @@ -111,7 +113,7 @@ private: void resetBinding(int objectId, const QString &propertyName); void setMethodBody(int objectId, const QString &method, const QString &body); - static QList m_engines; + QList m_engines; QDeclarativeWatcher *m_watch; }; Q_DECLARATIVE_EXPORT QDataStream &operator<<(QDataStream &, const QDeclarativeEngineDebugServer::QDeclarativeObjectData &); -- cgit v0.12 From af2b28f9ca070576ed465f17516fdb9a004b83a4 Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Tue, 24 Aug 2010 16:34:49 +0200 Subject: QDeclarativeDebug: send a message when new object are added Reviewed-by: Lasse Holmstedt --- src/declarative/debugger/qdeclarativedebug.cpp | 2 ++ src/declarative/debugger/qdeclarativedebug_p.h | 3 +++ src/declarative/qml/qdeclarativecomponent.cpp | 8 ++++++-- src/declarative/qml/qdeclarativeenginedebug.cpp | 15 +++++++++++++++ src/declarative/qml/qdeclarativeenginedebug_p.h | 1 + 5 files changed, 27 insertions(+), 2 deletions(-) diff --git a/src/declarative/debugger/qdeclarativedebug.cpp b/src/declarative/debugger/qdeclarativedebug.cpp index 154df51..1ffe441 100644 --- a/src/declarative/debugger/qdeclarativedebug.cpp +++ b/src/declarative/debugger/qdeclarativedebug.cpp @@ -340,6 +340,8 @@ void QDeclarativeEngineDebugPrivate::message(const QByteArray &data) if (!watch) return; emit watch->valueChanged(name, value); + } else if (type == "OBJECT_CREATED") { + emit q_func()->newObjects(); } } diff --git a/src/declarative/debugger/qdeclarativedebug_p.h b/src/declarative/debugger/qdeclarativedebug_p.h index 2e79c5d..f0fc488 100644 --- a/src/declarative/debugger/qdeclarativedebug_p.h +++ b/src/declarative/debugger/qdeclarativedebug_p.h @@ -99,6 +99,9 @@ public: bool resetBindingForObject(int objectDebugId, const QString &propertyName); bool setMethodBody(int objectDebugId, const QString &methodName, const QString &methodBody); +Q_SIGNALS: + void newObjects(); + private: Q_DECLARE_PRIVATE(QDeclarativeEngineDebug) }; diff --git a/src/declarative/qml/qdeclarativecomponent.cpp b/src/declarative/qml/qdeclarativecomponent.cpp index 15cef16..d2d1f19 100644 --- a/src/declarative/qml/qdeclarativecomponent.cpp +++ b/src/declarative/qml/qdeclarativecomponent.cpp @@ -54,6 +54,7 @@ #include "private/qdeclarativeglobal_p.h" #include "private/qdeclarativescriptparser_p.h" #include "private/qdeclarativedebugtrace_p.h" +#include "private/qdeclarativeenginedebug_p.h" #include #include @@ -765,8 +766,11 @@ QDeclarativeComponentPrivate::beginCreate(QDeclarativeContextData *context, cons QObject *rv = begin(ctxt, ep, cc, start, count, &state, bindings); - if (rv && !context->isInternal && ep->isDebugging) - context->asQDeclarativeContextPrivate()->instances.append(rv); + if (ep->isDebugging && rv) { + if (!context->isInternal) + context->asQDeclarativeContextPrivate()->instances.append(rv); + QDeclarativeEngineDebugServer::instance()->objectCreated(engine, rv); + } return rv; } diff --git a/src/declarative/qml/qdeclarativeenginedebug.cpp b/src/declarative/qml/qdeclarativeenginedebug.cpp index 056d8a0..ed28185 100644 --- a/src/declarative/qml/qdeclarativeenginedebug.cpp +++ b/src/declarative/qml/qdeclarativeenginedebug.cpp @@ -604,4 +604,19 @@ void QDeclarativeEngineDebugServer::remEngine(QDeclarativeEngine *engine) m_engines.removeAll(engine); } +void QDeclarativeEngineDebugServer::objectCreated(QDeclarativeEngine *engine, QObject *object) +{ + Q_ASSERT(engine); + Q_ASSERT(m_engines.contains(engine)); + + int engineId = QDeclarativeDebugService::idForObject(engine); + int objectId = QDeclarativeDebugService::idForObject(object); + + QByteArray reply; + QDataStream rs(&reply, QIODevice::WriteOnly); + + rs << QByteArray("OBJECT_CREATED") << engineId << objectId; + sendMessage(reply); +} + QT_END_NAMESPACE diff --git a/src/declarative/qml/qdeclarativeenginedebug_p.h b/src/declarative/qml/qdeclarativeenginedebug_p.h index 4704393..613f1fe 100644 --- a/src/declarative/qml/qdeclarativeenginedebug_p.h +++ b/src/declarative/qml/qdeclarativeenginedebug_p.h @@ -94,6 +94,7 @@ public: void addEngine(QDeclarativeEngine *); void remEngine(QDeclarativeEngine *); + void objectCreated(QDeclarativeEngine *, QObject *); static QDeclarativeEngineDebugServer *instance(); -- cgit v0.12 From d8cd04e97540ac1c048a35ad54c8c6337d639ca1 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Tue, 24 Aug 2010 20:17:48 +0200 Subject: Fix building of qsimd.cpp on Windows CE --- src/corelib/tools/qsimd.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/corelib/tools/qsimd.cpp b/src/corelib/tools/qsimd.cpp index c34644c..68ab033 100644 --- a/src/corelib/tools/qsimd.cpp +++ b/src/corelib/tools/qsimd.cpp @@ -63,6 +63,8 @@ QT_BEGIN_NAMESPACE #if defined (Q_OS_WINCE) static inline uint detectProcessorFeatures() { + uint features = 0; + #if defined (ARM) if (IsProcessorFeaturePresent(PF_ARM_INTEL_WMMX)) { features = IWMMXT; -- cgit v0.12 From a60940d89cf7bf075e5b1f2055d63477d1187125 Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Tue, 24 Aug 2010 20:36:28 +0200 Subject: Stabilize tst_qgraphicsscene --- tests/auto/qgraphicsscene/tst_qgraphicsscene.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/auto/qgraphicsscene/tst_qgraphicsscene.cpp b/tests/auto/qgraphicsscene/tst_qgraphicsscene.cpp index 7ee2a48..c145623 100644 --- a/tests/auto/qgraphicsscene/tst_qgraphicsscene.cpp +++ b/tests/auto/qgraphicsscene/tst_qgraphicsscene.cpp @@ -4581,13 +4581,13 @@ void tst_QGraphicsScene::zeroScale() rect1->setScale(0.00000001); QApplication::processEvents(); - QCOMPARE(cl.changes.count(), 1); + QTRY_COMPARE(cl.changes.count(), 1); QGraphicsRectItem *rect2 = new QGraphicsRectItem(-0.0000001, -0.0000001, 0.0000001, 0.0000001); rect2->setScale(0.00000001); scene.addItem(rect2); rect1->setPos(20,20); QApplication::processEvents(); - QCOMPARE(cl.changes.count(), 2); + QTRY_COMPARE(cl.changes.count(), 2); } QTEST_MAIN(tst_QGraphicsScene) -- cgit v0.12 From ed1fecfe6b7ce370184ef4dfb421fb387807633b Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Tue, 24 Aug 2010 23:22:13 +0200 Subject: Add the missing license headers to the QString benchmark data --- tests/auto/headers/tst_headers.cpp | 3 +- tests/benchmarks/corelib/tools/qstring/data.cpp | 1 + tests/benchmarks/corelib/tools/qstring/data.h | 41 ++++++++++++++++++++++ .../corelib/tools/qstring/generatelist.pl | 3 +- 4 files changed, 46 insertions(+), 2 deletions(-) diff --git a/tests/auto/headers/tst_headers.cpp b/tests/auto/headers/tst_headers.cpp index 06c70f9..7ccf058 100644 --- a/tests/auto/headers/tst_headers.cpp +++ b/tests/auto/headers/tst_headers.cpp @@ -213,7 +213,8 @@ void tst_Headers::licenseCheck() return; if (content.first().contains("generated")) { - content.takeFirst(); + // don't scan generated files + return; } if (sourceFile.endsWith("/tests/auto/linguist/lupdate/testdata/good/merge_ordering/foo.cpp") diff --git a/tests/benchmarks/corelib/tools/qstring/data.cpp b/tests/benchmarks/corelib/tools/qstring/data.cpp index 89f50d0..6d1a069 100644 --- a/tests/benchmarks/corelib/tools/qstring/data.cpp +++ b/tests/benchmarks/corelib/tools/qstring/data.cpp @@ -1,3 +1,4 @@ +// This is a generated file - DO NOT EDIT static const ushort stringCollectionData[] __attribute__((aligned(16))) = { // #0 65535, diff --git a/tests/benchmarks/corelib/tools/qstring/data.h b/tests/benchmarks/corelib/tools/qstring/data.h index a23dae3..c7a7467 100644 --- a/tests/benchmarks/corelib/tools/qstring/data.h +++ b/tests/benchmarks/corelib/tools/qstring/data.h @@ -1,3 +1,44 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + #include struct StringCollection diff --git a/tests/benchmarks/corelib/tools/qstring/generatelist.pl b/tests/benchmarks/corelib/tools/qstring/generatelist.pl index 2777329..d027adb 100644 --- a/tests/benchmarks/corelib/tools/qstring/generatelist.pl +++ b/tests/benchmarks/corelib/tools/qstring/generatelist.pl @@ -105,7 +105,8 @@ sub printUshortArray($$$) { print "#include \"data.h\"\n\n"; -print "const ushort stringCollectionData[] __attribute__((aligned(64))) = { \n"; +print "// This is a generated file - DO NOT EDIT\n"; +print "const ushort stringCollectionData[] __attribute__((aligned(64))) = {\n"; $count = 0; $offset = 0; $totalsize = 0; -- cgit v0.12