qfloat16: extend comparison with integral types

qfloat16 implemented comparison with int, but not with other integral
types. As a result, comparing qfloat16 vs qint64 or short was
ambiguous, because the compiler had (at least) two options:
* qint64 -> int
* qint64 -> float

Fix it by explicitly introducing comparison operators for other integral
types.
Use the new compare helper macros for that, and implement helper methods
as templates restricted on integral types.

Note that we have to manually extend the std::is_integral type trait
because libstdc++ only treats __{u}int128_t types as integral when
compiling in -std=gnu++XX mode, and we compile Qt in -std=c++XX mode.

Fixes: QTBUG-117637
Change-Id: Id0c074af1e9ccc2c2492eb2cc4ee62a4a7131b07
Reviewed-by: Marc Mutz <marc.mutz@qt.io>
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
This commit is contained in:
Ivan Solovev 2023-10-30 18:43:20 +01:00
parent e1eec6476a
commit 0d85d0a72f
2 changed files with 68 additions and 7 deletions

View File

@ -14,6 +14,7 @@
#include <limits>
#include <string.h>
#include <type_traits>
#if defined(QT_COMPILER_SUPPORTS_F16C) && defined(__AVX2__) && !defined(__F16C__)
// All processors that support AVX2 do support F16C too, so we could enable the
@ -51,6 +52,19 @@ class qfloat16
constexpr inline explicit Wrap(int value) : b16(quint16(value)) {}
};
#ifdef QT_SUPPORTS_INT128
template <typename T>
using IsIntegral = std::disjunction<std::is_integral<T>,
std::is_same<std::remove_const_t<T>, qint128>,
std::is_same<std::remove_const_t<T>, quint128>>;
#else
template <typename T>
using IsIntegral = std::is_integral<T>;
#endif
template <typename T>
using if_type_is_integral = std::enable_if_t<IsIntegral<std::remove_reference_t<T>>::value,
bool>;
public:
using NativeType = QtPrivate::NativeFloat16Type;
@ -189,11 +203,27 @@ QT_WARNING_DISABLE_FLOAT_COMPARE
#endif
#undef QF16_MAKE_ORDER_OP_FP
friend bool comparesEqual(const qfloat16 &lhs, int rhs) noexcept
template <typename T, if_type_is_integral<T> = true>
friend bool comparesEqual(const qfloat16 &lhs, T rhs) noexcept
{ return static_cast<NearestFloat>(lhs) == static_cast<NearestFloat>(rhs); }
friend Qt::partial_ordering compareThreeWay(const qfloat16 &lhs, int rhs) noexcept
template <typename T, if_type_is_integral<T> = true>
friend Qt::partial_ordering compareThreeWay(const qfloat16 &lhs, T rhs) noexcept
{ return Qt::compareThreeWay(static_cast<NearestFloat>(lhs), static_cast<NearestFloat>(rhs)); }
Q_DECLARE_PARTIALLY_ORDERED(qfloat16, int)
Q_DECLARE_PARTIALLY_ORDERED(qfloat16, qint8)
Q_DECLARE_PARTIALLY_ORDERED(qfloat16, quint8)
Q_DECLARE_PARTIALLY_ORDERED(qfloat16, qint16)
Q_DECLARE_PARTIALLY_ORDERED(qfloat16, quint16)
Q_DECLARE_PARTIALLY_ORDERED(qfloat16, qint32)
Q_DECLARE_PARTIALLY_ORDERED(qfloat16, quint32)
Q_DECLARE_PARTIALLY_ORDERED(qfloat16, long)
Q_DECLARE_PARTIALLY_ORDERED(qfloat16, unsigned long)
Q_DECLARE_PARTIALLY_ORDERED(qfloat16, qint64)
Q_DECLARE_PARTIALLY_ORDERED(qfloat16, quint64)
#ifdef QT_SUPPORTS_INT128
Q_DECLARE_PARTIALLY_ORDERED(qfloat16, qint128)
Q_DECLARE_PARTIALLY_ORDERED(qfloat16, quint128)
#endif
QT_WARNING_POP

View File

@ -62,6 +62,22 @@ void tst_qfloat16::compareCompiles()
QTestPrivate::testAllComparisonOperatorsCompile<qfloat16, qfloat16::NativeType>();
#endif
QTestPrivate::testAllComparisonOperatorsCompile<qfloat16, int>();
QTestPrivate::testAllComparisonOperatorsCompile<qfloat16, qint8>();
QTestPrivate::testAllComparisonOperatorsCompile<qfloat16, quint8>();
QTestPrivate::testAllComparisonOperatorsCompile<qfloat16, qint16>();
QTestPrivate::testAllComparisonOperatorsCompile<qfloat16, quint16>();
QTestPrivate::testAllComparisonOperatorsCompile<qfloat16, char16_t>();
QTestPrivate::testAllComparisonOperatorsCompile<qfloat16, long>();
QTestPrivate::testAllComparisonOperatorsCompile<qfloat16, unsigned long>();
QTestPrivate::testAllComparisonOperatorsCompile<qfloat16, wchar_t>();
QTestPrivate::testAllComparisonOperatorsCompile<qfloat16, qint32>();
QTestPrivate::testAllComparisonOperatorsCompile<qfloat16, quint32>();
QTestPrivate::testAllComparisonOperatorsCompile<qfloat16, qint64>();
QTestPrivate::testAllComparisonOperatorsCompile<qfloat16, quint64>();
#ifdef QT_SUPPORTS_INT128
QTestPrivate::testAllComparisonOperatorsCompile<qfloat16, qint128>();
QTestPrivate::testAllComparisonOperatorsCompile<qfloat16, quint128>();
#endif
}
void tst_qfloat16::ordering_data()
@ -142,10 +158,25 @@ void tst_qfloat16::ordering()
if (qIsFinite(right)) {
CHECK_INT(int);
// These fail because of QTBUG-117637. Will be fixed in a follow-up patch.
// CHECK_INT(qint8);
// CHECK_INT(qint16);
// CHECK_INT(qint64);
CHECK_INT(qint8);
CHECK_INT(signed char);
CHECK_INT(qint16);
CHECK_INT(qint32);
CHECK_INT(qint64);
#if QT_SUPPORTS_INT128
CHECK_INT(qint128);
#endif
if (right >= 0) {
CHECK_INT(unsigned int);
CHECK_INT(quint8);
CHECK_INT(unsigned char);
CHECK_INT(quint16);
CHECK_INT(quint32);
CHECK_INT(quint64);
#if QT_SUPPORTS_INT128
CHECK_INT(quint128);
#endif
}
}
#undef CHECK_INT