summaryrefslogtreecommitdiffstats
path: root/tests/auto/corelib/global/qnumeric/tst_qnumeric.cpp
diff options
context:
space:
mode:
authorThiago Macieira <thiago.macieira@intel.com>2017-11-30 20:37:57 -0800
committerGabriel de Dietrich <gabriel.dedietrich@qt.io>2018-01-24 21:13:20 +0000
commit43c44d05ca6af4ec78c1dea84635375a637ff80d (patch)
tree268767b106cb5b74826711e687f3c6d937b229fb /tests/auto/corelib/global/qnumeric/tst_qnumeric.cpp
parent34e8cafa29a5240bb7a426c69a5fd8e8ad741dc4 (diff)
Update the overflow functions to include qsizetype
Commit 29bc68cf169b8cf87d306a1c72e12eb9b6fbfce7 added support for unsigned and commit 5ff7a3d96e0ce0dcb3d388b53d038cdd40c7a975 later added support for int. This commit adds support for qsizetype, which isn't int on 64-bit platforms. We do this by reorganizing the code and using the generic version of __builtin_{add,sub,mul}_overflow from GCC 5 and Clang 3.8, which ICC 18 seems to support now too on Linux. That leaves older versions of GCC and Clang, as well as MSVC, ICC on Windows, and the GHS compiler, to use the generic implementations, as I've removed the assembly code those versions of GCC and Clang on x86 are now uncommon. Note: any older version of ICC probably breaks. We only support the latest. Change-Id: I9e2892cb6c374e93bcb7fffd14fc11bcd5f067a7 Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'tests/auto/corelib/global/qnumeric/tst_qnumeric.cpp')
-rw-r--r--tests/auto/corelib/global/qnumeric/tst_qnumeric.cpp154
1 files changed, 145 insertions, 9 deletions
diff --git a/tests/auto/corelib/global/qnumeric/tst_qnumeric.cpp b/tests/auto/corelib/global/qnumeric/tst_qnumeric.cpp
index 8232ca8fba..03300c6dbe 100644
--- a/tests/auto/corelib/global/qnumeric/tst_qnumeric.cpp
+++ b/tests/auto/corelib/global/qnumeric/tst_qnumeric.cpp
@@ -223,11 +223,20 @@ void tst_QNumeric::floatDistance_double()
void tst_QNumeric::addOverflow_data()
{
QTest::addColumn<int>("size");
+
+ // for unsigned, all sizes are supported
QTest::newRow("quint8") << 8;
QTest::newRow("quint16") << 16;
QTest::newRow("quint32") << 32;
QTest::newRow("quint64") << 64;
QTest::newRow("ulong") << 48; // it's either 32- or 64-bit, so on average it's 48 :-)
+
+ // for signed, we can't guarantee 64-bit
+ QTest::newRow("qint8") << -8;
+ QTest::newRow("qint16") << -16;
+ QTest::newRow("qint32") << -32;
+ if (sizeof(void *) == sizeof(qint64))
+ QTest::newRow("qint64") << -64;
}
// Note: in release mode, all the tests may be statically determined and only the calls
@@ -238,6 +247,7 @@ template <typename Int> static void addOverflow_template()
QSKIP("Test disabled, this test generates an Internal Compiler Error compiling in release mode");
#else
const Int max = std::numeric_limits<Int>::max();
+ const Int min = std::numeric_limits<Int>::min();
Int r;
// basic values
@@ -248,15 +258,50 @@ template <typename Int> static void addOverflow_template()
QCOMPARE(add_overflow(Int(0), Int(1), &r), false);
QCOMPARE(r, Int(1));
+ QCOMPARE(sub_overflow(Int(0), Int(0), &r), false);
+ QCOMPARE(r, Int(0));
+ QCOMPARE(sub_overflow(Int(1), Int(0), &r), false);
+ QCOMPARE(r, Int(1));
+ QCOMPARE(sub_overflow(Int(1), Int(1), &r), false);
+ QCOMPARE(r, Int(0));
+ QCOMPARE(sub_overflow(Int(0), Int(1), &r), !min);
+ if (min)
+ QCOMPARE(r, Int(-1));
+
// half-way through max
QCOMPARE(add_overflow(Int(max/2), Int(max/2), &r), false);
QCOMPARE(r, Int(max / 2 * 2));
+ QCOMPARE(sub_overflow(Int(max/2), Int(max/2), &r), false);
+ QCOMPARE(r, Int(0));
QCOMPARE(add_overflow(Int(max/2 - 1), Int(max/2 + 1), &r), false);
QCOMPARE(r, Int(max / 2 * 2));
+ QCOMPARE(sub_overflow(Int(max/2 - 1), Int(max/2 + 1), &r), !min);
+ if (min)
+ QCOMPARE(r, Int(-2));
QCOMPARE(add_overflow(Int(max/2 + 1), Int(max/2), &r), false);
QCOMPARE(r, max);
+ QCOMPARE(sub_overflow(Int(max/2 + 1), Int(max/2), &r), false);
+ QCOMPARE(r, Int(1));
QCOMPARE(add_overflow(Int(max/2), Int(max/2 + 1), &r), false);
QCOMPARE(r, max);
+ QCOMPARE(sub_overflow(Int(max/2), Int(max/2 + 1), &r), !min);
+ if (min)
+ QCOMPARE(r, Int(-1));
+
+ QCOMPARE(add_overflow(Int(min/2), Int(min/2), &r), false);
+ QCOMPARE(r, Int(min / 2 * 2));
+ QCOMPARE(sub_overflow(Int(min/2), Int(min/2), &r), false);
+ QCOMPARE(r, Int(0));
+ QCOMPARE(add_overflow(Int(min/2 - 1), Int(min/2 + 1), &r), !min);
+ if (min)
+ QCOMPARE(r, Int(min / 2 * 2));
+ QCOMPARE(sub_overflow(Int(min/2 - 1), Int(min/2 + 1), &r), false);
+ QCOMPARE(r, Int(-2));
+ QCOMPARE(sub_overflow(Int(min/2 + 1), Int(min/2), &r), false);
+ QCOMPARE(r, Int(1));
+ QCOMPARE(sub_overflow(Int(min/2), Int(min/2 + 1), &r), !min);
+ if (min)
+ QCOMPARE(r, Int(-1));
// more than half
QCOMPARE(add_overflow(Int(max/4 * 3), Int(max/4), &r), false);
@@ -265,19 +310,55 @@ template <typename Int> static void addOverflow_template()
// max
QCOMPARE(add_overflow(max, Int(0), &r), false);
QCOMPARE(r, max);
+ QCOMPARE(sub_overflow(max, Int(0), &r), false);
+ QCOMPARE(r, max);
QCOMPARE(add_overflow(Int(0), max, &r), false);
QCOMPARE(r, max);
+ QCOMPARE(sub_overflow(Int(0), max, &r), !min);
+ if (min)
+ QCOMPARE(r, Int(-max));
+
+ QCOMPARE(add_overflow(min, Int(0), &r), false);
+ QCOMPARE(r, min);
+ QCOMPARE(sub_overflow(min, Int(0), &r), false);
+ QCOMPARE(r, min);
+ QCOMPARE(add_overflow(Int(0), min, &r), false);
+ QCOMPARE(r, min);
+ QCOMPARE(sub_overflow(Int(0), Int(min+1), &r), !min);
+ if (min)
+ QCOMPARE(r, Int(-(min+1)));
// 64-bit issues
if (max > std::numeric_limits<uint>::max()) {
QCOMPARE(add_overflow(Int(std::numeric_limits<uint>::max()), Int(std::numeric_limits<uint>::max()), &r), false);
QCOMPARE(r, Int(2 * Int(std::numeric_limits<uint>::max())));
+ QCOMPARE(sub_overflow(Int(std::numeric_limits<uint>::max()), Int(std::numeric_limits<uint>::max()), &r), false);
+ QCOMPARE(r, Int(0));
+ }
+ if (min && min < -Int(std::numeric_limits<uint>::max())) {
+ QCOMPARE(add_overflow(Int(-Int(std::numeric_limits<uint>::max())), Int(-Int(std::numeric_limits<uint>::max())), &r), false);
+ QCOMPARE(r, Int(-2 * Int(std::numeric_limits<uint>::max())));
+ QCOMPARE(sub_overflow(Int(-Int(std::numeric_limits<uint>::max())), Int(-Int(std::numeric_limits<uint>::max())), &r), false);
+ QCOMPARE(r, Int(0));
}
- // overflows
+ // overflows past max
QCOMPARE(add_overflow(max, Int(1), &r), true);
QCOMPARE(add_overflow(Int(1), max, &r), true);
QCOMPARE(add_overflow(Int(max/2 + 1), Int(max/2 + 1), &r), true);
+ if (!min) {
+ QCOMPARE(sub_overflow(Int(-max), Int(-2), &r), true);
+ QCOMPARE(sub_overflow(Int(max/2 - 1), Int(max/2 + 1), &r), true);
+ }
+
+ // overflows past min (in case of min == 0, repeats some tests above)
+ if (min) {
+ QCOMPARE(sub_overflow(min, Int(1), &r), true);
+ QCOMPARE(sub_overflow(Int(1), min, &r), true);
+ QCOMPARE(sub_overflow(Int(min/2 - 1), Int(-Int(min/2)), &r), true);
+ QCOMPARE(add_overflow(min, Int(-1), &r), true);
+ QCOMPARE(add_overflow(Int(-1), min, &r), true);
+ }
#endif
}
@@ -294,6 +375,15 @@ void tst_QNumeric::addOverflow()
addOverflow_template<ulong>(); // not really 48-bit
if (size == 64)
addOverflow_template<quint64>();
+
+ if (size == -8)
+ addOverflow_template<qint8>();
+ if (size == -16)
+ addOverflow_template<qint16>();
+ if (size == -32)
+ addOverflow_template<qint32>();
+ if (size == -64)
+ addOverflow_template<qint64>();
}
void tst_QNumeric::mulOverflow_data()
@@ -309,7 +399,13 @@ template <typename Int> static void mulOverflow_template()
QSKIP("Test disabled, this test generates an Internal Compiler Error compiling");
#else
const Int max = std::numeric_limits<Int>::max();
- const Int middle = Int(max >> (sizeof(Int) * CHAR_BIT / 2));
+ const Int min = std::numeric_limits<Int>::min();
+
+ // for unsigned (even number of significant bits): mid2 = mid1 - 1
+ // for signed (odd number of significant bits): mid2 = mid1 / 2 - 1
+ const Int mid1 = Int(Int(1) << sizeof(Int) * CHAR_BIT / 2);
+ const Int mid2 = (std::numeric_limits<Int>::digits % 2 ? mid1 / 2 : mid1) - 1;
+
Int r;
// basic multiplications
@@ -323,6 +419,10 @@ template <typename Int> static void mulOverflow_template()
QCOMPARE(r, Int(0));
QCOMPARE(mul_overflow(Int(0), max, &r), false);
QCOMPARE(r, Int(0));
+ QCOMPARE(mul_overflow(min, Int(0), &r), false);
+ QCOMPARE(r, Int(0));
+ QCOMPARE(mul_overflow(Int(0), min, &r), false);
+ QCOMPARE(r, Int(0));
QCOMPARE(mul_overflow(Int(1), Int(1), &r), false);
QCOMPARE(r, Int(1));
@@ -330,23 +430,45 @@ template <typename Int> static void mulOverflow_template()
QCOMPARE(r, max);
QCOMPARE(mul_overflow(max, Int(1), &r), false);
QCOMPARE(r, max);
+ QCOMPARE(mul_overflow(Int(1), min, &r), false);
+ QCOMPARE(r, min);
+ QCOMPARE(mul_overflow(min, Int(1), &r), false);
+ QCOMPARE(r, min);
// almost max
- QCOMPARE(mul_overflow(middle, middle, &r), false);
- QCOMPARE(r, Int(max - 2 * middle));
- QCOMPARE(mul_overflow(Int(middle + 1), middle, &r), false);
- QCOMPARE(r, Int(middle << (sizeof(Int) * CHAR_BIT / 2)));
- QCOMPARE(mul_overflow(middle, Int(middle + 1), &r), false);
- QCOMPARE(r, Int(middle << (sizeof(Int) * CHAR_BIT / 2)));
+ QCOMPARE(mul_overflow(mid1, mid2, &r), false);
+ QCOMPARE(r, Int(max - mid1 + 1));
QCOMPARE(mul_overflow(Int(max / 2), Int(2), &r), false);
QCOMPARE(r, Int(max & ~Int(1)));
QCOMPARE(mul_overflow(Int(max / 4), Int(4), &r), false);
QCOMPARE(r, Int(max & ~Int(3)));
+ if (min) {
+ QCOMPARE(mul_overflow(Int(-mid1), mid2, &r), false);
+ QCOMPARE(r, Int(-max + mid1 - 1));
+ QCOMPARE(mul_overflow(Int(-max / 2), Int(2), &r), false);
+ QCOMPARE(r, Int(-max + 1));
+ QCOMPARE(mul_overflow(Int(-max / 4), Int(4), &r), false);
+ QCOMPARE(r, Int(-max + 3));
+
+ QCOMPARE(mul_overflow(Int(-mid1), Int(mid2 + 1), &r), false);
+ QCOMPARE(r, min);
+ QCOMPARE(mul_overflow(mid1, Int(-mid2 - 1), &r), false);
+ QCOMPARE(r, min);
+ }
// overflows
QCOMPARE(mul_overflow(max, Int(2), &r), true);
QCOMPARE(mul_overflow(Int(max / 2), Int(3), &r), true);
- QCOMPARE(mul_overflow(Int(middle + 1), Int(middle + 1), &r), true);
+ QCOMPARE(mul_overflow(mid1, Int(mid2 + 1), &r), true);
+ QCOMPARE(mul_overflow(Int(max / 2 + 2), Int(2), &r), true);
+ QCOMPARE(mul_overflow(Int(1ULL << (std::numeric_limits<Int>::digits - 1)), Int(2), &r), true);
+
+ if (min) {
+ QCOMPARE(mul_overflow(min, Int(2), &r), true);
+ QCOMPARE(mul_overflow(Int(min / 2), Int(3), &r), true);
+ QCOMPARE(mul_overflow(Int(min / 2 - 1), Int(2), &r), true);
+ QCOMPARE(mul_overflow(Int(min + min/2), Int(2), &r), true);
+ }
#endif
}
@@ -373,6 +495,20 @@ void tst_QNumeric::mulOverflow()
MulOverflowDispatch<ulong>()(); // not really 48-bit
if (size == 64)
MulOverflowDispatch<quint64>()();
+
+ if (size == -8)
+ MulOverflowDispatch<qint8>()();
+ if (size == -16)
+ MulOverflowDispatch<qint16>()();
+ if (size == -32)
+ MulOverflowDispatch<qint32>()();
+ if (size == -64) {
+#if QT_POINTER_SIZE == 8
+ MulOverflowDispatch<qint64>()();
+#else
+ QFAIL("128-bit multiplication not supported on this platform");
+#endif
+ }
}
void tst_QNumeric::signedOverflow()