uint128.cpp
3.87 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
#define AVOID_NATIVE_UINT128_T 1
#include "flang/Common/uint128.h"
#include "testing.h"
#include "llvm/Support/raw_ostream.h"
#include <cinttypes>
#if (defined __GNUC__ || defined __clang__) && defined __SIZEOF_INT128__
#define HAS_NATIVE_UINT128_T 1
#else
#undef HAS_NATIVE_UINT128_T
#endif
using U128 = Fortran::common::UnsignedInt128;
static void Test(std::uint64_t x) {
U128 n{x};
MATCH(x, static_cast<std::uint64_t>(n));
MATCH(~x, static_cast<std::uint64_t>(~n));
MATCH(-x, static_cast<std::uint64_t>(-n));
MATCH(!x, static_cast<std::uint64_t>(!n));
TEST(n == n);
TEST(n + n == n * static_cast<U128>(2));
TEST(n - n == static_cast<U128>(0));
TEST(n + n == n << static_cast<U128>(1));
TEST(n + n == n << static_cast<U128>(1));
TEST((n + n) - n == n);
TEST(((n + n) >> static_cast<U128>(1)) == n);
if (x != 0) {
TEST(static_cast<U128>(0) / n == static_cast<U128>(0));
TEST(static_cast<U128>(n - 1) / n == static_cast<U128>(0));
TEST(static_cast<U128>(n) / n == static_cast<U128>(1));
TEST(static_cast<U128>(n + n - 1) / n == static_cast<U128>(1));
TEST(static_cast<U128>(n + n) / n == static_cast<U128>(2));
}
}
static void Test(std::uint64_t x, std::uint64_t y) {
U128 m{x}, n{y};
MATCH(x, static_cast<std::uint64_t>(m));
MATCH(y, static_cast<std::uint64_t>(n));
MATCH(x & y, static_cast<std::uint64_t>(m & n));
MATCH(x | y, static_cast<std::uint64_t>(m | n));
MATCH(x ^ y, static_cast<std::uint64_t>(m ^ n));
MATCH(x + y, static_cast<std::uint64_t>(m + n));
MATCH(x - y, static_cast<std::uint64_t>(m - n));
MATCH(x * y, static_cast<std::uint64_t>(m * n));
if (n != 0) {
MATCH(x / y, static_cast<std::uint64_t>(m / n));
}
}
#if HAS_NATIVE_UINT128_T
static __uint128_t ToNative(U128 n) {
return static_cast<__uint128_t>(static_cast<std::uint64_t>(n >> 64)) << 64 |
static_cast<std::uint64_t>(n);
}
static U128 FromNative(__uint128_t n) {
return U128{static_cast<std::uint64_t>(n >> 64)} << 64 |
U128{static_cast<std::uint64_t>(n)};
}
static void TestVsNative(__uint128_t x, __uint128_t y) {
U128 m{FromNative(x)}, n{FromNative(y)};
TEST(ToNative(m) == x);
TEST(ToNative(n) == y);
TEST(ToNative(~m) == ~x);
TEST(ToNative(-m) == -x);
TEST(ToNative(!m) == !x);
TEST(ToNative(m < n) == (x < y));
TEST(ToNative(m <= n) == (x <= y));
TEST(ToNative(m == n) == (x == y));
TEST(ToNative(m != n) == (x != y));
TEST(ToNative(m >= n) == (x >= y));
TEST(ToNative(m > n) == (x > y));
TEST(ToNative(m & n) == (x & y));
TEST(ToNative(m | n) == (x | y));
TEST(ToNative(m ^ n) == (x ^ y));
if (y < 128) {
TEST(ToNative(m << n) == (x << y));
TEST(ToNative(m >> n) == (x >> y));
}
TEST(ToNative(m + n) == (x + y));
TEST(ToNative(m - n) == (x - y));
TEST(ToNative(m * n) == (x * y));
if (y > 0) {
TEST(ToNative(m / n) == (x / y));
TEST(ToNative(m % n) == (x % y));
TEST(ToNative(m - n * (m / n)) == (x % y));
}
}
static void TestVsNative() {
for (int j{0}; j < 128; ++j) {
for (int k{0}; k < 128; ++k) {
__uint128_t m{1}, n{1};
m <<= j, n <<= k;
TestVsNative(m, n);
TestVsNative(~m, n);
TestVsNative(m, ~n);
TestVsNative(~m, ~n);
TestVsNative(m ^ n, n);
TestVsNative(m, m ^ n);
TestVsNative(m ^ ~n, n);
TestVsNative(m, ~m ^ n);
TestVsNative(m ^ ~n, m ^ n);
TestVsNative(m ^ n, ~m ^ n);
TestVsNative(m ^ ~n, ~m ^ n);
Test(m, 10000000000000000); // important case for decimal conversion
Test(~m, 10000000000000000);
}
}
}
#endif
int main() {
for (std::uint64_t j{0}; j < 64; ++j) {
Test(j);
Test(~j);
Test(std::uint64_t(1) << j);
for (std::uint64_t k{0}; k < 64; ++k) {
Test(j, k);
}
}
#if HAS_NATIVE_UINT128_T
llvm::outs() << "Environment has native __uint128_t\n";
TestVsNative();
#else
llvm::outs() << "Environment lacks native __uint128_t\n";
#endif
return testing::Complete();
}