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 | |
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(s: desc, maxlen: sizeof desc, |
15 | format: "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(s: buffer, maxlen: sizeof buffer, format: " %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(s: buffer, maxlen: sizeof buffer, format: "%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 | |
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 | |