1 #include "flang/Evaluate/integer.h"
2 #include "testing.h"
3 #include <cstdio>
4 #include <string>
5 
6 using Fortran::evaluate::Ordering;
7 using Fortran::evaluate::value::Integer;
8 
exhaustiveTesting()9 template <int BITS, typename INT = Integer<BITS>> void exhaustiveTesting() {
10   std::uint64_t maxUnsignedValue{(std::uint64_t{1} << BITS) - 1};
11   std::int64_t maxPositiveSignedValue{(std::int64_t{1} << (BITS - 1)) - 1};
12   std::int64_t mostNegativeSignedValue{-(std::int64_t{1} << (BITS - 1))};
13   char desc[64];
14   std::snprintf(desc, sizeof desc,
15       "BITS=%d, PARTBITS=%d, sizeof(Part)=%d, LE=%d", BITS, INT::partBits,
16       static_cast<int>(sizeof(typename INT::Part)), INT::littleEndian);
17 
18   MATCH(BITS, INT::bits)(desc);
19   MATCH(maxPositiveSignedValue, INT::HUGE().ToUInt64())(desc);
20   INT zero;
21   TEST(zero.IsZero())(desc);
22   MATCH(0, zero.ToUInt64())(desc);
23   MATCH(0, zero.ToInt64())(desc);
24 
25   for (std::uint64_t x{0}; x <= maxUnsignedValue; ++x) {
26     unsigned long long ullx = x;
27     INT a{x};
28     MATCH(x, a.ToUInt64())(desc);
29     INT copy{a};
30     MATCH(x, copy.ToUInt64())(desc);
31     copy = a;
32     MATCH(x, copy.ToUInt64())(desc);
33     MATCH(x == 0, a.IsZero())("%s, x=0x%llx", desc, x);
34     char buffer[64];
35     std::snprintf(buffer, sizeof buffer, "   %llu", ullx);
36     const char *p{buffer};
37     auto readcheck{INT::Read(p)};
38     TEST(!readcheck.overflow)("%s, x=0x%llx", desc, x);
39     MATCH(x, readcheck.value.ToUInt64())("%s, x=0x%llx", desc, x);
40     TEST(!*p)("%s, x=0x%llx", desc, x);
41     std::snprintf(buffer, sizeof buffer, "%llx", ullx);
42     p = buffer;
43     readcheck = INT::Read(p, 16);
44     TEST(!readcheck.overflow)("%s, x=0x%llx", desc, x);
45     MATCH(x, readcheck.value.ToUInt64())("%s, x=0x%llx", desc, x);
46     TEST(!*p)("%s, x=0x%llx", desc, x);
47     std::string udec{a.UnsignedDecimal()};
48     p = udec.data();
49     readcheck = INT::Read(p);
50     TEST(!readcheck.overflow)("%s, x=0x%llx", desc, x);
51     MATCH(x, readcheck.value.ToUInt64())("%s, x=0x%llx", desc, x);
52     TEST(!*p)("%s, x=0x%llx", desc, x);
53     std::string hex{a.Hexadecimal()};
54     p = hex.data();
55     readcheck = INT::Read(p, 16);
56     TEST(!readcheck.overflow)("%s, x=0x%llx", desc, x);
57     MATCH(x, readcheck.value.ToUInt64())("%s, x=0x%llx", desc, x);
58     TEST(!*p)("%s, x=0x%llx", desc, x);
59     INT t{a.NOT()};
60     MATCH(x ^ maxUnsignedValue, t.ToUInt64())("%s, x=0x%llx", desc, x);
61     auto negated{a.Negate()};
62     MATCH(x == std::uint64_t{1} << (BITS - 1), negated.overflow)
63     ("%s, x=0x%llx", desc, x);
64     MATCH(-x & maxUnsignedValue, negated.value.ToUInt64())
65     ("%s, x=0x%llx", desc, x);
66     auto abs{a.ABS()};
67     MATCH(x == std::uint64_t{1} << (BITS - 1), abs.overflow)
68     ("%s, x=0x%llx", desc, x);
69     MATCH(x >> (BITS - 1) ? -x & maxUnsignedValue : x, abs.value.ToUInt64())
70     ("%s, x=0x%llx", desc, x);
71     int lzbc{a.LEADZ()};
72     COMPARE(lzbc, >=, 0)("%s, x=0x%llx", desc, x);
73     COMPARE(lzbc, <=, BITS)("%s, x=0x%llx", desc, x);
74     MATCH(x == 0, lzbc == BITS)("%s, x=0x%llx, lzbc=%d", desc, x, lzbc);
75     std::uint64_t lzcheck{std::uint64_t{1} << (BITS - lzbc)};
76     COMPARE(x, <, lzcheck)("%s, x=0x%llx, lzbc=%d", desc, x, lzbc);
77     COMPARE(x + x + !x, >=, lzcheck)("%s, x=0x%llx, lzbc=%d", desc, x, lzbc);
78     int popcheck{0};
79     for (int j{0}; j < BITS; ++j) {
80       popcheck += (x >> j) & 1;
81     }
82     MATCH(popcheck, a.POPCNT())("%s, x=0x%llx", desc, x);
83     MATCH(popcheck & 1, a.POPPAR())("%s, x=0x%llx", desc, x);
84     int trailcheck{0};
85     for (; trailcheck < BITS; ++trailcheck) {
86       if ((x >> trailcheck) & 1) {
87         break;
88       }
89     }
90     MATCH(trailcheck, a.TRAILZ())("%s, x=0x%llx", desc, x);
91     for (int j{0}; j < BITS; ++j) {
92       MATCH((x >> j) & 1, a.BTEST(j))
93       ("%s, x=0x%llx, bit %d", desc, x, j);
94     }
95     // TODO test DIM, MODULO, ISHFTC, DSHIFTL/R
96     // TODO test IBCLR, IBSET, IBITS, MAX, MIN, MERGE_BITS, RANGE, SIGN
97 
98     Ordering ord{Ordering::Equal};
99     std::int64_t sx = x;
100     if (x + x > maxUnsignedValue) {
101       TEST(a.IsNegative())("%s, x=0x%llx", desc, x);
102       sx = x | (~std::uint64_t{0} << BITS);
103       TEST(sx < 0)("%s, x=0x%llx %lld", desc, x, sx);
104       ord = Ordering::Less;
105     } else {
106       TEST(!a.IsNegative())("%s, x=0x%llx", desc, x);
107       TEST(sx >= 0)("%s, x=0x%llx %lld", desc, x, sx);
108       if (sx > 0) {
109         ord = Ordering::Greater;
110       } else {
111         ord = Ordering::Equal;
112       }
113     }
114 
115     TEST(sx == a.ToInt64())("%s, x=0x%llx %lld", desc, x, sx);
116     TEST(a.CompareToZeroSigned() == ord)("%s, x=0x%llx %lld", desc, x, sx);
117     for (int count{0}; count <= BITS + 1; ++count) {
118       t = a.SHIFTL(count);
119       MATCH((x << count) & maxUnsignedValue, t.ToUInt64())
120       ("%s, x=0x%llx, count=%d", desc, x, count);
121       t = a.ISHFT(count);
122       MATCH((x << count) & maxUnsignedValue, t.ToUInt64())
123       ("%s, x=0x%llx, count=%d", desc, x, count);
124       t = a.SHIFTR(count);
125       MATCH(x >> count, t.ToUInt64())
126       ("%s, x=0x%llx, count=%d", desc, x, count);
127       t = a.ISHFT(-count);
128       MATCH(x >> count, t.ToUInt64())("%s, x=0x%llx, count=%d", desc, x, count);
129       t = a.SHIFTA(count);
130       std::uint64_t fill{-(x >> (BITS - 1))};
131       std::uint64_t sra{
132           count >= BITS ? fill : (x >> count) | (fill << (BITS - count))};
133       MATCH(sra, t.ToInt64())
134       ("%s, x=0x%llx, count=%d", desc, x, count);
135     }
136 
137     for (std::uint64_t y{0}; y <= maxUnsignedValue; ++y) {
138       std::int64_t sy = y;
139       if (y + y > maxUnsignedValue) {
140         sy = y | (~std::uint64_t{0} << BITS);
141       }
142       INT b{y};
143       if (x < y) {
144         ord = Ordering::Less;
145       } else if (x > y) {
146         ord = Ordering::Greater;
147       } else {
148         ord = Ordering::Equal;
149       }
150       TEST(a.CompareUnsigned(b) == ord)("%s, x=0x%llx, y=0x%llx", desc, x, y);
151       MATCH(x >= y, a.BGE(b))("%s, x=0x%llx, y=0x%llx", desc, x, y);
152       MATCH(x > y, a.BGT(b))("%s, x=0x%llx, y=0x%llx", desc, x, y);
153       MATCH(x <= y, a.BLE(b))("%s, x=0x%llx, y=0x%llx", desc, x, y);
154       MATCH(x < y, a.BLT(b))("%s, x=0x%llx, y=0x%llx", desc, x, y);
155       if (sx < sy) {
156         ord = Ordering::Less;
157       } else if (sx > sy) {
158         ord = Ordering::Greater;
159       } else {
160         ord = Ordering::Equal;
161       }
162       TEST(a.CompareSigned(b) == ord)
163       ("%s, x=0x%llx %lld %d, y=0x%llx %lld %d", desc, x, sx, a.IsNegative(), y,
164           sy, b.IsNegative());
165 
166       t = a.IAND(b);
167       MATCH(x & y, t.ToUInt64())("%s, x=0x%llx, y=0x%llx", desc, x, y);
168       t = a.IOR(b);
169       MATCH(x | y, t.ToUInt64())("%s, x=0x%llx, y=0x%llx", desc, x, y);
170       t = a.IEOR(b);
171       MATCH(x ^ y, t.ToUInt64())("%s, x=0x%llx, y=0x%llx", desc, x, y);
172       auto sum{a.AddUnsigned(b)};
173       COMPARE(
174           x + y, ==, sum.value.ToUInt64() + (std::uint64_t{sum.carry} << BITS))
175       ("%s, x=0x%llx, y=0x%llx, carry=%d", desc, x, y, sum.carry);
176       auto ssum{a.AddSigned(b)};
177       MATCH((sx + sy) & maxUnsignedValue, ssum.value.ToUInt64())
178       ("%s, x=0x%llx, y=0x%llx", desc, x, y);
179       MATCH(
180           sx + sy < mostNegativeSignedValue || sx + sy > maxPositiveSignedValue,
181           ssum.overflow)
182       ("%s, x=0x%llx, y=0x%llx", desc, x, y);
183       auto diff{a.SubtractSigned(b)};
184       MATCH((sx - sy) & maxUnsignedValue, diff.value.ToUInt64())
185       ("%s, x=0x%llx, y=0x%llx", desc, x, y);
186       MATCH(
187           sx - sy < mostNegativeSignedValue || sx - sy > maxPositiveSignedValue,
188           diff.overflow)
189       ("%s, x=0x%llx, y=0x%llx", desc, x, y);
190       auto product{a.MultiplyUnsigned(b)};
191       MATCH(
192           x * y, (product.upper.ToUInt64() << BITS) ^ product.lower.ToUInt64())
193       ("%s, x=0x%llx, y=0x%llx, lower=0x%llx, upper=0x%llx", desc, x, y,
194           product.lower.ToUInt64(), product.upper.ToUInt64());
195       product = a.MultiplySigned(b);
196       MATCH((sx * sy) & maxUnsignedValue, product.lower.ToUInt64())
197       ("%s, x=0x%llx, y=0x%llx", desc, x, y);
198       MATCH(((sx * sy) >> BITS) & maxUnsignedValue, product.upper.ToUInt64())
199       ("%s, x=0x%llx, y=0x%llx", desc, x, y);
200       auto quot{a.DivideUnsigned(b)};
201       MATCH(y == 0, quot.divisionByZero)("%s, x=0x%llx, y=0x%llx", desc, x, y);
202       if (y == 0) {
203         MATCH(maxUnsignedValue, quot.quotient.ToUInt64())
204         ("%s, x=0x%llx, y=0x%llx", desc, x, y);
205         MATCH(0, quot.remainder.ToUInt64())
206         ("%s, x=0x%llx, y=0x%llx", desc, x, y);
207       } else {
208         MATCH(x / y, quot.quotient.ToUInt64())
209         ("%s, x=0x%llx, y=0x%llx", desc, x, y);
210         MATCH(x % y, quot.remainder.ToUInt64())
211         ("%s, x=0x%llx, y=0x%llx", desc, x, y);
212       }
213       quot = a.DivideSigned(b);
214       bool badCase{sx == mostNegativeSignedValue &&
215           ((sy == -1 && sx != sy) || (BITS == 1 && sx == sy))};
216       MATCH(y == 0, quot.divisionByZero)("%s, x=0x%llx, y=0x%llx", desc, x, y);
217       MATCH(badCase, quot.overflow)("%s, x=0x%llx, y=0x%llx", desc, x, y);
218       if (y == 0) {
219         if (sx >= 0) {
220           MATCH(maxPositiveSignedValue, quot.quotient.ToInt64())
221           ("%s, x=0x%llx, y=0x%llx", desc, x, y);
222         } else {
223           MATCH(mostNegativeSignedValue, quot.quotient.ToInt64())
224           ("%s, x=0x%llx, y=0x%llx", desc, x, y);
225         }
226         MATCH(0, quot.remainder.ToUInt64())
227         ("%s, x=0x%llx, y=0x%llx", desc, x, y);
228       } else if (badCase) {
229         MATCH(x, quot.quotient.ToUInt64())
230         ("%s, x=0x%llx, y=0x%llx", desc, x, y);
231         MATCH(0, quot.remainder.ToUInt64())
232         ("%s, x=0x%llx, y=0x%llx", desc, x, y);
233       } else {
234         MATCH(sx / sy, quot.quotient.ToInt64())
235         ("%s, x=0x%llx %lld, y=0x%llx %lld; unsigned 0x%llx", desc, x, sx, y,
236             sy, quot.quotient.ToUInt64());
237         MATCH(sx - sy * (sx / sy), quot.remainder.ToInt64())
238         ("%s, x=0x%llx, y=0x%llx", desc, x, y);
239       }
240     }
241   }
242 }
243 
main()244 int main() {
245   TEST(Reverse(Ordering::Less) == Ordering::Greater);
246   TEST(Reverse(Ordering::Greater) == Ordering::Less);
247   TEST(Reverse(Ordering::Equal) == Ordering::Equal);
248   TEST(Integer<128>{123456789}.UnsignedDecimal() == "123456789");
249   TEST(Integer<128>{123456789}.SignedDecimal() == "123456789");
250   TEST(Integer<128>{-123456789}.SignedDecimal() == "-123456789");
251   std::uint64_t big{0x123456789abcdef};
252   TEST(Integer<128>{big}.Hexadecimal() == "123456789abcdef");
253   exhaustiveTesting<1>();
254   exhaustiveTesting<2>();
255   exhaustiveTesting<7>();
256   exhaustiveTesting<8>();
257   exhaustiveTesting<9>();
258   exhaustiveTesting<9, Integer<9, true, 1>>();
259   exhaustiveTesting<9, Integer<9, true, 1, std::uint8_t, std::uint16_t>>();
260   exhaustiveTesting<9, Integer<9, true, 2>>();
261   exhaustiveTesting<9, Integer<9, true, 2, std::uint8_t, std::uint16_t>>();
262   exhaustiveTesting<9, Integer<9, true, 8, std::uint8_t, std::uint16_t>>();
263   exhaustiveTesting<9, Integer<9, false, 8, std::uint8_t, std::uint16_t>>();
264   return testing::Complete();
265 }
266