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