From accfdc85e5cb1816b3eda02ec8d37474259c247e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Abecasis?= Date: Mon, 12 Mar 2012 17:14:48 +0100 Subject: [PATCH] Fallback implementation of Q_ALIGNOF For all practical purposes, the fallback introduced here returns the desired value. Having a fallback enables unconditional use of Q_ALIGNOF. For compilers that provide native support for it, Q_ALIGNOF is otherwise #defined in qcompilerdetection.h. Change-Id: Ie148ca8936cbbf8b80fe87771a14797c39a9d30c Reviewed-by: Marc Mutz Reviewed-by: Thiago Macieira --- src/corelib/global/qglobal.h | 50 ++++++++ src/corelib/kernel/qmetaobjectbuilder.cpp | 4 - src/corelib/tools/qcontiguouscache.h | 4 - src/corelib/tools/qhash.h | 5 - src/corelib/tools/qvector.h | 4 - .../corelib/global/qglobal/tst_qglobal.cpp | 111 ++++++++++++++++++ .../kernel/qmetatype/tst_qmetatype.cpp | 34 +----- 7 files changed, 165 insertions(+), 47 deletions(-) diff --git a/src/corelib/global/qglobal.h b/src/corelib/global/qglobal.h index d0d6e851ad1..ee577a75633 100644 --- a/src/corelib/global/qglobal.h +++ b/src/corelib/global/qglobal.h @@ -248,6 +248,56 @@ typedef quint64 qulonglong; #if defined(__cplusplus) +namespace QtPrivate { + template + struct AlignOfHelper + { + char c; + T type; + + AlignOfHelper(); + ~AlignOfHelper(); + }; + + template + struct AlignOf_Default + { + enum { Value = sizeof(AlignOfHelper) - sizeof(T) }; + }; + + template struct AlignOf : AlignOf_Default { }; + template struct AlignOf : AlignOf {}; + template struct AlignOf : AlignOf {}; + +#ifdef Q_COMPILER_RVALUE_REFS + template struct AlignOf : AlignOf {}; +#endif + +#if defined(Q_PROCESSOR_X86_32) && !defined(Q_OS_WIN) + template struct AlignOf_WorkaroundForI386Abi { enum { Value = sizeof(T) }; }; + + // x86 ABI weirdness + // Alignment of naked type is 8, but inside struct has alignment 4. + template <> struct AlignOf : AlignOf_WorkaroundForI386Abi {}; + template <> struct AlignOf : AlignOf_WorkaroundForI386Abi {}; + template <> struct AlignOf : AlignOf_WorkaroundForI386Abi {}; +#ifdef Q_CC_CLANG + // GCC and Clang seem to disagree wrt to alignment of arrays + template struct AlignOf : AlignOf_Default {}; + template struct AlignOf : AlignOf_Default {}; + template struct AlignOf : AlignOf_Default {}; +#endif +#endif +} // namespace QtPrivate + +#define QT_EMULATED_ALIGNOF(T) \ + (size_t(QT_PREPEND_NAMESPACE(QtPrivate)::AlignOf::Value)) + +#ifndef Q_ALIGNOF +#define Q_ALIGNOF(T) QT_EMULATED_ALIGNOF(T) +#endif + + /* quintptr and qptrdiff is guaranteed to be the same size as a pointer, i.e. diff --git a/src/corelib/kernel/qmetaobjectbuilder.cpp b/src/corelib/kernel/qmetaobjectbuilder.cpp index 59740960c9b..8d6d7cbe919 100644 --- a/src/corelib/kernel/qmetaobjectbuilder.cpp +++ b/src/corelib/kernel/qmetaobjectbuilder.cpp @@ -1095,11 +1095,7 @@ int QMetaStringTable::enter(const QByteArray &value) int QMetaStringTable::preferredAlignment() { -#ifdef Q_ALIGNOF return Q_ALIGNOF(QByteArrayData); -#else - return sizeof(void *); -#endif } // Returns the size (in bytes) required for serializing this string table. diff --git a/src/corelib/tools/qcontiguouscache.h b/src/corelib/tools/qcontiguouscache.h index 4dc763f35de..4e01d7b5862 100644 --- a/src/corelib/tools/qcontiguouscache.h +++ b/src/corelib/tools/qcontiguouscache.h @@ -170,11 +170,7 @@ private: } int alignOfTypedData() const { -#ifdef Q_ALIGNOF return qMax(sizeof(void*), Q_ALIGNOF(Data)); -#else - return 0; -#endif } }; diff --git a/src/corelib/tools/qhash.h b/src/corelib/tools/qhash.h index 73162b6cf1a..ef003c8a71f 100644 --- a/src/corelib/tools/qhash.h +++ b/src/corelib/tools/qhash.h @@ -257,13 +257,8 @@ class QHash return reinterpret_cast(node); } -#ifdef Q_ALIGNOF static inline int alignOfNode() { return qMax(sizeof(void*), Q_ALIGNOF(Node)); } static inline int alignOfDummyNode() { return qMax(sizeof(void*), Q_ALIGNOF(DummyNode)); } -#else - static inline int alignOfNode() { return 0; } - static inline int alignOfDummyNode() { return 0; } -#endif public: inline QHash() : d(const_cast(&QHashData::shared_null)) { } diff --git a/src/corelib/tools/qvector.h b/src/corelib/tools/qvector.h index 226d0bb258a..04ab9e6e80d 100644 --- a/src/corelib/tools/qvector.h +++ b/src/corelib/tools/qvector.h @@ -331,11 +331,7 @@ private: } static Q_DECL_CONSTEXPR int alignOfTypedData() { -#ifdef Q_ALIGNOF return Q_ALIGNOF(AlignmentDummy); -#else - return sizeof(void *); -#endif } }; diff --git a/tests/auto/corelib/global/qglobal/tst_qglobal.cpp b/tests/auto/corelib/global/qglobal/tst_qglobal.cpp index b3d76bef8a0..529bafaa7a1 100644 --- a/tests/auto/corelib/global/qglobal/tst_qglobal.cpp +++ b/tests/auto/corelib/global/qglobal/tst_qglobal.cpp @@ -56,6 +56,7 @@ private slots: void qstaticassert(); void qConstructorFunction(); void isEnum(); + void qAlignOf(); }; void tst_QGlobal::qIsNull() @@ -415,5 +416,115 @@ void tst_QGlobal::isEnum() #undef IS_ENUM_FALSE } +struct Empty {}; +template struct AlignmentInStruct { T dummy; }; + +typedef int (*fun) (); +typedef int (Empty::*memFun) (); + +#define TEST_AlignOf(type, alignment) \ + do { \ + TEST_AlignOf_impl(type, alignment); \ + \ + TEST_AlignOf_impl(type &, alignment); \ + TEST_AlignOf_RValueRef(type &&, alignment); \ + \ + TEST_AlignOf_impl(type [5], alignment); \ + TEST_AlignOf_impl(type (&) [5], alignment); \ + \ + TEST_AlignOf_impl(AlignmentInStruct, alignment); \ + \ + /* Some internal sanity validation, just for fun */ \ + TEST_AlignOf_impl(AlignmentInStruct, alignment); \ + TEST_AlignOf_impl(AlignmentInStruct, Q_ALIGNOF(void *)); \ + TEST_AlignOf_impl(AlignmentInStruct, \ + Q_ALIGNOF(void *)); \ + TEST_AlignOf_RValueRef(AlignmentInStruct, \ + Q_ALIGNOF(void *)); \ + } while (false) \ + /**/ + +#ifdef Q_COMPILER_RVALUE_REFS +#define TEST_AlignOf_RValueRef(type, alignment) \ + TEST_AlignOf_impl(type, alignment) +#else +#define TEST_AlignOf_RValueRef(type, alignment) do {} while (false) +#endif + +#define TEST_AlignOf_impl(type, alignment) \ + do { \ + QCOMPARE(Q_ALIGNOF(type), size_t(alignment)); \ + /* Compare to native operator for compilers that support it, + otherwise... erm... check consistency! :-) */ \ + QCOMPARE(QT_EMULATED_ALIGNOF(type), Q_ALIGNOF(type)); \ + } while (false) + /**/ + +void tst_QGlobal::qAlignOf() +{ + // Built-in types, except 64-bit integers and double + TEST_AlignOf(char, 1); + TEST_AlignOf(signed char, 1); + TEST_AlignOf(unsigned char, 1); + TEST_AlignOf(qint8, 1); + TEST_AlignOf(quint8, 1); + TEST_AlignOf(qint16, 2); + TEST_AlignOf(quint16, 2); + TEST_AlignOf(qint32, 4); + TEST_AlignOf(quint32, 4); + TEST_AlignOf(void *, sizeof(void *)); + + // Depends on platform and compiler, disabling test for now + // TEST_AlignOf(long double, 16); + + // Empty struct + TEST_AlignOf(Empty, 1); + + // Function pointers + TEST_AlignOf(fun, Q_ALIGNOF(void *)); + TEST_AlignOf(memFun, Q_ALIGNOF(void *)); + + + // 64-bit integers and double + TEST_AlignOf_impl(qint64, 8); + TEST_AlignOf_impl(quint64, 8); + TEST_AlignOf_impl(double, 8); + + TEST_AlignOf_impl(qint64 &, 8); + TEST_AlignOf_impl(quint64 &, 8); + TEST_AlignOf_impl(double &, 8); + + TEST_AlignOf_RValueRef(qint64 &&, 8); + TEST_AlignOf_RValueRef(quint64 &&, 8); + TEST_AlignOf_RValueRef(double &&, 8); + + // 32-bit x86 ABI idiosyncrasies +#if defined(Q_PROCESSOR_X86_32) && !defined(Q_OS_WIN) + TEST_AlignOf_impl(AlignmentInStruct, 4); +#else + TEST_AlignOf_impl(AlignmentInStruct, 8); +#endif + + TEST_AlignOf_impl(AlignmentInStruct, Q_ALIGNOF(AlignmentInStruct)); + TEST_AlignOf_impl(AlignmentInStruct, Q_ALIGNOF(AlignmentInStruct)); + + // 32-bit x86 ABI, Clang disagrees with gcc +#if !defined(Q_PROCESSOR_X86_32) || !defined(Q_CC_CLANG) + TEST_AlignOf_impl(qint64 [5], Q_ALIGNOF(qint64)); +#else + TEST_AlignOf_impl(qint64 [5], Q_ALIGNOF(AlignmentInStruct)); +#endif + + TEST_AlignOf_impl(qint64 (&) [5], Q_ALIGNOF(qint64 [5])); + TEST_AlignOf_impl(quint64 [5], Q_ALIGNOF(quint64 [5])); + TEST_AlignOf_impl(quint64 (&) [5], Q_ALIGNOF(quint64 [5])); + TEST_AlignOf_impl(double [5], Q_ALIGNOF(double [5])); + TEST_AlignOf_impl(double (&) [5], Q_ALIGNOF(double [5])); +} + +#undef TEST_AlignOf +#undef TEST_AlignOf_RValueRef +#undef TEST_AlignOf_impl + QTEST_MAIN(tst_QGlobal) #include "tst_qglobal.moc" diff --git a/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp b/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp index 72ad3080d62..9f4944b44b3 100644 --- a/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp +++ b/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp @@ -868,41 +868,15 @@ void tst_QMetaType::construct_data() create_data(); } -#ifndef Q_ALIGNOF -template -struct RoundToNextHighestPowerOfTwo -{ -private: - enum { V1 = N-1 }; - enum { V2 = V1 | (V1 >> 1) }; - enum { V3 = V2 | (V2 >> 2) }; - enum { V4 = V3 | (V3 >> 4) }; - enum { V5 = V4 | (V4 >> 8) }; - enum { V6 = V5 | (V5 >> 16) }; -public: - enum { Value = V6 + 1 }; -}; -#endif - -template -struct TypeAlignment -{ -#ifdef Q_ALIGNOF - enum { Value = Q_ALIGNOF(T) }; -#else - enum { Value = RoundToNextHighestPowerOfTwo::Value }; -#endif -}; - template static void testConstructHelper() { typedef typename MetaEnumToType::Type Type; QMetaType info(ID); int size = info.sizeOf(); - void *storage1 = qMallocAligned(size, TypeAlignment::Value); + void *storage1 = qMallocAligned(size, Q_ALIGNOF(Type)); void *actual1 = QMetaType::construct(ID, storage1, /*copy=*/0); - void *storage2 = qMallocAligned(size, TypeAlignment::Value); + void *storage2 = qMallocAligned(size, Q_ALIGNOF(Type)); void *actual2 = info.construct(storage2, /*copy=*/0); QCOMPARE(actual1, storage1); QCOMPARE(actual2, storage2); @@ -971,9 +945,9 @@ static void testConstructCopyHelper() QMetaType info(ID); int size = QMetaType::sizeOf(ID); QCOMPARE(info.sizeOf(), size); - void *storage1 = qMallocAligned(size, TypeAlignment::Value); + void *storage1 = qMallocAligned(size, Q_ALIGNOF(Type)); void *actual1 = QMetaType::construct(ID, storage1, expected); - void *storage2 = qMallocAligned(size, TypeAlignment::Value); + void *storage2 = qMallocAligned(size, Q_ALIGNOF(Type)); void *actual2 = info.construct(storage2, expected); QCOMPARE(actual1, storage1); QCOMPARE(actual2, storage2);