| 1 | #include "flang/Evaluate/integer.h" |
| 2 | #include "flang/Testing/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 | |