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 
Test(std::uint64_t x)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 
Test(std::uint64_t x,std::uint64_t y)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
ToNative(U128 n)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 
FromNative(__uint128_t n)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 
TestVsNative(__uint128_t x,__uint128_t y)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 
TestVsNative()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(m, n);
99       TestVsNative(~m, n);
100       TestVsNative(m, ~n);
101       TestVsNative(~m, ~n);
102       TestVsNative(m ^ n, n);
103       TestVsNative(m, m ^ n);
104       TestVsNative(m ^ ~n, n);
105       TestVsNative(m, ~m ^ n);
106       TestVsNative(m ^ ~n, m ^ n);
107       TestVsNative(m ^ n, ~m ^ n);
108       TestVsNative(m ^ ~n, ~m ^ n);
109       Test(m, 10000000000000000); // important case for decimal conversion
110       Test(~m, 10000000000000000);
111     }
112   }
113 }
114 #endif
115 
main()116 int main() {
117   for (std::uint64_t j{0}; j < 64; ++j) {
118     Test(j);
119     Test(~j);
120     Test(std::uint64_t(1) << j);
121     for (std::uint64_t k{0}; k < 64; ++k) {
122       Test(j, 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