Bug Summary

File:build/source/flang/include/flang/Evaluate/integer.h
Warning:line 481, column 31
The result of the left shift is undefined because the left operand is negative

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name integer.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -mframe-pointer=none -relaxed-aliasing -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -ffunction-sections -fdata-sections -fcoverage-compilation-dir=/build/source/build-llvm/tools/clang/stage2-bins -resource-dir /usr/lib/llvm-17/lib/clang/17 -isystem /build/source/llvm/../mlir/include -isystem tools/mlir/include -isystem tools/clang/include -isystem /build/source/llvm/../clang/include -D FLANG_INCLUDE_TESTS=1 -D FLANG_LITTLE_ENDIAN=1 -D FLANG_VENDOR="Debian " -D _DEBUG -D _GLIBCXX_ASSERTIONS -D _GNU_SOURCE -D _LIBCPP_ENABLE_ASSERTIONS -D __STDC_CONSTANT_MACROS -D __STDC_FORMAT_MACROS -D __STDC_LIMIT_MACROS -I tools/flang/unittests/Evaluate -I /build/source/flang/unittests/Evaluate -I /build/source/flang/include -I tools/flang/include -I include -I /build/source/llvm/include -D _FORTIFY_SOURCE=2 -D NDEBUG -U NDEBUG -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/x86_64-linux-gnu/c++/10 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/backward -internal-isystem /usr/lib/llvm-17/lib/clang/17/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fmacro-prefix-map=/build/source/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fmacro-prefix-map=/build/source/= -fcoverage-prefix-map=/build/source/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fcoverage-prefix-map=/build/source/= -source-date-epoch 1683717183 -O2 -Wno-unused-command-line-argument -Wno-unused-parameter -Wwrite-strings -Wno-missing-field-initializers -Wno-long-long -Wno-maybe-uninitialized -Wno-class-memaccess -Wno-redundant-move -Wno-pessimizing-move -Wno-noexcept-type -Wno-comment -Wno-misleading-indentation -Wno-deprecated-copy -Wno-ctad-maybe-unsupported -Wno-suggest-override -std=c++17 -fdeprecated-macro -fdebug-compilation-dir=/build/source/build-llvm/tools/clang/stage2-bins -fdebug-prefix-map=/build/source/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fdebug-prefix-map=/build/source/= -ferror-limit 19 -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcxx-exceptions -fexceptions -fcolor-diagnostics -vectorize-loops -vectorize-slp -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2023-05-10-133810-16478-1 -x c++ /build/source/flang/unittests/Evaluate/integer.cpp

/build/source/flang/unittests/Evaluate/integer.cpp

1#include "flang/Evaluate/integer.h"
2#include "testing.h"
3#include <cstdio>
4#include <string>
5
6using Fortran::evaluate::Ordering;
7using Fortran::evaluate::value::Integer;
8
9template <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)testing::Match("flang/unittests/Evaluate/integer.cpp", 18, (BITS
), "INT::bits", (INT::bits))
(desc);
19 MATCH(maxPositiveSignedValue, INT::HUGE().ToUInt64())testing::Match("flang/unittests/Evaluate/integer.cpp", 19, (maxPositiveSignedValue
), "INT::HUGE().ToUInt64()", (INT::HUGE().ToUInt64()))
(desc);
20 INT zero;
21 TEST(zero.IsZero())testing::Test("flang/unittests/Evaluate/integer.cpp", 21, "zero.IsZero()"
, (zero.IsZero()))
(desc);
22 MATCH(0, zero.ToUInt64())testing::Match("flang/unittests/Evaluate/integer.cpp", 22, (0
), "zero.ToUInt64()", (zero.ToUInt64()))
(desc);
23 MATCH(0, zero.ToInt64())testing::Match("flang/unittests/Evaluate/integer.cpp", 23, (0
), "zero.ToInt64()", (zero.ToInt64()))
(desc);
24
25 for (std::uint64_t x{0}; x <= maxUnsignedValue; ++x) {
2
Loop condition is true. Entering loop body
38
Loop condition is true. Entering loop body
26 unsigned long long ullx = x;
27 INT a{x};
28 MATCH(x, a.ToUInt64())testing::Match("flang/unittests/Evaluate/integer.cpp", 28, (x
), "a.ToUInt64()", (a.ToUInt64()))
(desc);
29 INT copy{a};
30 MATCH(x, copy.ToUInt64())testing::Match("flang/unittests/Evaluate/integer.cpp", 30, (x
), "copy.ToUInt64()", (copy.ToUInt64()))
(desc);
31 copy = a;
32 MATCH(x, copy.ToUInt64())testing::Match("flang/unittests/Evaluate/integer.cpp", 32, (x
), "copy.ToUInt64()", (copy.ToUInt64()))
(desc);
33 MATCH(x == 0, a.IsZero())testing::Match("flang/unittests/Evaluate/integer.cpp", 33, (x
== 0), "a.IsZero()", (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)testing::Test("flang/unittests/Evaluate/integer.cpp", 38, "!readcheck.overflow"
, (!readcheck.overflow))
("%s, x=0x%llx", desc, x);
39 MATCH(x, readcheck.value.ToUInt64())testing::Match("flang/unittests/Evaluate/integer.cpp", 39, (x
), "readcheck.value.ToUInt64()", (readcheck.value.ToUInt64())
)
("%s, x=0x%llx", desc, x);
40 TEST(!*p)testing::Test("flang/unittests/Evaluate/integer.cpp", 40, "!*p"
, (!*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)testing::Test("flang/unittests/Evaluate/integer.cpp", 44, "!readcheck.overflow"
, (!readcheck.overflow))
("%s, x=0x%llx", desc, x);
45 MATCH(x, readcheck.value.ToUInt64())testing::Match("flang/unittests/Evaluate/integer.cpp", 45, (x
), "readcheck.value.ToUInt64()", (readcheck.value.ToUInt64())
)
("%s, x=0x%llx", desc, x);
46 TEST(!*p)testing::Test("flang/unittests/Evaluate/integer.cpp", 46, "!*p"
, (!*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)testing::Test("flang/unittests/Evaluate/integer.cpp", 50, "!readcheck.overflow"
, (!readcheck.overflow))
("%s, x=0x%llx", desc, x);
51 MATCH(x, readcheck.value.ToUInt64())testing::Match("flang/unittests/Evaluate/integer.cpp", 51, (x
), "readcheck.value.ToUInt64()", (readcheck.value.ToUInt64())
)
("%s, x=0x%llx", desc, x);
52 TEST(!*p)testing::Test("flang/unittests/Evaluate/integer.cpp", 52, "!*p"
, (!*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)testing::Test("flang/unittests/Evaluate/integer.cpp", 56, "!readcheck.overflow"
, (!readcheck.overflow))
("%s, x=0x%llx", desc, x);
57 MATCH(x, readcheck.value.ToUInt64())testing::Match("flang/unittests/Evaluate/integer.cpp", 57, (x
), "readcheck.value.ToUInt64()", (readcheck.value.ToUInt64())
)
("%s, x=0x%llx", desc, x);
58 TEST(!*p)testing::Test("flang/unittests/Evaluate/integer.cpp", 58, "!*p"
, (!*p))
("%s, x=0x%llx", desc, x);
59 INT t{a.NOT()};
60 MATCH(x ^ maxUnsignedValue, t.ToUInt64())testing::Match("flang/unittests/Evaluate/integer.cpp", 60, (x
^ maxUnsignedValue), "t.ToUInt64()", (t.ToUInt64()))
("%s, x=0x%llx", desc, x);
61 auto negated{a.Negate()};
62 MATCH(x == std::uint64_t{1} << (BITS - 1), negated.overflow)testing::Match("flang/unittests/Evaluate/integer.cpp", 62, (x
== std::uint64_t{1} << (BITS - 1)), "negated.overflow"
, (negated.overflow))
63 ("%s, x=0x%llx", desc, x);
64 MATCH(-x & maxUnsignedValue, negated.value.ToUInt64())testing::Match("flang/unittests/Evaluate/integer.cpp", 64, (-
x & maxUnsignedValue), "negated.value.ToUInt64()", (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)testing::Match("flang/unittests/Evaluate/integer.cpp", 67, (x
== std::uint64_t{1} << (BITS - 1)), "abs.overflow", (abs
.overflow))
68 ("%s, x=0x%llx", desc, x);
69 MATCH(x >> (BITS - 1) ? -x & maxUnsignedValue : x, abs.value.ToUInt64())testing::Match("flang/unittests/Evaluate/integer.cpp", 69, (x
>> (BITS - 1) ? -x & maxUnsignedValue : x), "abs.value.ToUInt64()"
, (abs.value.ToUInt64()))
3
'?' condition is false
39
'?' condition is true
70 ("%s, x=0x%llx", desc, x);
71 int lzbc{a.LEADZ()};
72 COMPARE(lzbc, >=, 0)testing::Compare("flang/unittests/Evaluate/integer.cpp", 72, "lzbc"
, ">=", "0", (lzbc), (0))
("%s, x=0x%llx", desc, x);
73 COMPARE(lzbc, <=, BITS)testing::Compare("flang/unittests/Evaluate/integer.cpp", 73, "lzbc"
, "<=", "BITS", (lzbc), (BITS))
("%s, x=0x%llx", desc, x);
74 MATCH(x == 0, lzbc == BITS)testing::Match("flang/unittests/Evaluate/integer.cpp", 74, (x
== 0), "lzbc == BITS", (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)testing::Compare("flang/unittests/Evaluate/integer.cpp", 76, "x"
, "<", "lzcheck", (x), (lzcheck))
("%s, x=0x%llx, lzbc=%d", desc, x, lzbc);
77 COMPARE(x + x + !x, >=, lzcheck)testing::Compare("flang/unittests/Evaluate/integer.cpp", 77, "x + x + !x"
, ">=", "lzcheck", (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) {
4
Loop condition is true. Entering loop body
5
Loop condition is false. Execution continues on line 82
40
Loop condition is true. Entering loop body
41
Loop condition is false. Execution continues on line 82
80 popcheck += (x >> j) & 1;
81 }
82 MATCH(popcheck, a.POPCNT())testing::Match("flang/unittests/Evaluate/integer.cpp", 82, (popcheck
), "a.POPCNT()", (a.POPCNT()))
("%s, x=0x%llx", desc, x);
83 MATCH(popcheck & 1, a.POPPAR())testing::Match("flang/unittests/Evaluate/integer.cpp", 83, (popcheck
& 1), "a.POPPAR()", (a.POPPAR()))
("%s, x=0x%llx", desc, x);
84 int trailcheck{0};
85 for (; trailcheck < BITS; ++trailcheck) {
6
Loop condition is true. Entering loop body
8
Loop condition is false. Execution continues on line 90
42
Loop condition is true. Entering loop body
86 if ((x >> trailcheck) & 1) {
7
Taking false branch
43
Taking true branch
87 break;
44
Execution continues on line 90
88 }
89 }
90 MATCH(trailcheck, a.TRAILZ())testing::Match("flang/unittests/Evaluate/integer.cpp", 90, (trailcheck
), "a.TRAILZ()", (a.TRAILZ()))
("%s, x=0x%llx", desc, x);
91 for (int j{0}; j < BITS; ++j) {
9
Loop condition is true. Entering loop body
10
Loop condition is false. Execution continues on line 98
45
Loop condition is true. Entering loop body
46
Loop condition is false. Execution continues on line 98
92 MATCH((x >> j) & 1, a.BTEST(j))testing::Match("flang/unittests/Evaluate/integer.cpp", 92, ((
x >> j) & 1), "a.BTEST(j)", (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) {
11
Taking false branch
47
Taking true branch
101 TEST(a.IsNegative())testing::Test("flang/unittests/Evaluate/integer.cpp", 101, "a.IsNegative()"
, (a.IsNegative()))
("%s, x=0x%llx", desc, x);
102 sx = x | (~std::uint64_t{0} << BITS);
103 TEST(sx < 0)testing::Test("flang/unittests/Evaluate/integer.cpp", 103, "sx < 0"
, (sx < 0))
("%s, x=0x%llx %lld", desc, x, sx);
104 ord = Ordering::Less;
105 } else {
106 TEST(!a.IsNegative())testing::Test("flang/unittests/Evaluate/integer.cpp", 106, "!a.IsNegative()"
, (!a.IsNegative()))
("%s, x=0x%llx", desc, x);
107 TEST(sx >= 0)testing::Test("flang/unittests/Evaluate/integer.cpp", 107, "sx >= 0"
, (sx >= 0))
("%s, x=0x%llx %lld", desc, x, sx);
108 if (sx
11.1
'sx' is <= 0
11.1
'sx' is <= 0
> 0) {
12
Taking false branch
109 ord = Ordering::Greater;
110 } else {
111 ord = Ordering::Equal;
112 }
113 }
114
115 TEST(sx == a.ToInt64())testing::Test("flang/unittests/Evaluate/integer.cpp", 115, "sx == a.ToInt64()"
, (sx == a.ToInt64()))
("%s, x=0x%llx %lld", desc, x, sx);
48
Calling 'Integer::ToInt64'
116 TEST(a.CompareToZeroSigned() == ord)testing::Test("flang/unittests/Evaluate/integer.cpp", 116, "a.CompareToZeroSigned() == ord"
, (a.CompareToZeroSigned() == ord))
("%s, x=0x%llx %lld", desc, x, sx);
117 for (int count{0}; count <= BITS + 1; ++count) {
13
Loop condition is true. Entering loop body
15
Loop condition is true. Entering loop body
17
Loop condition is true. Entering loop body
19
Loop condition is false. Execution continues on line 137
118 t = a.SHIFTL(count);
119 MATCH((x << count) & maxUnsignedValue, t.ToUInt64())testing::Match("flang/unittests/Evaluate/integer.cpp", 119, (
(x << count) & maxUnsignedValue), "t.ToUInt64()", (
t.ToUInt64()))
120 ("%s, x=0x%llx, count=%d", desc, x, count);
121 t = a.ISHFT(count);
122 MATCH((x << count) & maxUnsignedValue, t.ToUInt64())testing::Match("flang/unittests/Evaluate/integer.cpp", 122, (
(x << count) & maxUnsignedValue), "t.ToUInt64()", (
t.ToUInt64()))
123 ("%s, x=0x%llx, count=%d", desc, x, count);
124 t = a.SHIFTR(count);
125 MATCH(x >> count, t.ToUInt64())testing::Match("flang/unittests/Evaluate/integer.cpp", 125, (
x >> count), "t.ToUInt64()", (t.ToUInt64()))
126 ("%s, x=0x%llx, count=%d", desc, x, count);
127 t = a.ISHFT(-count);
128 MATCH(x >> count, t.ToUInt64())testing::Match("flang/unittests/Evaluate/integer.cpp", 128, (
x >> count), "t.ToUInt64()", (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
13.1
'count' is < 1
15.1
'count' is >= 1
17.1
'count' is >= 1
13.1
'count' is < 1
15.1
'count' is >= 1
17.1
'count' is >= 1
>= BITS ? fill : (x >> count) | (fill << (BITS - count))};
14
'?' condition is false
16
'?' condition is true
18
'?' condition is true
133 MATCH(sra, t.ToInt64())testing::Match("flang/unittests/Evaluate/integer.cpp", 133, (
sra), "t.ToInt64()", (t.ToInt64()))
134 ("%s, x=0x%llx, count=%d", desc, x, count);
135 }
136
137 for (std::uint64_t y{0}; y <= maxUnsignedValue; ++y) {
20
Loop condition is true. Entering loop body
29
Loop condition is true. Entering loop body
37
Loop condition is false. Execution continues on line 25
138 std::int64_t sy = y;
139 if (y + y > maxUnsignedValue) {
21
Taking false branch
30
Taking true branch
140 sy = y | (~std::uint64_t{0} << BITS);
141 }
142 INT b{y};
143 if (x
21.1
'x' is >= 'y'
30.1
'x' is < 'y'
21.1
'x' is >= 'y'
30.1
'x' is < 'y'
< y) {
22
Taking false branch
31
Taking true branch
144 ord = Ordering::Less;
145 } else if (x
22.1
'x' is <= 'y'
22.1
'x' is <= 'y'
> y) {
23
Taking false branch
146 ord = Ordering::Greater;
147 } else {
148 ord = Ordering::Equal;
149 }
150 TEST(a.CompareUnsigned(b) == ord)testing::Test("flang/unittests/Evaluate/integer.cpp", 150, "a.CompareUnsigned(b) == ord"
, (a.CompareUnsigned(b) == ord))
("%s, x=0x%llx, y=0x%llx", desc, x, y);
151 MATCH(x >= y, a.BGE(b))testing::Match("flang/unittests/Evaluate/integer.cpp", 151, (
x >= y), "a.BGE(b)", (a.BGE(b)))
("%s, x=0x%llx, y=0x%llx", desc, x, y);
152 MATCH(x > y, a.BGT(b))testing::Match("flang/unittests/Evaluate/integer.cpp", 152, (
x > y), "a.BGT(b)", (a.BGT(b)))
("%s, x=0x%llx, y=0x%llx", desc, x, y);
153 MATCH(x <= y, a.BLE(b))testing::Match("flang/unittests/Evaluate/integer.cpp", 153, (
x <= y), "a.BLE(b)", (a.BLE(b)))
("%s, x=0x%llx, y=0x%llx", desc, x, y);
154 MATCH(x < y, a.BLT(b))testing::Match("flang/unittests/Evaluate/integer.cpp", 154, (
x < y), "a.BLT(b)", (a.BLT(b)))
("%s, x=0x%llx, y=0x%llx", desc, x, y);
155 if (sx
23.1
'sx' is >= 'sy'
31.1
'sx' is >= 'sy'
23.1
'sx' is >= 'sy'
31.1
'sx' is >= 'sy'
< sy) {
24
Taking false branch
32
Taking false branch
156 ord = Ordering::Less;
157 } else if (sx
24.1
'sx' is <= 'sy'
32.1
'sx' is > 'sy'
24.1
'sx' is <= 'sy'
32.1
'sx' is > 'sy'
> sy) {
25
Taking false branch
33
Taking true branch
158 ord = Ordering::Greater;
159 } else {
160 ord = Ordering::Equal;
161 }
162 TEST(a.CompareSigned(b) == ord)testing::Test("flang/unittests/Evaluate/integer.cpp", 162, "a.CompareSigned(b) == ord"
, (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())testing::Match("flang/unittests/Evaluate/integer.cpp", 167, (
x & y), "t.ToUInt64()", (t.ToUInt64()))
("%s, x=0x%llx, y=0x%llx", desc, x, y);
168 t = a.IOR(b);
169 MATCH(x | y, t.ToUInt64())testing::Match("flang/unittests/Evaluate/integer.cpp", 169, (
x | y), "t.ToUInt64()", (t.ToUInt64()))
("%s, x=0x%llx, y=0x%llx", desc, x, y);
170 t = a.IEOR(b);
171 MATCH(x ^ y, t.ToUInt64())testing::Match("flang/unittests/Evaluate/integer.cpp", 171, (
x ^ y), "t.ToUInt64()", (t.ToUInt64()))
("%s, x=0x%llx, y=0x%llx", desc, x, y);
172 auto sum{a.AddUnsigned(b)};
173 COMPARE(testing::Compare("flang/unittests/Evaluate/integer.cpp", 174,
"x + y", "==", "sum.value.ToUInt64() + (std::uint64_t{sum.carry} << BITS)"
, (x + y), (sum.value.ToUInt64() + (std::uint64_t{sum.carry} <<
BITS)))
174 x + y, ==, sum.value.ToUInt64() + (std::uint64_t{sum.carry} << BITS))testing::Compare("flang/unittests/Evaluate/integer.cpp", 174,
"x + y", "==", "sum.value.ToUInt64() + (std::uint64_t{sum.carry} << BITS)"
, (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())testing::Match("flang/unittests/Evaluate/integer.cpp", 177, (
(sx + sy) & maxUnsignedValue), "ssum.value.ToUInt64()", (
ssum.value.ToUInt64()))
178 ("%s, x=0x%llx, y=0x%llx", desc, x, y);
179 MATCH(testing::Match("flang/unittests/Evaluate/integer.cpp", 181, (
sx + sy < mostNegativeSignedValue || sx + sy > maxPositiveSignedValue
), "ssum.overflow", (ssum.overflow))
180 sx + sy < mostNegativeSignedValue || sx + sy > maxPositiveSignedValue,testing::Match("flang/unittests/Evaluate/integer.cpp", 181, (
sx + sy < mostNegativeSignedValue || sx + sy > maxPositiveSignedValue
), "ssum.overflow", (ssum.overflow))
181 ssum.overflow)testing::Match("flang/unittests/Evaluate/integer.cpp", 181, (
sx + sy < mostNegativeSignedValue || sx + sy > maxPositiveSignedValue
), "ssum.overflow", (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())testing::Match("flang/unittests/Evaluate/integer.cpp", 184, (
(sx - sy) & maxUnsignedValue), "diff.value.ToUInt64()", (
diff.value.ToUInt64()))
185 ("%s, x=0x%llx, y=0x%llx", desc, x, y);
186 MATCH(testing::Match("flang/unittests/Evaluate/integer.cpp", 188, (
sx - sy < mostNegativeSignedValue || sx - sy > maxPositiveSignedValue
), "diff.overflow", (diff.overflow))
187 sx - sy < mostNegativeSignedValue || sx - sy > maxPositiveSignedValue,testing::Match("flang/unittests/Evaluate/integer.cpp", 188, (
sx - sy < mostNegativeSignedValue || sx - sy > maxPositiveSignedValue
), "diff.overflow", (diff.overflow))
188 diff.overflow)testing::Match("flang/unittests/Evaluate/integer.cpp", 188, (
sx - sy < mostNegativeSignedValue || sx - sy > maxPositiveSignedValue
), "diff.overflow", (diff.overflow))
189 ("%s, x=0x%llx, y=0x%llx", desc, x, y);
190 auto product{a.MultiplyUnsigned(b)};
191 MATCH(testing::Match("flang/unittests/Evaluate/integer.cpp", 192, (
x * y), "(product.upper.ToUInt64() << BITS) ^ product.lower.ToUInt64()"
, ((product.upper.ToUInt64() << BITS) ^ product.lower.ToUInt64
()))
192 x * y, (product.upper.ToUInt64() << BITS) ^ product.lower.ToUInt64())testing::Match("flang/unittests/Evaluate/integer.cpp", 192, (
x * y), "(product.upper.ToUInt64() << BITS) ^ product.lower.ToUInt64()"
, ((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())testing::Match("flang/unittests/Evaluate/integer.cpp", 196, (
(sx * sy) & maxUnsignedValue), "product.lower.ToUInt64()"
, (product.lower.ToUInt64()))
197 ("%s, x=0x%llx, y=0x%llx", desc, x, y);
198 MATCH(((sx * sy) >> BITS) & maxUnsignedValue, product.upper.ToUInt64())testing::Match("flang/unittests/Evaluate/integer.cpp", 198, (
((sx * sy) >> BITS) & maxUnsignedValue), "product.upper.ToUInt64()"
, (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)testing::Match("flang/unittests/Evaluate/integer.cpp", 201, (
y == 0), "quot.divisionByZero", (quot.divisionByZero))
("%s, x=0x%llx, y=0x%llx", desc, x, y);
202 if (y
25.1
'y' is equal to 0
33.1
'y' is not equal to 0
25.1
'y' is equal to 0
33.1
'y' is not equal to 0
== 0) {
26
Taking true branch
34
Taking false branch
203 MATCH(maxUnsignedValue, quot.quotient.ToUInt64())testing::Match("flang/unittests/Evaluate/integer.cpp", 203, (
maxUnsignedValue), "quot.quotient.ToUInt64()", (quot.quotient
.ToUInt64()))
204 ("%s, x=0x%llx, y=0x%llx", desc, x, y);
205 MATCH(0, quot.remainder.ToUInt64())testing::Match("flang/unittests/Evaluate/integer.cpp", 205, (
0), "quot.remainder.ToUInt64()", (quot.remainder.ToUInt64()))
206 ("%s, x=0x%llx, y=0x%llx", desc, x, y);
207 } else {
208 MATCH(x / y, quot.quotient.ToUInt64())testing::Match("flang/unittests/Evaluate/integer.cpp", 208, (
x / y), "quot.quotient.ToUInt64()", (quot.quotient.ToUInt64()
))
209 ("%s, x=0x%llx, y=0x%llx", desc, x, y);
210 MATCH(x % y, quot.remainder.ToUInt64())testing::Match("flang/unittests/Evaluate/integer.cpp", 210, (
x % y), "quot.remainder.ToUInt64()", (quot.remainder.ToUInt64
()))
211 ("%s, x=0x%llx, y=0x%llx", desc, x, y);
212 }
213 quot = a.DivideSigned(b);
214 bool badCase{sx
26.1
'sx' is not equal to 'mostNegativeSignedValue'
34.1
'sx' is not equal to 'mostNegativeSignedValue'
26.1
'sx' is not equal to 'mostNegativeSignedValue'
34.1
'sx' is not equal to 'mostNegativeSignedValue'
== mostNegativeSignedValue &&
215 ((sy == -1 && sx != sy) || (BITS == 1 && sx == sy))};
216 MATCH(y == 0, quot.divisionByZero)testing::Match("flang/unittests/Evaluate/integer.cpp", 216, (
y == 0), "quot.divisionByZero", (quot.divisionByZero))
("%s, x=0x%llx, y=0x%llx", desc, x, y);
217 MATCH(badCase, quot.overflow)testing::Match("flang/unittests/Evaluate/integer.cpp", 217, (
badCase), "quot.overflow", (quot.overflow))
("%s, x=0x%llx, y=0x%llx", desc, x, y);
218 if (y
26.2
'y' is equal to 0
34.2
'y' is not equal to 0
26.2
'y' is equal to 0
34.2
'y' is not equal to 0
== 0) {
27
Taking true branch
35
Taking false branch
219 if (sx
27.1
'sx' is >= 0
27.1
'sx' is >= 0
>= 0) {
28
Taking true branch
220 MATCH(maxPositiveSignedValue, quot.quotient.ToInt64())testing::Match("flang/unittests/Evaluate/integer.cpp", 220, (
maxPositiveSignedValue), "quot.quotient.ToInt64()", (quot.quotient
.ToInt64()))
221 ("%s, x=0x%llx, y=0x%llx", desc, x, y);
222 } else {
223 MATCH(mostNegativeSignedValue, quot.quotient.ToInt64())testing::Match("flang/unittests/Evaluate/integer.cpp", 223, (
mostNegativeSignedValue), "quot.quotient.ToInt64()", (quot.quotient
.ToInt64()))
224 ("%s, x=0x%llx, y=0x%llx", desc, x, y);
225 }
226 MATCH(0, quot.remainder.ToUInt64())testing::Match("flang/unittests/Evaluate/integer.cpp", 226, (
0), "quot.remainder.ToUInt64()", (quot.remainder.ToUInt64()))
227 ("%s, x=0x%llx, y=0x%llx", desc, x, y);
228 } else if (badCase
35.1
'badCase' is false
35.1
'badCase' is false
) {
36
Taking false branch
229 MATCH(x, quot.quotient.ToUInt64())testing::Match("flang/unittests/Evaluate/integer.cpp", 229, (
x), "quot.quotient.ToUInt64()", (quot.quotient.ToUInt64()))
230 ("%s, x=0x%llx, y=0x%llx", desc, x, y);
231 MATCH(0, quot.remainder.ToUInt64())testing::Match("flang/unittests/Evaluate/integer.cpp", 231, (
0), "quot.remainder.ToUInt64()", (quot.remainder.ToUInt64()))
232 ("%s, x=0x%llx, y=0x%llx", desc, x, y);
233 } else {
234 MATCH(sx / sy, quot.quotient.ToInt64())testing::Match("flang/unittests/Evaluate/integer.cpp", 234, (
sx / sy), "quot.quotient.ToInt64()", (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())testing::Match("flang/unittests/Evaluate/integer.cpp", 237, (
sx - sy * (sx / sy)), "quot.remainder.ToInt64()", (quot.remainder
.ToInt64()))
238 ("%s, x=0x%llx, y=0x%llx", desc, x, y);
239 }
240 }
241 }
242}
243
244int main() {
245 TEST(Reverse(Ordering::Less) == Ordering::Greater)testing::Test("flang/unittests/Evaluate/integer.cpp", 245, "Reverse(Ordering::Less) == Ordering::Greater"
, (Reverse(Ordering::Less) == Ordering::Greater))
;
246 TEST(Reverse(Ordering::Greater) == Ordering::Less)testing::Test("flang/unittests/Evaluate/integer.cpp", 246, "Reverse(Ordering::Greater) == Ordering::Less"
, (Reverse(Ordering::Greater) == Ordering::Less))
;
247 TEST(Reverse(Ordering::Equal) == Ordering::Equal)testing::Test("flang/unittests/Evaluate/integer.cpp", 247, "Reverse(Ordering::Equal) == Ordering::Equal"
, (Reverse(Ordering::Equal) == Ordering::Equal))
;
248 TEST(Integer<128>{123456789}.UnsignedDecimal() == "123456789")testing::Test("flang/unittests/Evaluate/integer.cpp", 248, "Integer<128>{123456789}.UnsignedDecimal() == \"123456789\""
, (Integer<128>{123456789}.UnsignedDecimal() == "123456789"
))
;
249 TEST(Integer<128>{123456789}.SignedDecimal() == "123456789")testing::Test("flang/unittests/Evaluate/integer.cpp", 249, "Integer<128>{123456789}.SignedDecimal() == \"123456789\""
, (Integer<128>{123456789}.SignedDecimal() == "123456789"
))
;
250 TEST(Integer<128>{-123456789}.SignedDecimal() == "-123456789")testing::Test("flang/unittests/Evaluate/integer.cpp", 250, "Integer<128>{-123456789}.SignedDecimal() == \"-123456789\""
, (Integer<128>{-123456789}.SignedDecimal() == "-123456789"
))
;
251 std::uint64_t big{0x123456789abcdef};
252 TEST(Integer<128>{big}.Hexadecimal() == "123456789abcdef")testing::Test("flang/unittests/Evaluate/integer.cpp", 252, "Integer<128>{big}.Hexadecimal() == \"123456789abcdef\""
, (Integer<128>{big}.Hexadecimal() == "123456789abcdef"
))
;
253 exhaustiveTesting<1>();
1
Calling 'exhaustiveTesting<1, Fortran::evaluate::value::Integer<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}

/build/source/flang/include/flang/Evaluate/integer.h

1//===-- include/flang/Evaluate/integer.h ------------------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#ifndef FORTRAN_EVALUATE_INTEGER_H_
10#define FORTRAN_EVALUATE_INTEGER_H_
11
12// Emulates binary integers of an arbitrary (but fixed) bit size for use
13// when the host C++ environment does not support that size or when the
14// full suite of Fortran's integer intrinsic scalar functions are needed.
15// The data model is typeless, so signed* and unsigned operations
16// are distinguished from each other with distinct member function interfaces.
17// (*"Signed" here means two's-complement, just to be clear. Ones'-complement
18// and signed-magnitude encodings appear to be extinct in 2018.)
19
20#include "flang/Common/bit-population-count.h"
21#include "flang/Common/leading-zero-bit-count.h"
22#include "flang/Evaluate/common.h"
23#include <cinttypes>
24#include <climits>
25#include <cstddef>
26#include <cstdint>
27#include <string>
28#include <type_traits>
29
30// Some environments, viz. clang on Darwin, allow the macro HUGE
31// to leak out of <math.h> even when it is never directly included.
32#undef HUGE
33
34namespace Fortran::evaluate::value {
35
36// Implements an integer as an assembly of smaller host integer parts
37// that constitute the digits of a large-radix fixed-point number.
38// For best performance, the type of these parts should be half of the
39// size of the largest efficient integer supported by the host processor.
40// These parts are stored in either little- or big-endian order, which can
41// match that of the host's endianness or not; but if the ordering matches
42// that of the host, raw host data can be overlaid with a properly configured
43// instance of this class and used in situ.
44// To facilitate exhaustive testing of what would otherwise be more rare
45// edge cases, this class template may be configured to use other part
46// types &/or partial fields in the parts. The radix (i.e., the number
47// of possible values in a part), however, must be a power of two; this
48// template class is not generalized to enable, say, decimal arithmetic.
49// Member functions that correspond to Fortran intrinsic functions are
50// named accordingly in ALL CAPS so that they can be referenced easily in
51// the language standard.
52template <int BITS, bool IS_LITTLE_ENDIAN = isHostLittleEndian,
53 int PARTBITS = BITS <= 32 ? BITS : 32,
54 typename PART = HostUnsignedInt<PARTBITS>,
55 typename BIGPART = HostUnsignedInt<PARTBITS * 2>>
56class Integer {
57public:
58 static constexpr int bits{BITS};
59 static constexpr int partBits{PARTBITS};
60 using Part = PART;
61 using BigPart = BIGPART;
62 static_assert(std::is_integral_v<Part>);
63 static_assert(std::is_unsigned_v<Part>);
64 static_assert(std::is_integral_v<BigPart>);
65 static_assert(std::is_unsigned_v<BigPart>);
66 static_assert(CHAR_BIT8 * sizeof(BigPart) >= 2 * partBits);
67 static constexpr bool littleEndian{IS_LITTLE_ENDIAN};
68
69private:
70 static constexpr int maxPartBits{CHAR_BIT8 * sizeof(Part)};
71 static_assert(partBits > 0 && partBits <= maxPartBits);
72 static constexpr int extraPartBits{maxPartBits - partBits};
73 static constexpr int parts{(bits + partBits - 1) / partBits};
74 static_assert(parts >= 1);
75 static constexpr int extraTopPartBits{
76 extraPartBits + (parts * partBits) - bits};
77 static constexpr int topPartBits{maxPartBits - extraTopPartBits};
78 static_assert(topPartBits > 0 && topPartBits <= partBits);
79 static_assert((parts - 1) * partBits + topPartBits == bits);
80 static constexpr Part partMask{static_cast<Part>(~0) >> extraPartBits};
81 static constexpr Part topPartMask{static_cast<Part>(~0) >> extraTopPartBits};
82
83public:
84 // Some types used for member function results
85 struct ValueWithOverflow {
86 Integer value;
87 bool overflow;
88 };
89
90 struct ValueWithCarry {
91 Integer value;
92 bool carry;
93 };
94
95 struct Product {
96 bool SignedMultiplicationOverflowed() const {
97 return lower.IsNegative() ? (upper.POPCNT() != bits) : !upper.IsZero();
98 }
99 Integer upper, lower;
100 };
101
102 struct QuotientWithRemainder {
103 Integer quotient, remainder;
104 bool divisionByZero, overflow;
105 };
106
107 struct PowerWithErrors {
108 Integer power;
109 bool divisionByZero{false}, overflow{false}, zeroToZero{false};
110 };
111
112 // Constructors and value-generating static functions
113 constexpr Integer() { Clear(); } // default constructor: zero
114 constexpr Integer(const Integer &) = default;
115 constexpr Integer(Integer &&) = default;
116
117 // C++'s integral types can all be converted to Integer
118 // with silent truncation.
119 template <typename INT, typename = std::enable_if_t<std::is_integral_v<INT>>>
120 constexpr Integer(INT n) {
121 constexpr int nBits = CHAR_BIT8 * sizeof n;
122 if constexpr (nBits < partBits) {
123 if constexpr (std::is_unsigned_v<INT>) {
124 // Zero-extend an unsigned smaller value.
125 SetLEPart(0, n);
126 for (int j{1}; j < parts; ++j) {
127 SetLEPart(j, 0);
128 }
129 } else {
130 // n has a signed type smaller than the usable
131 // bits in a Part.
132 // Avoid conversions that change both size and sign.
133 using SignedPart = std::make_signed_t<Part>;
134 Part p = static_cast<SignedPart>(n);
135 SetLEPart(0, p);
136 if constexpr (parts > 1) {
137 Part signExtension = static_cast<SignedPart>(-(n < 0));
138 for (int j{1}; j < parts; ++j) {
139 SetLEPart(j, signExtension);
140 }
141 }
142 }
143 } else {
144 // n has some integral type no smaller than the usable
145 // bits in a Part.
146 // Ensure that all shifts are smaller than a whole word.
147 if constexpr (std::is_unsigned_v<INT>) {
148 for (int j{0}; j < parts; ++j) {
149 SetLEPart(j, static_cast<Part>(n));
150 if constexpr (nBits > partBits) {
151 n >>= partBits;
152 } else {
153 n = 0;
154 }
155 }
156 } else {
157 INT signExtension{-(n < 0)};
158 static_assert(nBits >= partBits);
159 if constexpr (nBits > partBits) {
160 signExtension <<= nBits - partBits;
161 for (int j{0}; j < parts; ++j) {
162 SetLEPart(j, static_cast<Part>(n));
163 n >>= partBits;
164 n |= signExtension;
165 }
166 } else {
167 SetLEPart(0, static_cast<Part>(n));
168 for (int j{1}; j < parts; ++j) {
169 SetLEPart(j, static_cast<Part>(signExtension));
170 }
171 }
172 }
173 }
174 }
175
176 constexpr Integer &operator=(const Integer &) = default;
177
178 constexpr bool operator<(const Integer &that) const {
179 return CompareSigned(that) == Ordering::Less;
180 }
181 constexpr bool operator<=(const Integer &that) const {
182 return CompareSigned(that) != Ordering::Greater;
183 }
184 constexpr bool operator==(const Integer &that) const {
185 return CompareSigned(that) == Ordering::Equal;
186 }
187 constexpr bool operator!=(const Integer &that) const {
188 return !(*this == that);
189 }
190 constexpr bool operator>=(const Integer &that) const {
191 return CompareSigned(that) != Ordering::Less;
192 }
193 constexpr bool operator>(const Integer &that) const {
194 return CompareSigned(that) == Ordering::Greater;
195 }
196
197 // Left-justified mask (e.g., MASKL(1) has only its sign bit set)
198 static constexpr Integer MASKL(int places) {
199 if (places <= 0) {
200 return {};
201 } else if (places >= bits) {
202 return MASKR(bits);
203 } else {
204 return MASKR(bits - places).NOT();
205 }
206 }
207
208 // Right-justified mask (e.g., MASKR(1) == 1, MASKR(2) == 3, &c.)
209 static constexpr Integer MASKR(int places) {
210 Integer result{nullptr};
211 int j{0};
212 for (; j + 1 < parts && places >= partBits; ++j, places -= partBits) {
213 result.LEPart(j) = partMask;
214 }
215 if (places > 0) {
216 if (j + 1 < parts) {
217 result.LEPart(j++) = partMask >> (partBits - places);
218 } else if (j + 1 == parts) {
219 if (places >= topPartBits) {
220 result.LEPart(j++) = topPartMask;
221 } else {
222 result.LEPart(j++) = topPartMask >> (topPartBits - places);
223 }
224 }
225 }
226 for (; j < parts; ++j) {
227 result.LEPart(j) = 0;
228 }
229 return result;
230 }
231
232 static constexpr ValueWithOverflow Read(
233 const char *&pp, std::uint64_t base = 10, bool isSigned = false) {
234 Integer result;
235 bool overflow{false};
236 const char *p{pp};
237 while (*p == ' ' || *p == '\t') {
238 ++p;
239 }
240 bool negate{*p == '-'};
241 if (negate || *p == '+') {
242 while (*++p == ' ' || *p == '\t') {
243 }
244 }
245 Integer radix{base};
246 // This code makes assumptions about local contiguity in regions of the
247 // character set and only works up to base 36. These assumptions hold
248 // for all current combinations of surviving character sets (ASCII, UTF-8,
249 // EBCDIC) and the bases used in Fortran source and formatted I/O
250 // (viz., 2, 8, 10, & 16). But: management thought that a disclaimer
251 // might be needed here to warn future users of this code about these
252 // assumptions, so here you go, future programmer in some postapocalyptic
253 // hellscape, and best of luck with the inexorable killer robots.
254 for (; std::uint64_t digit = *p; ++p) {
255 if (digit >= '0' && digit <= '9' && digit < '0' + base) {
256 digit -= '0';
257 } else if (base > 10 && digit >= 'A' && digit < 'A' + base - 10) {
258 digit -= 'A' - 10;
259 } else if (base > 10 && digit >= 'a' && digit < 'a' + base - 10) {
260 digit -= 'a' - 10;
261 } else {
262 break;
263 }
264 Product shifted{result.MultiplyUnsigned(radix)};
265 overflow |= !shifted.upper.IsZero();
266 ValueWithCarry next{shifted.lower.AddUnsigned(Integer{digit})};
267 overflow |= next.carry;
268 result = next.value;
269 }
270 pp = p;
271 if (negate) {
272 result = result.Negate().value;
273 overflow |= isSigned && !result.IsNegative() && !result.IsZero();
274 } else {
275 overflow |= isSigned && result.IsNegative();
276 }
277 return {result, overflow};
278 }
279
280 template <typename FROM>
281 static constexpr ValueWithOverflow ConvertUnsigned(const FROM &that) {
282 std::uint64_t field{that.ToUInt64()};
283 ValueWithOverflow result{field, false};
284 if constexpr (bits < 64) {
285 result.overflow = (field >> bits) != 0;
286 }
287 for (int j{64}; j < that.bits && !result.overflow; j += 64) {
288 field = that.SHIFTR(j).ToUInt64();
289 if (bits <= j) {
290 result.overflow = field != 0;
291 } else {
292 result.value = result.value.IOR(Integer{field}.SHIFTL(j));
293 if (bits < j + 64) {
294 result.overflow = (field >> (bits - j)) != 0;
295 }
296 }
297 }
298 return result;
299 }
300
301 template <typename FROM>
302 static constexpr ValueWithOverflow ConvertSigned(const FROM &that) {
303 ValueWithOverflow result{ConvertUnsigned(that)};
304 if constexpr (bits > FROM::bits) {
305 if (that.IsNegative()) {
306 result.value = result.value.IOR(MASKL(bits - FROM::bits));
307 }
308 result.overflow = false;
309 } else if constexpr (bits < FROM::bits) {
310 auto back{FROM::template ConvertSigned(result.value)};
311 result.overflow = back.value.CompareUnsigned(that) != Ordering::Equal;
312 }
313 return result;
314 }
315
316 std::string UnsignedDecimal() const {
317 if constexpr (bits < 4) {
318 char digit = '0' + ToUInt64();
319 return {digit};
320 } else if (IsZero()) {
321 return {'0'};
322 } else {
323 QuotientWithRemainder qr{DivideUnsigned(10)};
324 char digit = '0' + qr.remainder.ToUInt64();
325 if (qr.quotient.IsZero()) {
326 return {digit};
327 } else {
328 return qr.quotient.UnsignedDecimal() + digit;
329 }
330 }
331 }
332
333 std::string SignedDecimal() const {
334 if (IsNegative()) {
335 return std::string{'-'} + Negate().value.UnsignedDecimal();
336 } else {
337 return UnsignedDecimal();
338 }
339 }
340
341 // Omits a leading "0x".
342 std::string Hexadecimal() const {
343 std::string result;
344 int digits{(bits + 3) >> 2};
345 for (int j{0}; j < digits; ++j) {
346 int pos{(digits - 1 - j) * 4};
347 char nybble = IBITS(pos, 4).ToUInt64();
348 if (nybble != 0 || !result.empty() || j + 1 == digits) {
349 char digit = '0' + nybble;
350 if (digit > '9') {
351 digit += 'a' - ('9' + 1);
352 }
353 result += digit;
354 }
355 }
356 return result;
357 }
358
359 static constexpr int DIGITS{bits - 1}; // don't count the sign bit
360 static constexpr Integer HUGE() { return MASKR(bits - 1); }
361 static constexpr Integer Least() { return MASKL(1); }
362 static constexpr int RANGE{// in the sense of SELECTED_INT_KIND
363 // This magic value is LOG10(2.)*1E12.
364 static_cast<int>(((bits - 1) * 301029995664) / 1000000000000)};
365
366 constexpr bool IsZero() const {
367 for (int j{0}; j < parts; ++j) {
368 if (part_[j] != 0) {
369 return false;
370 }
371 }
372 return true;
373 }
374
375 constexpr bool IsNegative() const {
376 return (LEPart(parts - 1) >> (topPartBits - 1)) & 1;
377 }
378
379 constexpr Ordering CompareToZeroSigned() const {
380 if (IsNegative()) {
381 return Ordering::Less;
382 } else if (IsZero()) {
383 return Ordering::Equal;
384 } else {
385 return Ordering::Greater;
386 }
387 }
388
389 // Count the number of contiguous most-significant bit positions
390 // that are clear.
391 constexpr int LEADZ() const {
392 if (LEPart(parts - 1) != 0) {
393 int lzbc{common::LeadingZeroBitCount(LEPart(parts - 1))};
394 return lzbc - extraTopPartBits;
395 }
396 int upperZeroes{topPartBits};
397 for (int j{1}; j < parts; ++j) {
398 if (Part p{LEPart(parts - 1 - j)}) {
399 int lzbc{common::LeadingZeroBitCount(p)};
400 return upperZeroes + lzbc - extraPartBits;
401 }
402 upperZeroes += partBits;
403 }
404 return bits;
405 }
406
407 // Count the number of bit positions that are set.
408 constexpr int POPCNT() const {
409 int count{0};
410 for (int j{0}; j < parts; ++j) {
411 count += common::BitPopulationCount(part_[j]);
412 }
413 return count;
414 }
415
416 // True when POPCNT is odd.
417 constexpr bool POPPAR() const { return POPCNT() & 1; }
418
419 constexpr int TRAILZ() const {
420 auto minus1{AddUnsigned(MASKR(bits))}; // { x-1, carry = x > 0 }
421 if (!minus1.carry) {
422 return bits; // was zero
423 } else {
424 // x ^ (x-1) has all bits set at and below original least-order set bit.
425 return IEOR(minus1.value).POPCNT() - 1;
426 }
427 }
428
429 constexpr bool BTEST(int pos) const {
430 if (pos < 0 || pos >= bits) {
431 return false;
432 } else {
433 return (LEPart(pos / partBits) >> (pos % partBits)) & 1;
434 }
435 }
436
437 constexpr Ordering CompareUnsigned(const Integer &y) const {
438 for (int j{parts}; j-- > 0;) {
439 if (LEPart(j) > y.LEPart(j)) {
440 return Ordering::Greater;
441 }
442 if (LEPart(j) < y.LEPart(j)) {
443 return Ordering::Less;
444 }
445 }
446 return Ordering::Equal;
447 }
448
449 constexpr bool BGE(const Integer &y) const {
450 return CompareUnsigned(y) != Ordering::Less;
451 }
452 constexpr bool BGT(const Integer &y) const {
453 return CompareUnsigned(y) == Ordering::Greater;
454 }
455 constexpr bool BLE(const Integer &y) const { return !BGT(y); }
456 constexpr bool BLT(const Integer &y) const { return !BGE(y); }
457
458 constexpr Ordering CompareSigned(const Integer &y) const {
459 bool isNegative{IsNegative()};
460 if (isNegative != y.IsNegative()) {
461 return isNegative ? Ordering::Less : Ordering::Greater;
462 }
463 return CompareUnsigned(y);
464 }
465
466 template <typename UINT = std::uint64_t> constexpr UINT ToUInt() const {
467 UINT n{LEPart(0)};
468 std::size_t filled{partBits};
469 constexpr std::size_t maxBits{CHAR_BIT8 * sizeof n};
470 for (int j{1}; filled < maxBits && j < parts; ++j, filled += partBits) {
471 n |= UINT{LEPart(j)} << filled;
472 }
473 return n;
474 }
475
476 template <typename SINT = std::int64_t, typename UINT = std::uint64_t>
477 constexpr SINT ToSInt() const {
478 SINT n = ToUInt<UINT>();
479 constexpr std::size_t maxBits{CHAR_BIT8 * sizeof n};
480 if constexpr (bits
49.1
'bits' is < 'maxBits'
49.1
'bits' is < 'maxBits'
< maxBits) {
50
Taking true branch
481 n |= -(n >> (bits - 1)) << bits;
51
The result of the left shift is undefined because the left operand is negative
482 }
483 return n;
484 }
485
486 constexpr std::uint64_t ToUInt64() const { return ToUInt<std::uint64_t>(); }
487
488 constexpr std::int64_t ToInt64() const {
489 return ToSInt<std::int64_t, std::uint64_t>();
49
Calling 'Integer::ToSInt'
490 }
491
492 // Ones'-complement (i.e., C's ~)
493 constexpr Integer NOT() const {
494 Integer result{nullptr};
495 for (int j{0}; j < parts; ++j) {
496 result.SetLEPart(j, ~LEPart(j));
497 }
498 return result;
499 }
500
501 // Two's-complement negation (-x = ~x + 1).
502 // An overflow flag accompanies the result, and will be true when the
503 // operand is the most negative signed number (MASKL(1)).
504 constexpr ValueWithOverflow Negate() const {
505 Integer result{nullptr};
506 Part carry{1};
507 for (int j{0}; j + 1 < parts; ++j) {
508 Part newCarry{LEPart(j) == 0 && carry};
509 result.SetLEPart(j, ~LEPart(j) + carry);
510 carry = newCarry;
511 }
512 Part top{LEPart(parts - 1)};
513 result.SetLEPart(parts - 1, ~top + carry);
514 bool overflow{top != 0 && result.LEPart(parts - 1) == top};
515 return {result, overflow};
516 }
517
518 constexpr ValueWithOverflow ABS() const {
519 if (IsNegative()) {
520 return Negate();
521 } else {
522 return {*this, false};
523 }
524 }
525
526 // Shifts the operand left when the count is positive, right when negative.
527 // Vacated bit positions are filled with zeroes.
528 constexpr Integer ISHFT(int count) const {
529 if (count < 0) {
530 return SHIFTR(-count);
531 } else {
532 return SHIFTL(count);
533 }
534 }
535
536 // Left shift with zero fill.
537 constexpr Integer SHIFTL(int count) const {
538 if (count <= 0) {
539 return *this;
540 } else {
541 Integer result{nullptr};
542 int shiftParts{count / partBits};
543 int bitShift{count - partBits * shiftParts};
544 int j{parts - 1};
545 if (bitShift == 0) {
546 for (; j >= shiftParts; --j) {
547 result.SetLEPart(j, LEPart(j - shiftParts));
548 }
549 for (; j >= 0; --j) {
550 result.LEPart(j) = 0;
551 }
552 } else {
553 for (; j > shiftParts; --j) {
554 result.SetLEPart(j,
555 ((LEPart(j - shiftParts) << bitShift) |
556 (LEPart(j - shiftParts - 1) >> (partBits - bitShift))));
557 }
558 if (j == shiftParts) {
559 result.SetLEPart(j, LEPart(0) << bitShift);
560 --j;
561 }
562 for (; j >= 0; --j) {
563 result.LEPart(j) = 0;
564 }
565 }
566 return result;
567 }
568 }
569
570 // Circular shift of a field of least-significant bits. The least-order
571 // "size" bits are shifted circularly in place by "count" positions;
572 // the shift is leftward if count is nonnegative, rightward otherwise.
573 // Higher-order bits are unchanged.
574 constexpr Integer ISHFTC(int count, int size = bits) const {
575 if (count == 0 || size <= 0) {
576 return *this;
577 }
578 if (size > bits) {
579 size = bits;
580 }
581 count %= size;
582 if (count == 0) {
583 return *this;
584 }
585 int middleBits{size - count}, leastBits{count};
586 if (count < 0) {
587 middleBits = -count;
588 leastBits = size + count;
589 }
590 if (size == bits) {
591 return SHIFTL(leastBits).IOR(SHIFTR(middleBits));
592 }
593 Integer unchanged{IAND(MASKL(bits - size))};
594 Integer middle{IAND(MASKR(middleBits)).SHIFTL(leastBits)};
595 Integer least{SHIFTR(middleBits).IAND(MASKR(leastBits))};
596 return unchanged.IOR(middle).IOR(least);
597 }
598
599 // Double shifts, aka shifts with specific fill.
600 constexpr Integer SHIFTLWithFill(const Integer &fill, int count) const {
601 if (count <= 0) {
602 return *this;
603 } else if (count >= 2 * bits) {
604 return {};
605 } else if (count > bits) {
606 return fill.SHIFTL(count - bits);
607 } else if (count == bits) {
608 return fill;
609 } else {
610 return SHIFTL(count).IOR(fill.SHIFTR(bits - count));
611 }
612 }
613
614 constexpr Integer SHIFTRWithFill(const Integer &fill, int count) const {
615 if (count <= 0) {
616 return *this;
617 } else if (count >= 2 * bits) {
618 return {};
619 } else if (count > bits) {
620 return fill.SHIFTR(count - bits);
621 } else if (count == bits) {
622 return fill;
623 } else {
624 return SHIFTR(count).IOR(fill.SHIFTL(bits - count));
625 }
626 }
627
628 constexpr Integer DSHIFTL(const Integer &fill, int count) const {
629 // DSHIFTL(I,J) shifts I:J left; the second argument is the right fill.
630 return SHIFTLWithFill(fill, count);
631 }
632
633 constexpr Integer DSHIFTR(const Integer &value, int count) const {
634 // DSHIFTR(I,J) shifts I:J right; the *first* argument is the left fill.
635 return value.SHIFTRWithFill(*this, count);
636 }
637
638 // Vacated upper bits are filled with zeroes.
639 constexpr Integer SHIFTR(int count) const {
640 if (count <= 0) {
641 return *this;
642 } else {
643 Integer result{nullptr};
644 int shiftParts{count / partBits};
645 int bitShift{count - partBits * shiftParts};
646 int j{0};
647 if (bitShift == 0) {
648 for (; j + shiftParts < parts; ++j) {
649 result.LEPart(j) = LEPart(j + shiftParts);
650 }
651 for (; j < parts; ++j) {
652 result.LEPart(j) = 0;
653 }
654 } else {
655 for (; j + shiftParts + 1 < parts; ++j) {
656 result.SetLEPart(j,
657 (LEPart(j + shiftParts) >> bitShift) |
658 (LEPart(j + shiftParts + 1) << (partBits - bitShift)));
659 }
660 if (j + shiftParts + 1 == parts) {
661 result.LEPart(j++) = LEPart(parts - 1) >> bitShift;
662 }
663 for (; j < parts; ++j) {
664 result.LEPart(j) = 0;
665 }
666 }
667 return result;
668 }
669 }
670
671 // Be advised, an arithmetic (sign-filling) right shift is not
672 // the same as a division by a power of two in all cases.
673 constexpr Integer SHIFTA(int count) const {
674 if (count <= 0) {
675 return *this;
676 } else if (IsNegative()) {
677 return SHIFTR(count).IOR(MASKL(count));
678 } else {
679 return SHIFTR(count);
680 }
681 }
682
683 // Clears a single bit.
684 constexpr Integer IBCLR(int pos) const {
685 if (pos < 0 || pos >= bits) {
686 return *this;
687 } else {
688 Integer result{*this};
689 result.LEPart(pos / partBits) &= ~(Part{1} << (pos % partBits));
690 return result;
691 }
692 }
693
694 // Sets a single bit.
695 constexpr Integer IBSET(int pos) const {
696 if (pos < 0 || pos >= bits) {
697 return *this;
698 } else {
699 Integer result{*this};
700 result.LEPart(pos / partBits) |= Part{1} << (pos % partBits);
701 return result;
702 }
703 }
704
705 // Extracts a field.
706 constexpr Integer IBITS(int pos, int size) const {
707 return SHIFTR(pos).IAND(MASKR(size));
708 }
709
710 constexpr Integer IAND(const Integer &y) const {
711 Integer result{nullptr};
712 for (int j{0}; j < parts; ++j) {
713 result.LEPart(j) = LEPart(j) & y.LEPart(j);
714 }
715 return result;
716 }
717
718 constexpr Integer IOR(const Integer &y) const {
719 Integer result{nullptr};
720 for (int j{0}; j < parts; ++j) {
721 result.LEPart(j) = LEPart(j) | y.LEPart(j);
722 }
723 return result;
724 }
725
726 constexpr Integer IEOR(const Integer &y) const {
727 Integer result{nullptr};
728 for (int j{0}; j < parts; ++j) {
729 result.LEPart(j) = LEPart(j) ^ y.LEPart(j);
730 }
731 return result;
732 }
733
734 constexpr Integer MERGE_BITS(const Integer &y, const Integer &mask) const {
735 return IAND(mask).IOR(y.IAND(mask.NOT()));
736 }
737
738 constexpr Integer MAX(const Integer &y) const {
739 if (CompareSigned(y) == Ordering::Less) {
740 return y;
741 } else {
742 return *this;
743 }
744 }
745
746 constexpr Integer MIN(const Integer &y) const {
747 if (CompareSigned(y) == Ordering::Less) {
748 return *this;
749 } else {
750 return y;
751 }
752 }
753
754 // Unsigned addition with carry.
755 constexpr ValueWithCarry AddUnsigned(
756 const Integer &y, bool carryIn = false) const {
757 Integer sum{nullptr};
758 BigPart carry{carryIn};
759 for (int j{0}; j + 1 < parts; ++j) {
760 carry += LEPart(j);
761 carry += y.LEPart(j);
762 sum.SetLEPart(j, carry);
763 carry >>= partBits;
764 }
765 carry += LEPart(parts - 1);
766 carry += y.LEPart(parts - 1);
767 sum.SetLEPart(parts - 1, carry);
768 return {sum, carry > topPartMask};
769 }
770
771 constexpr ValueWithOverflow AddSigned(const Integer &y) const {
772 bool isNegative{IsNegative()};
773 bool sameSign{isNegative == y.IsNegative()};
774 ValueWithCarry sum{AddUnsigned(y)};
775 bool overflow{sameSign && sum.value.IsNegative() != isNegative};
776 return {sum.value, overflow};
777 }
778
779 constexpr ValueWithOverflow SubtractSigned(const Integer &y) const {
780 bool isNegative{IsNegative()};
781 bool sameSign{isNegative == y.IsNegative()};
782 ValueWithCarry diff{AddUnsigned(y.Negate().value)};
783 bool overflow{!sameSign && diff.value.IsNegative() != isNegative};
784 return {diff.value, overflow};
785 }
786
787 // DIM(X,Y)=MAX(X-Y, 0)
788 constexpr ValueWithOverflow DIM(const Integer &y) const {
789 if (CompareSigned(y) != Ordering::Greater) {
790 return {};
791 } else {
792 return SubtractSigned(y);
793 }
794 }
795
796 constexpr ValueWithOverflow SIGN(bool toNegative) const {
797 if (toNegative == IsNegative()) {
798 return {*this, false};
799 } else if (toNegative) {
800 return Negate();
801 } else {
802 return ABS();
803 }
804 }
805
806 constexpr ValueWithOverflow SIGN(const Integer &sign) const {
807 return SIGN(sign.IsNegative());
808 }
809
810 constexpr Product MultiplyUnsigned(const Integer &y) const {
811 Part product[2 * parts]{}; // little-endian full product
812 for (int j{0}; j < parts; ++j) {
813 if (Part xpart{LEPart(j)}) {
814 for (int k{0}; k < parts; ++k) {
815 if (Part ypart{y.LEPart(k)}) {
816 BigPart xy{xpart};
817 xy *= ypart;
818#if defined __GNUC__4 && __GNUC__4 < 8
819 // && to < (2 * parts) was added to avoid GCC < 8 build failure on
820 // -Werror=array-bounds. This can be removed if -Werror is disable.
821 for (int to{j + k}; xy != 0 && to < (2 * parts); ++to) {
822#else
823 for (int to{j + k}; xy != 0; ++to) {
824#endif
825 xy += product[to];
826 product[to] = xy & partMask;
827 xy >>= partBits;
828 }
829 }
830 }
831 }
832 }
833 Integer upper{nullptr}, lower{nullptr};
834 for (int j{0}; j < parts; ++j) {
835 lower.LEPart(j) = product[j];
836 upper.LEPart(j) = product[j + parts];
837 }
838 if constexpr (topPartBits < partBits) {
839 upper = upper.SHIFTL(partBits - topPartBits);
840 upper.LEPart(0) |= lower.LEPart(parts - 1) >> topPartBits;
841 lower.LEPart(parts - 1) &= topPartMask;
842 }
843 return {upper, lower};
844 }
845
846 constexpr Product MultiplySigned(const Integer &y) const {
847 bool yIsNegative{y.IsNegative()};
848 Integer absy{y};
849 if (yIsNegative) {
850 absy = y.Negate().value;
851 }
852 bool isNegative{IsNegative()};
853 Integer absx{*this};
854 if (isNegative) {
855 absx = Negate().value;
856 }
857 Product product{absx.MultiplyUnsigned(absy)};
858 if (isNegative != yIsNegative) {
859 product.lower = product.lower.NOT();
860 product.upper = product.upper.NOT();
861 Integer one{1};
862 auto incremented{product.lower.AddUnsigned(one)};
863 product.lower = incremented.value;
864 if (incremented.carry) {
865 product.upper = product.upper.AddUnsigned(one).value;
866 }
867 }
868 return product;
869 }
870
871 constexpr QuotientWithRemainder DivideUnsigned(const Integer &divisor) const {
872 if (divisor.IsZero()) {
873 return {MASKR(bits), Integer{}, true, false}; // overflow to max value
874 }
875 int bitsDone{LEADZ()};
876 Integer top{SHIFTL(bitsDone)};
877 Integer quotient, remainder;
878 for (; bitsDone < bits; ++bitsDone) {
879 auto doubledTop{top.AddUnsigned(top)};
880 top = doubledTop.value;
881 remainder = remainder.AddUnsigned(remainder, doubledTop.carry).value;
882 bool nextBit{remainder.CompareUnsigned(divisor) != Ordering::Less};
883 quotient = quotient.AddUnsigned(quotient, nextBit).value;
884 if (nextBit) {
885 remainder = remainder.SubtractSigned(divisor).value;
886 }
887 }
888 return {quotient, remainder, false, false};
889 }
890
891 // A nonzero remainder has the sign of the dividend, i.e., it computes
892 // the MOD intrinsic (X-INT(X/Y)*Y), not MODULO (which is below).
893 // 8/5 = 1r3; -8/5 = -1r-3; 8/-5 = -1r3; -8/-5 = 1r-3
894 constexpr QuotientWithRemainder DivideSigned(Integer divisor) const {
895 bool dividendIsNegative{IsNegative()};
896 bool negateQuotient{dividendIsNegative};
897 Ordering divisorOrdering{divisor.CompareToZeroSigned()};
898 if (divisorOrdering == Ordering::Less) {
899 negateQuotient = !negateQuotient;
900 auto negated{divisor.Negate()};
901 if (negated.overflow) {
902 // divisor was (and is) the most negative number
903 if (CompareUnsigned(divisor) == Ordering::Equal) {
904 return {MASKR(1), Integer{}, false, bits <= 1};
905 } else {
906 return {Integer{}, *this, false, false};
907 }
908 }
909 divisor = negated.value;
910 } else if (divisorOrdering == Ordering::Equal) {
911 // division by zero
912 if (dividendIsNegative) {
913 return {MASKL(1), Integer{}, true, false};
914 } else {
915 return {MASKR(bits - 1), Integer{}, true, false};
916 }
917 }
918 Integer dividend{*this};
919 if (dividendIsNegative) {
920 auto negated{Negate()};
921 if (negated.overflow) {
922 // Dividend was (and remains) the most negative number.
923 // See whether the original divisor was -1 (if so, it's 1 now).
924 if (divisorOrdering == Ordering::Less &&
925 divisor.CompareUnsigned(Integer{1}) == Ordering::Equal) {
926 // most negative number / -1 is the sole overflow case
927 return {*this, Integer{}, false, true};
928 }
929 } else {
930 dividend = negated.value;
931 }
932 }
933 // Overflow is not possible, and both the dividend and divisor
934 // are now positive.
935 QuotientWithRemainder result{dividend.DivideUnsigned(divisor)};
936 if (negateQuotient) {
937 result.quotient = result.quotient.Negate().value;
938 }
939 if (dividendIsNegative) {
940 result.remainder = result.remainder.Negate().value;
941 }
942 return result;
943 }
944
945 // Result has the sign of the divisor argument.
946 // 8 mod 5 = 3; -8 mod 5 = 2; 8 mod -5 = -2; -8 mod -5 = -3
947 constexpr ValueWithOverflow MODULO(const Integer &divisor) const {
948 bool negativeDivisor{divisor.IsNegative()};
949 bool distinctSigns{IsNegative() != negativeDivisor};
950 QuotientWithRemainder divided{DivideSigned(divisor)};
951 if (distinctSigns && !divided.remainder.IsZero()) {
952 return {divided.remainder.AddUnsigned(divisor).value, divided.overflow};
953 } else {
954 return {divided.remainder, divided.overflow};
955 }
956 }
957
958 constexpr PowerWithErrors Power(const Integer &exponent) const {
959 PowerWithErrors result{1, false, false, false};
960 if (exponent.IsZero()) {
961 // x**0 -> 1, including the case 0**0, which is not defined specifically
962 // in F'18 afaict; however, other Fortrans tested all produce 1, not 0,
963 // apart from nagfor, which stops with an error at runtime.
964 // Ada, APL, C's pow(), Haskell, Julia, MATLAB, and R all produce 1 too.
965 // F'77 explicitly states that 0**0 is mathematically undefined and
966 // therefore prohibited.
967 result.zeroToZero = IsZero();
968 } else if (exponent.IsNegative()) {
969 if (IsZero()) {
970 result.divisionByZero = true;
971 result.power = MASKR(bits - 1);
972 } else if (CompareSigned(Integer{1}) == Ordering::Equal) {
973 result.power = *this; // 1**x -> 1
974 } else if (CompareSigned(Integer{-1}) == Ordering::Equal) {
975 if (exponent.BTEST(0)) {
976 result.power = *this; // (-1)**x -> -1 if x is odd
977 }
978 } else {
979 result.power.Clear(); // j**k -> 0 if |j| > 1 and k < 0
980 }
981 } else {
982 Integer shifted{*this};
983 Integer pow{exponent};
984 int nbits{bits - pow.LEADZ()};
985 for (int j{0}; j < nbits; ++j) {
986 if (pow.BTEST(j)) {
987 Product product{result.power.MultiplySigned(shifted)};
988 result.power = product.lower;
989 result.overflow |= product.SignedMultiplicationOverflowed();
990 }
991 if (j + 1 < nbits) {
992 Product squared{shifted.MultiplySigned(shifted)};
993 result.overflow |= squared.SignedMultiplicationOverflowed();
994 shifted = squared.lower;
995 }
996 }
997 }
998 return result;
999 }
1000
1001private:
1002 // A private constructor, selected by the use of nullptr,
1003 // that is used by member functions when it would be a waste
1004 // of time to initialize parts_[].
1005 constexpr Integer(std::nullptr_t) {}
1006
1007 // Accesses parts in little-endian order.
1008 constexpr const Part &LEPart(int part) const {
1009 if constexpr (littleEndian) {
1010 return part_[part];
1011 } else {
1012 return part_[parts - 1 - part];
1013 }
1014 }
1015
1016 constexpr Part &LEPart(int part) {
1017 if constexpr (littleEndian) {
1018 return part_[part];
1019 } else {
1020 return part_[parts - 1 - part];
1021 }
1022 }
1023
1024 constexpr void SetLEPart(int part, Part x) {
1025 LEPart(part) = x & PartMask(part);
1026 }
1027
1028 static constexpr Part PartMask(int part) {
1029 return part == parts - 1 ? topPartMask : partMask;
1030 }
1031
1032 constexpr void Clear() {
1033 for (int j{0}; j < parts; ++j) {
1034 part_[j] = 0;
1035 }
1036 }
1037
1038 Part part_[parts]{};
1039};
1040
1041extern template class Integer<8>;
1042extern template class Integer<16>;
1043extern template class Integer<32>;
1044extern template class Integer<64>;
1045extern template class Integer<80>;
1046extern template class Integer<128>;
1047} // namespace Fortran::evaluate::value
1048#endif // FORTRAN_EVALUATE_INTEGER_H_