Bug Summary

File:build/source/flang/include/flang/Evaluate/integer.h
Warning:line 471, column 28
The result of the left shift is undefined due to shifting '-1' by '32', which is unrepresentable in the unsigned version of the return type 'unsigned long'

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 real.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/real.cpp

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

1#include "fp-testing.h"
2#include "testing.h"
3#include "flang/Evaluate/type.h"
4#include "llvm/Support/raw_ostream.h"
5#include <cmath>
6#include <cstdio>
7#include <cstdlib>
8#include <type_traits>
9
10using namespace Fortran::evaluate;
11using namespace Fortran::common;
12
13using Real2 = Scalar<Type<TypeCategory::Real, 2>>;
14using Real3 = Scalar<Type<TypeCategory::Real, 3>>;
15using Real4 = Scalar<Type<TypeCategory::Real, 4>>;
16using Real8 = Scalar<Type<TypeCategory::Real, 8>>;
17using Real10 = Scalar<Type<TypeCategory::Real, 10>>;
18using Real16 = Scalar<Type<TypeCategory::Real, 16>>;
19using Integer4 = Scalar<Type<TypeCategory::Integer, 4>>;
20using Integer8 = Scalar<Type<TypeCategory::Integer, 8>>;
21
22void dumpTest() {
23 struct {
24 std::uint64_t raw;
25 const char *expected;
26 } table[] = {
27 {0x7f876543, "NaN0x7f876543"},
28 {0x7f800000, "Inf"},
29 {0xff800000, "-Inf"},
30 {0x00000000, "0.0"},
31 {0x80000000, "-0.0"},
32 {0x3f800000, "0x1.0p0"},
33 {0xbf800000, "-0x1.0p0"},
34 {0x40000000, "0x1.0p1"},
35 {0x3f000000, "0x1.0p-1"},
36 {0x7f7fffff, "0x1.fffffep127"},
37 {0x00800000, "0x1.0p-126"},
38 {0x00400000, "0x0.8p-126"},
39 {0x00000001, "0x0.000002p-126"},
40 {0, nullptr},
41 };
42 for (int j{0}; table[j].expected != nullptr; ++j) {
43 TEST(Real4{Integer4{table[j].raw}}.DumpHexadecimal() == table[j].expected)testing::Test("flang/unittests/Evaluate/real.cpp", 43, "Real4{Integer4{table[j].raw}}.DumpHexadecimal() == table[j].expected"
, (Real4{Integer4{table[j].raw}}.DumpHexadecimal() == table[j
].expected))
44 ("%d", j);
45 }
46}
47
48template <typename R> void basicTests(int rm, Rounding rounding) {
49 static constexpr int kind{R::bits / 8};
50 char desc[64];
51 using Word = typename R::Word;
52 std::snprintf(desc, sizeof desc, "bits=%d, le=%d, kind=%d", R::bits,
53 Word::littleEndian, kind);
54 R zero;
55 TEST(!zero.IsNegative())testing::Test("flang/unittests/Evaluate/real.cpp", 55, "!zero.IsNegative()"
, (!zero.IsNegative()))
(desc);
56 TEST(!zero.IsNotANumber())testing::Test("flang/unittests/Evaluate/real.cpp", 56, "!zero.IsNotANumber()"
, (!zero.IsNotANumber()))
(desc);
57 TEST(!zero.IsInfinite())testing::Test("flang/unittests/Evaluate/real.cpp", 57, "!zero.IsInfinite()"
, (!zero.IsInfinite()))
(desc);
58 TEST(zero.IsZero())testing::Test("flang/unittests/Evaluate/real.cpp", 58, "zero.IsZero()"
, (zero.IsZero()))
(desc);
59 MATCH(0, zero.Exponent())testing::Match("flang/unittests/Evaluate/real.cpp", 59, (0), "zero.Exponent()"
, (zero.Exponent()))
(desc);
60 TEST(zero.RawBits().IsZero())testing::Test("flang/unittests/Evaluate/real.cpp", 60, "zero.RawBits().IsZero()"
, (zero.RawBits().IsZero()))
(desc);
61 MATCH(0, zero.RawBits().ToUInt64())testing::Match("flang/unittests/Evaluate/real.cpp", 61, (0), "zero.RawBits().ToUInt64()"
, (zero.RawBits().ToUInt64()))
(desc);
62 TEST(zero.ABS().RawBits().IsZero())testing::Test("flang/unittests/Evaluate/real.cpp", 62, "zero.ABS().RawBits().IsZero()"
, (zero.ABS().RawBits().IsZero()))
(desc);
63 TEST(zero.Negate().RawBits().IEOR(Word::MASKL(1)).IsZero())testing::Test("flang/unittests/Evaluate/real.cpp", 63, "zero.Negate().RawBits().IEOR(Word::MASKL(1)).IsZero()"
, (zero.Negate().RawBits().IEOR(Word::MASKL(1)).IsZero()))
(desc);
64 TEST(zero.Compare(zero) == Relation::Equal)testing::Test("flang/unittests/Evaluate/real.cpp", 64, "zero.Compare(zero) == Relation::Equal"
, (zero.Compare(zero) == Relation::Equal))
(desc);
1
Assuming the condition is false
65 R minusZero{Word{std::uint64_t{1}}.SHIFTL(R::bits - 1)};
66 TEST(minusZero.IsNegative())testing::Test("flang/unittests/Evaluate/real.cpp", 66, "minusZero.IsNegative()"
, (minusZero.IsNegative()))
(desc);
67 TEST(!minusZero.IsNotANumber())testing::Test("flang/unittests/Evaluate/real.cpp", 67, "!minusZero.IsNotANumber()"
, (!minusZero.IsNotANumber()))
(desc);
68 TEST(!minusZero.IsInfinite())testing::Test("flang/unittests/Evaluate/real.cpp", 68, "!minusZero.IsInfinite()"
, (!minusZero.IsInfinite()))
(desc);
69 TEST(minusZero.IsZero())testing::Test("flang/unittests/Evaluate/real.cpp", 69, "minusZero.IsZero()"
, (minusZero.IsZero()))
(desc);
70 TEST(minusZero.ABS().RawBits().IsZero())testing::Test("flang/unittests/Evaluate/real.cpp", 70, "minusZero.ABS().RawBits().IsZero()"
, (minusZero.ABS().RawBits().IsZero()))
(desc);
71 TEST(minusZero.Negate().RawBits().IsZero())testing::Test("flang/unittests/Evaluate/real.cpp", 71, "minusZero.Negate().RawBits().IsZero()"
, (minusZero.Negate().RawBits().IsZero()))
(desc);
72 MATCH(0, minusZero.Exponent())testing::Match("flang/unittests/Evaluate/real.cpp", 72, (0), "minusZero.Exponent()"
, (minusZero.Exponent()))
(desc);
73 MATCH(0, minusZero.RawBits().LEADZ())testing::Match("flang/unittests/Evaluate/real.cpp", 73, (0), "minusZero.RawBits().LEADZ()"
, (minusZero.RawBits().LEADZ()))
(desc);
74 MATCH(1, minusZero.RawBits().POPCNT())testing::Match("flang/unittests/Evaluate/real.cpp", 74, (1), "minusZero.RawBits().POPCNT()"
, (minusZero.RawBits().POPCNT()))
(desc);
75 TEST(minusZero.Compare(minusZero) == Relation::Equal)testing::Test("flang/unittests/Evaluate/real.cpp", 75, "minusZero.Compare(minusZero) == Relation::Equal"
, (minusZero.Compare(minusZero) == Relation::Equal))
(desc);
2
Assuming the condition is false
76 TEST(zero.Compare(minusZero) == Relation::Equal)testing::Test("flang/unittests/Evaluate/real.cpp", 76, "zero.Compare(minusZero) == Relation::Equal"
, (zero.Compare(minusZero) == Relation::Equal))
(desc);
3
Assuming the condition is false
77 ValueWithRealFlags<R> vr;
78 MATCH(0, vr.value.RawBits().ToUInt64())testing::Match("flang/unittests/Evaluate/real.cpp", 78, (0), "vr.value.RawBits().ToUInt64()"
, (vr.value.RawBits().ToUInt64()))
(desc);
79 TEST(vr.flags.empty())testing::Test("flang/unittests/Evaluate/real.cpp", 79, "vr.flags.empty()"
, (vr.flags.empty()))
(desc);
80 R nan{Word{std::uint64_t{1}}
81 .SHIFTL(R::bits)
82 .SubtractSigned(Word{std::uint64_t{1}})
83 .value};
84 MATCH(R::bits, nan.RawBits().POPCNT())testing::Match("flang/unittests/Evaluate/real.cpp", 84, (R::bits
), "nan.RawBits().POPCNT()", (nan.RawBits().POPCNT()))
(desc);
85 TEST(!nan.IsNegative())testing::Test("flang/unittests/Evaluate/real.cpp", 85, "!nan.IsNegative()"
, (!nan.IsNegative()))
(desc);
86 TEST(nan.IsNotANumber())testing::Test("flang/unittests/Evaluate/real.cpp", 86, "nan.IsNotANumber()"
, (nan.IsNotANumber()))
(desc);
87 TEST(!nan.IsInfinite())testing::Test("flang/unittests/Evaluate/real.cpp", 87, "!nan.IsInfinite()"
, (!nan.IsInfinite()))
(desc);
88 TEST(!nan.IsZero())testing::Test("flang/unittests/Evaluate/real.cpp", 88, "!nan.IsZero()"
, (!nan.IsZero()))
(desc);
89 TEST(zero.Compare(nan) == Relation::Unordered)testing::Test("flang/unittests/Evaluate/real.cpp", 89, "zero.Compare(nan) == Relation::Unordered"
, (zero.Compare(nan) == Relation::Unordered))
(desc);
4
Assuming the condition is false
90 TEST(minusZero.Compare(nan) == Relation::Unordered)testing::Test("flang/unittests/Evaluate/real.cpp", 90, "minusZero.Compare(nan) == Relation::Unordered"
, (minusZero.Compare(nan) == Relation::Unordered))
(desc);
5
Assuming the condition is false
91 TEST(nan.Compare(zero) == Relation::Unordered)testing::Test("flang/unittests/Evaluate/real.cpp", 91, "nan.Compare(zero) == Relation::Unordered"
, (nan.Compare(zero) == Relation::Unordered))
(desc);
6
Assuming the condition is false
92 TEST(nan.Compare(minusZero) == Relation::Unordered)testing::Test("flang/unittests/Evaluate/real.cpp", 92, "nan.Compare(minusZero) == Relation::Unordered"
, (nan.Compare(minusZero) == Relation::Unordered))
(desc);
7
Assuming the condition is false
93 TEST(nan.Compare(nan) == Relation::Unordered)testing::Test("flang/unittests/Evaluate/real.cpp", 93, "nan.Compare(nan) == Relation::Unordered"
, (nan.Compare(nan) == Relation::Unordered))
(desc);
8
Assuming the condition is false
94 int significandBits{R::binaryPrecision - R::isImplicitMSB};
95 int exponentBits{R::bits - significandBits - 1};
96 std::uint64_t maxExponent{(std::uint64_t{1} << exponentBits) - 1};
97 MATCH(nan.Exponent(), maxExponent)testing::Match("flang/unittests/Evaluate/real.cpp", 97, (nan.
Exponent()), "maxExponent", (maxExponent))
(desc);
98 R inf{Word{maxExponent}.SHIFTL(significandBits)};
99 TEST(!inf.IsNegative())testing::Test("flang/unittests/Evaluate/real.cpp", 99, "!inf.IsNegative()"
, (!inf.IsNegative()))
(desc);
9
Assuming the condition is false
100 TEST(!inf.IsNotANumber())testing::Test("flang/unittests/Evaluate/real.cpp", 100, "!inf.IsNotANumber()"
, (!inf.IsNotANumber()))
(desc);
101 TEST(inf.IsInfinite())testing::Test("flang/unittests/Evaluate/real.cpp", 101, "inf.IsInfinite()"
, (inf.IsInfinite()))
(desc);
102 TEST(!inf.IsZero())testing::Test("flang/unittests/Evaluate/real.cpp", 102, "!inf.IsZero()"
, (!inf.IsZero()))
(desc);
103 TEST(inf.RawBits().CompareUnsigned(inf.ABS().RawBits()) == Ordering::Equal)testing::Test("flang/unittests/Evaluate/real.cpp", 103, "inf.RawBits().CompareUnsigned(inf.ABS().RawBits()) == Ordering::Equal"
, (inf.RawBits().CompareUnsigned(inf.ABS().RawBits()) == Ordering
::Equal))
104 (desc);
105 TEST(zero.Compare(inf) == Relation::Less)testing::Test("flang/unittests/Evaluate/real.cpp", 105, "zero.Compare(inf) == Relation::Less"
, (zero.Compare(inf) == Relation::Less))
(desc);
10
Assuming the condition is false
106 TEST(minusZero.Compare(inf) == Relation::Less)testing::Test("flang/unittests/Evaluate/real.cpp", 106, "minusZero.Compare(inf) == Relation::Less"
, (minusZero.Compare(inf) == Relation::Less))
(desc);
11
Assuming the condition is false
107 TEST(nan.Compare(inf) == Relation::Unordered)testing::Test("flang/unittests/Evaluate/real.cpp", 107, "nan.Compare(inf) == Relation::Unordered"
, (nan.Compare(inf) == Relation::Unordered))
(desc);
12
Assuming the condition is false
108 TEST(inf.Compare(inf) == Relation::Equal)testing::Test("flang/unittests/Evaluate/real.cpp", 108, "inf.Compare(inf) == Relation::Equal"
, (inf.Compare(inf) == Relation::Equal))
(desc);
13
Assuming the condition is false
109 R negInf{Word{maxExponent}.SHIFTL(significandBits).IOR(Word::MASKL(1))};
110 TEST(negInf.IsNegative())testing::Test("flang/unittests/Evaluate/real.cpp", 110, "negInf.IsNegative()"
, (negInf.IsNegative()))
(desc);
111 TEST(!negInf.IsNotANumber())testing::Test("flang/unittests/Evaluate/real.cpp", 111, "!negInf.IsNotANumber()"
, (!negInf.IsNotANumber()))
(desc);
112 TEST(negInf.IsInfinite())testing::Test("flang/unittests/Evaluate/real.cpp", 112, "negInf.IsInfinite()"
, (negInf.IsInfinite()))
(desc);
113 TEST(!negInf.IsZero())testing::Test("flang/unittests/Evaluate/real.cpp", 113, "!negInf.IsZero()"
, (!negInf.IsZero()))
(desc);
114 TEST(inf.RawBits().CompareUnsigned(negInf.ABS().RawBits()) == Ordering::Equal)testing::Test("flang/unittests/Evaluate/real.cpp", 114, "inf.RawBits().CompareUnsigned(negInf.ABS().RawBits()) == Ordering::Equal"
, (inf.RawBits().CompareUnsigned(negInf.ABS().RawBits()) == Ordering
::Equal))
14
Assuming the condition is false
115 (desc);
116 TEST(inf.RawBits().CompareUnsigned(negInf.Negate().RawBits()) ==testing::Test("flang/unittests/Evaluate/real.cpp", 117, "inf.RawBits().CompareUnsigned(negInf.Negate().RawBits()) == Ordering::Equal"
, (inf.RawBits().CompareUnsigned(negInf.Negate().RawBits()) ==
Ordering::Equal))
15
Assuming the condition is false
117 Ordering::Equal)testing::Test("flang/unittests/Evaluate/real.cpp", 117, "inf.RawBits().CompareUnsigned(negInf.Negate().RawBits()) == Ordering::Equal"
, (inf.RawBits().CompareUnsigned(negInf.Negate().RawBits()) ==
Ordering::Equal))
118 (desc);
119 TEST(inf.Negate().RawBits().CompareUnsigned(negInf.RawBits()) ==testing::Test("flang/unittests/Evaluate/real.cpp", 120, "inf.Negate().RawBits().CompareUnsigned(negInf.RawBits()) == Ordering::Equal"
, (inf.Negate().RawBits().CompareUnsigned(negInf.RawBits()) ==
Ordering::Equal))
16
Assuming the condition is false
120 Ordering::Equal)testing::Test("flang/unittests/Evaluate/real.cpp", 120, "inf.Negate().RawBits().CompareUnsigned(negInf.RawBits()) == Ordering::Equal"
, (inf.Negate().RawBits().CompareUnsigned(negInf.RawBits()) ==
Ordering::Equal))
121 (desc);
122 TEST(zero.Compare(negInf) == Relation::Greater)testing::Test("flang/unittests/Evaluate/real.cpp", 122, "zero.Compare(negInf) == Relation::Greater"
, (zero.Compare(negInf) == Relation::Greater))
(desc);
17
Assuming the condition is false
123 TEST(minusZero.Compare(negInf) == Relation::Greater)testing::Test("flang/unittests/Evaluate/real.cpp", 123, "minusZero.Compare(negInf) == Relation::Greater"
, (minusZero.Compare(negInf) == Relation::Greater))
(desc);
18
Assuming the condition is false
124 TEST(nan.Compare(negInf) == Relation::Unordered)testing::Test("flang/unittests/Evaluate/real.cpp", 124, "nan.Compare(negInf) == Relation::Unordered"
, (nan.Compare(negInf) == Relation::Unordered))
(desc);
19
Assuming the condition is false
125 TEST(inf.Compare(negInf) == Relation::Greater)testing::Test("flang/unittests/Evaluate/real.cpp", 125, "inf.Compare(negInf) == Relation::Greater"
, (inf.Compare(negInf) == Relation::Greater))
(desc);
20
Assuming the condition is false
126 TEST(negInf.Compare(negInf) == Relation::Equal)testing::Test("flang/unittests/Evaluate/real.cpp", 126, "negInf.Compare(negInf) == Relation::Equal"
, (negInf.Compare(negInf) == Relation::Equal))
(desc);
21
Assuming the condition is false
127 for (std::uint64_t j{0}; j < 63; ++j) {
22
Loop condition is true. Entering loop body
128 char ldesc[128];
129 std::uint64_t x{1};
130 x <<= j;
131 std::snprintf(ldesc, sizeof ldesc, "%s j=%d x=0x%jx rm=%d", desc,
132 static_cast<int>(j), static_cast<std::intmax_t>(x), rm);
133 Integer8 ix{x};
134 TEST(!ix.IsNegative())testing::Test("flang/unittests/Evaluate/real.cpp", 134, "!ix.IsNegative()"
, (!ix.IsNegative()))
(ldesc);
135 MATCH(x, ix.ToUInt64())testing::Match("flang/unittests/Evaluate/real.cpp", 135, (x),
"ix.ToUInt64()", (ix.ToUInt64()))
(ldesc);
136 vr = R::FromInteger(ix, rounding);
137 TEST(!vr.value.IsNegative())testing::Test("flang/unittests/Evaluate/real.cpp", 137, "!vr.value.IsNegative()"
, (!vr.value.IsNegative()))
(ldesc);
23
Assuming the condition is false
138 TEST(!vr.value.IsNotANumber())testing::Test("flang/unittests/Evaluate/real.cpp", 138, "!vr.value.IsNotANumber()"
, (!vr.value.IsNotANumber()))
(ldesc);
139 TEST(!vr.value.IsZero())testing::Test("flang/unittests/Evaluate/real.cpp", 139, "!vr.value.IsZero()"
, (!vr.value.IsZero()))
(ldesc);
140 auto ivf = vr.value.template ToInteger<Integer8>();
24
Calling 'Real::ToInteger'
35
Returning from 'Real::ToInteger'
141 if (j > (maxExponent / 2)) {
36
Taking false branch
142 TEST(vr.flags.test(RealFlag::Overflow))testing::Test("flang/unittests/Evaluate/real.cpp", 142, "vr.flags.test(RealFlag::Overflow)"
, (vr.flags.test(RealFlag::Overflow)))
(ldesc);
143 TEST(vr.value.IsInfinite())testing::Test("flang/unittests/Evaluate/real.cpp", 143, "vr.value.IsInfinite()"
, (vr.value.IsInfinite()))
(ldesc);
144 TEST(ivf.flags.test(RealFlag::Overflow))testing::Test("flang/unittests/Evaluate/real.cpp", 144, "ivf.flags.test(RealFlag::Overflow)"
, (ivf.flags.test(RealFlag::Overflow)))
(ldesc);
145 MATCH(0x7fffffffffffffff, ivf.value.ToUInt64())testing::Match("flang/unittests/Evaluate/real.cpp", 145, (0x7fffffffffffffff
), "ivf.value.ToUInt64()", (ivf.value.ToUInt64()))
(ldesc);
146 } else {
147 TEST(vr.flags.empty())testing::Test("flang/unittests/Evaluate/real.cpp", 147, "vr.flags.empty()"
, (vr.flags.empty()))
(ldesc);
148 TEST(!vr.value.IsInfinite())testing::Test("flang/unittests/Evaluate/real.cpp", 148, "!vr.value.IsInfinite()"
, (!vr.value.IsInfinite()))
(ldesc);
149 TEST(ivf.flags.empty())testing::Test("flang/unittests/Evaluate/real.cpp", 149, "ivf.flags.empty()"
, (ivf.flags.empty()))
(ldesc);
150 MATCH(x, ivf.value.ToUInt64())testing::Match("flang/unittests/Evaluate/real.cpp", 150, (x),
"ivf.value.ToUInt64()", (ivf.value.ToUInt64()))
(ldesc);
37
Calling 'Integer::ToUInt64'
151 if (rounding.mode == RoundingMode::TiesToEven) { // to match stold()
152 std::string buf;
153 llvm::raw_string_ostream ss{buf};
154 vr.value.AsFortran(ss, kind, false /*exact*/);
155 std::string decimal{ss.str()};
156 const char *p{decimal.data()};
157 MATCH(x, static_cast<std::uint64_t>(std::stold(decimal)))testing::Match("flang/unittests/Evaluate/real.cpp", 157, (x),
"static_cast<std::uint64_t>(std::stold(decimal))", (static_cast
<std::uint64_t>(std::stold(decimal))))
158 ("%s %s", ldesc, p);
159 auto check{R::Read(p, rounding)};
160 auto icheck{check.value.template ToInteger<Integer8>()};
161 MATCH(x, icheck.value.ToUInt64())testing::Match("flang/unittests/Evaluate/real.cpp", 161, (x),
"icheck.value.ToUInt64()", (icheck.value.ToUInt64()))
(ldesc);
162 TEST(vr.value.Compare(check.value) == Relation::Equal)testing::Test("flang/unittests/Evaluate/real.cpp", 162, "vr.value.Compare(check.value) == Relation::Equal"
, (vr.value.Compare(check.value) == Relation::Equal))
(ldesc);
163 }
164 }
165 TEST(vr.value.ToWholeNumber().value.Compare(vr.value) == Relation::Equal)testing::Test("flang/unittests/Evaluate/real.cpp", 165, "vr.value.ToWholeNumber().value.Compare(vr.value) == Relation::Equal"
, (vr.value.ToWholeNumber().value.Compare(vr.value) == Relation
::Equal))
166 (ldesc);
167 ix = ix.Negate().value;
168 TEST(ix.IsNegative())testing::Test("flang/unittests/Evaluate/real.cpp", 168, "ix.IsNegative()"
, (ix.IsNegative()))
(ldesc);
169 x = -x;
170 std::int64_t nx = x;
171 MATCH(x, ix.ToUInt64())testing::Match("flang/unittests/Evaluate/real.cpp", 171, (x),
"ix.ToUInt64()", (ix.ToUInt64()))
(ldesc);
172 MATCH(nx, ix.ToInt64())testing::Match("flang/unittests/Evaluate/real.cpp", 172, (nx)
, "ix.ToInt64()", (ix.ToInt64()))
(ldesc);
173 vr = R::FromInteger(ix);
174 TEST(vr.value.IsNegative())testing::Test("flang/unittests/Evaluate/real.cpp", 174, "vr.value.IsNegative()"
, (vr.value.IsNegative()))
(ldesc);
175 TEST(!vr.value.IsNotANumber())testing::Test("flang/unittests/Evaluate/real.cpp", 175, "!vr.value.IsNotANumber()"
, (!vr.value.IsNotANumber()))
(ldesc);
176 TEST(!vr.value.IsZero())testing::Test("flang/unittests/Evaluate/real.cpp", 176, "!vr.value.IsZero()"
, (!vr.value.IsZero()))
(ldesc);
177 ivf = vr.value.template ToInteger<Integer8>();
178 if (j > (maxExponent / 2)) {
179 TEST(vr.flags.test(RealFlag::Overflow))testing::Test("flang/unittests/Evaluate/real.cpp", 179, "vr.flags.test(RealFlag::Overflow)"
, (vr.flags.test(RealFlag::Overflow)))
(ldesc);
180 TEST(vr.value.IsInfinite())testing::Test("flang/unittests/Evaluate/real.cpp", 180, "vr.value.IsInfinite()"
, (vr.value.IsInfinite()))
(ldesc);
181 TEST(ivf.flags.test(RealFlag::Overflow))testing::Test("flang/unittests/Evaluate/real.cpp", 181, "ivf.flags.test(RealFlag::Overflow)"
, (ivf.flags.test(RealFlag::Overflow)))
(ldesc);
182 MATCH(0x8000000000000000, ivf.value.ToUInt64())testing::Match("flang/unittests/Evaluate/real.cpp", 182, (0x8000000000000000
), "ivf.value.ToUInt64()", (ivf.value.ToUInt64()))
(ldesc);
183 } else {
184 TEST(vr.flags.empty())testing::Test("flang/unittests/Evaluate/real.cpp", 184, "vr.flags.empty()"
, (vr.flags.empty()))
(ldesc);
185 TEST(!vr.value.IsInfinite())testing::Test("flang/unittests/Evaluate/real.cpp", 185, "!vr.value.IsInfinite()"
, (!vr.value.IsInfinite()))
(ldesc);
186 TEST(ivf.flags.empty())testing::Test("flang/unittests/Evaluate/real.cpp", 186, "ivf.flags.empty()"
, (ivf.flags.empty()))
(ldesc);
187 MATCH(x, ivf.value.ToUInt64())testing::Match("flang/unittests/Evaluate/real.cpp", 187, (x),
"ivf.value.ToUInt64()", (ivf.value.ToUInt64()))
(ldesc);
188 MATCH(nx, ivf.value.ToInt64())testing::Match("flang/unittests/Evaluate/real.cpp", 188, (nx)
, "ivf.value.ToInt64()", (ivf.value.ToInt64()))
(ldesc);
189 }
190 TEST(vr.value.ToWholeNumber().value.Compare(vr.value) == Relation::Equal)testing::Test("flang/unittests/Evaluate/real.cpp", 190, "vr.value.ToWholeNumber().value.Compare(vr.value) == Relation::Equal"
, (vr.value.ToWholeNumber().value.Compare(vr.value) == Relation
::Equal))
191 (ldesc);
192 }
193}
194
195// Takes an integer and distributes its bits across a floating
196// point value. The LSB is used to complement the result.
197std::uint32_t MakeReal(std::uint32_t n) {
198 int shifts[] = {-1, 31, 23, 30, 22, 0, 24, 29, 25, 28, 26, 1, 16, 21, 2, -1};
199 std::uint32_t x{0};
200 for (int j{1}; shifts[j] >= 0; ++j) {
201 x |= ((n >> j) & 1) << shifts[j];
202 }
203 x ^= -(n & 1);
204 return x;
205}
206
207std::uint64_t MakeReal(std::uint64_t n) {
208 int shifts[] = {
209 -1, 63, 52, 62, 51, 0, 53, 61, 54, 60, 55, 59, 1, 16, 50, 2, -1};
210 std::uint64_t x{0};
211 for (int j{1}; shifts[j] >= 0; ++j) {
212 x |= ((n >> j) & 1) << shifts[j];
213 }
214 x ^= -(n & 1);
215 return x;
216}
217
218inline bool IsNaN(std::uint32_t x) {
219 return (x & 0x7f800000) == 0x7f800000 && (x & 0x007fffff) != 0;
220}
221
222inline bool IsNaN(std::uint64_t x) {
223 return (x & 0x7ff0000000000000) == 0x7ff0000000000000 &&
224 (x & 0x000fffffffffffff) != 0;
225}
226
227inline bool IsInfinite(std::uint32_t x) {
228 return (x & 0x7fffffff) == 0x7f800000;
229}
230
231inline bool IsInfinite(std::uint64_t x) {
232 return (x & 0x7fffffffffffffff) == 0x7ff0000000000000;
233}
234
235inline bool IsNegative(std::uint32_t x) { return (x & 0x80000000) != 0; }
236
237inline bool IsNegative(std::uint64_t x) {
238 return (x & 0x8000000000000000) != 0;
239}
240
241inline std::uint32_t NormalizeNaN(std::uint32_t x) {
242 if (IsNaN(x)) {
243 x = 0x7fe00000;
244 }
245 return x;
246}
247
248inline std::uint64_t NormalizeNaN(std::uint64_t x) {
249 if (IsNaN(x)) {
250 x = 0x7ffc000000000000;
251 }
252 return x;
253}
254
255enum FlagBits {
256 Overflow = 1,
257 DivideByZero = 2,
258 InvalidArgument = 4,
259 Underflow = 8,
260 Inexact = 16,
261};
262
263#ifdef __clang__1
264// clang support for fenv.h is broken, so tests of flag settings
265// are disabled.
266inline std::uint32_t FlagsToBits(const RealFlags &) { return 0; }
267#else
268inline std::uint32_t FlagsToBits(const RealFlags &flags) {
269 std::uint32_t bits{0};
270 if (flags.test(RealFlag::Overflow)) {
271 bits |= Overflow;
272 }
273 if (flags.test(RealFlag::DivideByZero)) {
274 bits |= DivideByZero;
275 }
276 if (flags.test(RealFlag::InvalidArgument)) {
277 bits |= InvalidArgument;
278 }
279 if (flags.test(RealFlag::Underflow)) {
280 bits |= Underflow;
281 }
282 if (flags.test(RealFlag::Inexact)) {
283 bits |= Inexact;
284 }
285 return bits;
286}
287#endif // __clang__
288
289template <typename UINT = std::uint32_t, typename FLT = float, typename REAL>
290void inttest(std::int64_t x, int pass, Rounding rounding) {
291 union {
292 UINT ui;
293 FLT f;
294 } u;
295 ScopedHostFloatingPointEnvironment fpenv;
296 Integer8 ix{x};
297 ValueWithRealFlags<REAL> real;
298 real = real.value.FromInteger(ix, rounding);
299#ifndef __clang__1 // broken and also slow
300 fpenv.ClearFlags();
301#endif
302 FLT fcheck = x; // TODO unsigned too
303 auto actualFlags{FlagsToBits(fpenv.CurrentFlags())};
304 u.f = fcheck;
305 UINT rcheck{NormalizeNaN(u.ui)};
306 UINT check = real.value.RawBits().ToUInt64();
307 MATCH(rcheck, check)testing::Match("flang/unittests/Evaluate/real.cpp", 307, (rcheck
), "check", (check))
("%d 0x%llx", pass, x);
308 MATCH(actualFlags, FlagsToBits(real.flags))testing::Match("flang/unittests/Evaluate/real.cpp", 308, (actualFlags
), "FlagsToBits(real.flags)", (FlagsToBits(real.flags)))
("%d 0x%llx", pass, x);
309}
310
311template <typename FLT = float> FLT ToIntPower(FLT x, int power) {
312 if (power == 0) {
313 return x / x;
314 }
315 bool negative{power < 0};
316 if (negative) {
317 power = -power;
318 }
319 FLT result{1};
320 while (power > 0) {
321 if (power & 1) {
322 result *= x;
323 }
324 x *= x;
325 power >>= 1;
326 }
327 if (negative) {
328 result = 1.0 / result;
329 }
330 return result;
331}
332
333template <typename FLT, int decimalDigits>
334FLT TimesIntPowerOfTen(FLT x, int power) {
335 if (power > decimalDigits || power < -decimalDigits) {
336 auto maxExactPowerOfTen{
337 TimesIntPowerOfTen<FLT, decimalDigits>(1, decimalDigits)};
338 auto big{ToIntPower<FLT>(maxExactPowerOfTen, power / decimalDigits)};
339 auto small{
340 TimesIntPowerOfTen<FLT, decimalDigits>(1, power % decimalDigits)};
341 return (x * big) * small;
342 }
343 return x * ToIntPower<FLT>(10.0, power);
344}
345
346template <typename UINT = std::uint32_t, typename FLT = float,
347 typename REAL = Real4>
348void subsetTests(int pass, Rounding rounding, std::uint32_t opds) {
349 for (int j{0}; j < 63; ++j) {
350 std::int64_t x{1};
351 x <<= j;
352 inttest<UINT, FLT, REAL>(x, pass, rounding);
353 inttest<UINT, FLT, REAL>(-x, pass, rounding);
354 }
355 inttest<UINT, FLT, REAL>(0, pass, rounding);
356 inttest<UINT, FLT, REAL>(
357 static_cast<std::int64_t>(0x8000000000000000), pass, rounding);
358
359 union {
360 UINT ui;
361 FLT f;
362 } u;
363 ScopedHostFloatingPointEnvironment fpenv;
364
365 for (UINT j{0}; j < opds; ++j) {
366
367 UINT rj{MakeReal(j)};
368 u.ui = rj;
369 FLT fj{u.f};
370 REAL x{typename REAL::Word{std::uint64_t{rj}}};
371
372 // unary operations
373 {
374 ValueWithRealFlags<REAL> aint{x.ToWholeNumber()};
375#ifndef __clang__1 // broken and also slow
376 fpenv.ClearFlags();
377#endif
378 FLT fcheck{std::trunc(fj)};
379 auto actualFlags{FlagsToBits(fpenv.CurrentFlags())};
380 actualFlags &= ~Inexact; // x86 std::trunc can set Inexact; AINT ain't
381 u.f = fcheck;
382#ifndef __clang__1
383 if (IsNaN(u.ui)) {
384 actualFlags |= InvalidArgument; // x86 std::trunc(NaN) workaround
385 }
386#endif
387 UINT rcheck{NormalizeNaN(u.ui)};
388 UINT check = aint.value.RawBits().ToUInt64();
389 MATCH(rcheck, check)testing::Match("flang/unittests/Evaluate/real.cpp", 389, (rcheck
), "check", (check))
390 ("%d AINT(0x%jx)", pass, static_cast<std::intmax_t>(rj));
391 MATCH(actualFlags, FlagsToBits(aint.flags))testing::Match("flang/unittests/Evaluate/real.cpp", 391, (actualFlags
), "FlagsToBits(aint.flags)", (FlagsToBits(aint.flags)))
392 ("%d AINT(0x%jx)", pass, static_cast<std::intmax_t>(rj));
393 }
394
395 {
396 ValueWithRealFlags<REAL> root{x.SQRT(rounding)};
397#ifndef __clang__1 // broken and also slow
398 fpenv.ClearFlags();
399#endif
400 FLT fcheck{std::sqrt(fj)};
401 auto actualFlags{FlagsToBits(fpenv.CurrentFlags())};
402 u.f = fcheck;
403 UINT rcheck{NormalizeNaN(u.ui)};
404 UINT check = root.value.RawBits().ToUInt64();
405 MATCH(rcheck, check)testing::Match("flang/unittests/Evaluate/real.cpp", 405, (rcheck
), "check", (check))
406 ("%d SQRT(0x%jx)", pass, static_cast<std::intmax_t>(rj));
407 MATCH(actualFlags, FlagsToBits(root.flags))testing::Match("flang/unittests/Evaluate/real.cpp", 407, (actualFlags
), "FlagsToBits(root.flags)", (FlagsToBits(root.flags)))
408 ("%d SQRT(0x%jx)", pass, static_cast<std::intmax_t>(rj));
409 }
410
411 {
412 MATCH(IsNaN(rj), x.IsNotANumber())testing::Match("flang/unittests/Evaluate/real.cpp", 412, (IsNaN
(rj)), "x.IsNotANumber()", (x.IsNotANumber()))
413 ("%d IsNaN(0x%jx)", pass, static_cast<std::intmax_t>(rj));
414 MATCH(IsInfinite(rj), x.IsInfinite())testing::Match("flang/unittests/Evaluate/real.cpp", 414, (IsInfinite
(rj)), "x.IsInfinite()", (x.IsInfinite()))
415 ("%d IsInfinite(0x%jx)", pass, static_cast<std::intmax_t>(rj));
416
417 static constexpr int kind{REAL::bits / 8};
418 std::string ssBuf, cssBuf;
419 llvm::raw_string_ostream ss{ssBuf};
420 llvm::raw_string_ostream css{cssBuf};
421 x.AsFortran(ss, kind, false /*exact*/);
422 std::string s{ss.str()};
423 if (IsNaN(rj)) {
424 css << "(0._" << kind << "/0.)";
425 MATCH(css.str(), s)testing::Match("flang/unittests/Evaluate/real.cpp", 425, (css
.str()), "s", (s))
426 ("%d invalid(0x%jx)", pass, static_cast<std::intmax_t>(rj));
427 } else if (IsInfinite(rj)) {
428 css << '(';
429 if (IsNegative(rj)) {
430 css << '-';
431 }
432 css << "1._" << kind << "/0.)";
433 MATCH(css.str(), s)testing::Match("flang/unittests/Evaluate/real.cpp", 433, (css
.str()), "s", (s))
434 ("%d overflow(0x%jx)", pass, static_cast<std::intmax_t>(rj));
435 } else {
436 const char *p = s.data();
437 if (*p == '(') {
438 ++p;
439 }
440 auto readBack{REAL::Read(p, rounding)};
441 MATCH(rj, readBack.value.RawBits().ToUInt64())testing::Match("flang/unittests/Evaluate/real.cpp", 441, (rj)
, "readBack.value.RawBits().ToUInt64()", (readBack.value.RawBits
().ToUInt64()))
442 ("%d Read(AsFortran()) 0x%jx %s %g", pass,
443 static_cast<std::intmax_t>(rj), s.data(), static_cast<double>(fj));
444 MATCH('_', *p)testing::Match("flang/unittests/Evaluate/real.cpp", 444, ('_'
), "*p", (*p))
445 ("%d Read(AsFortran()) 0x%jx %s %d", pass,
446 static_cast<std::intmax_t>(rj), s.data(),
447 static_cast<int>(p - s.data()));
448 }
449 }
450
451 // dyadic operations
452 for (UINT k{0}; k < opds; ++k) {
453 UINT rk{MakeReal(k)};
454 u.ui = rk;
455 FLT fk{u.f};
456 REAL y{typename REAL::Word{std::uint64_t{rk}}};
457 {
458 ValueWithRealFlags<REAL> sum{x.Add(y, rounding)};
459#ifndef __clang__1 // broken and also slow
460 fpenv.ClearFlags();
461#endif
462 FLT fcheck{fj + fk};
463 auto actualFlags{FlagsToBits(fpenv.CurrentFlags())};
464 u.f = fcheck;
465 UINT rcheck{NormalizeNaN(u.ui)};
466 UINT check = sum.value.RawBits().ToUInt64();
467 MATCH(rcheck, check)testing::Match("flang/unittests/Evaluate/real.cpp", 467, (rcheck
), "check", (check))
468 ("%d 0x%jx + 0x%jx", pass, static_cast<std::intmax_t>(rj),
469 static_cast<std::intmax_t>(rk));
470 MATCH(actualFlags, FlagsToBits(sum.flags))testing::Match("flang/unittests/Evaluate/real.cpp", 470, (actualFlags
), "FlagsToBits(sum.flags)", (FlagsToBits(sum.flags)))
471 ("%d 0x%jx + 0x%jx", pass, static_cast<std::intmax_t>(rj),
472 static_cast<std::intmax_t>(rk));
473 }
474 {
475 ValueWithRealFlags<REAL> diff{x.Subtract(y, rounding)};
476#ifndef __clang__1 // broken and also slow
477 fpenv.ClearFlags();
478#endif
479 FLT fcheck{fj - fk};
480 auto actualFlags{FlagsToBits(fpenv.CurrentFlags())};
481 u.f = fcheck;
482 UINT rcheck{NormalizeNaN(u.ui)};
483 UINT check = diff.value.RawBits().ToUInt64();
484 MATCH(rcheck, check)testing::Match("flang/unittests/Evaluate/real.cpp", 484, (rcheck
), "check", (check))
485 ("%d 0x%jx - 0x%jx", pass, static_cast<std::intmax_t>(rj),
486 static_cast<std::intmax_t>(rk));
487 MATCH(actualFlags, FlagsToBits(diff.flags))testing::Match("flang/unittests/Evaluate/real.cpp", 487, (actualFlags
), "FlagsToBits(diff.flags)", (FlagsToBits(diff.flags)))
488 ("%d 0x%jx - 0x%jx", pass, static_cast<std::intmax_t>(rj),
489 static_cast<std::intmax_t>(rk));
490 }
491 {
492 ValueWithRealFlags<REAL> prod{x.Multiply(y, rounding)};
493#ifndef __clang__1 // broken and also slow
494 fpenv.ClearFlags();
495#endif
496 FLT fcheck{fj * fk};
497 auto actualFlags{FlagsToBits(fpenv.CurrentFlags())};
498 u.f = fcheck;
499 UINT rcheck{NormalizeNaN(u.ui)};
500 UINT check = prod.value.RawBits().ToUInt64();
501 MATCH(rcheck, check)testing::Match("flang/unittests/Evaluate/real.cpp", 501, (rcheck
), "check", (check))
502 ("%d 0x%jx * 0x%jx", pass, static_cast<std::intmax_t>(rj),
503 static_cast<std::intmax_t>(rk));
504 MATCH(actualFlags, FlagsToBits(prod.flags))testing::Match("flang/unittests/Evaluate/real.cpp", 504, (actualFlags
), "FlagsToBits(prod.flags)", (FlagsToBits(prod.flags)))
505 ("%d 0x%jx * 0x%jx", pass, static_cast<std::intmax_t>(rj),
506 static_cast<std::intmax_t>(rk));
507 }
508 {
509 ValueWithRealFlags<REAL> quot{x.Divide(y, rounding)};
510#ifndef __clang__1 // broken and also slow
511 fpenv.ClearFlags();
512#endif
513 FLT fcheck{fj / fk};
514 auto actualFlags{FlagsToBits(fpenv.CurrentFlags())};
515 u.f = fcheck;
516 UINT rcheck{NormalizeNaN(u.ui)};
517 UINT check = quot.value.RawBits().ToUInt64();
518 MATCH(rcheck, check)testing::Match("flang/unittests/Evaluate/real.cpp", 518, (rcheck
), "check", (check))
519 ("%d 0x%jx / 0x%jx", pass, static_cast<std::intmax_t>(rj),
520 static_cast<std::intmax_t>(rk));
521 MATCH(actualFlags, FlagsToBits(quot.flags))testing::Match("flang/unittests/Evaluate/real.cpp", 521, (actualFlags
), "FlagsToBits(quot.flags)", (FlagsToBits(quot.flags)))
522 ("%d 0x%jx / 0x%jx", pass, static_cast<std::intmax_t>(rj),
523 static_cast<std::intmax_t>(rk));
524 }
525 }
526 }
527}
528
529void roundTest(int rm, Rounding rounding, std::uint32_t opds) {
530 basicTests<Real2>(rm, rounding);
531 basicTests<Real3>(rm, rounding);
532 basicTests<Real4>(rm, rounding);
533 basicTests<Real8>(rm, rounding);
534 basicTests<Real10>(rm, rounding);
535 basicTests<Real16>(rm, rounding);
536 ScopedHostFloatingPointEnvironment::SetRounding(rounding);
537 subsetTests<std::uint32_t, float, Real4>(rm, rounding, opds);
538 subsetTests<std::uint64_t, double, Real8>(rm, rounding, opds);
539}
540
541int main() {
542 dumpTest();
543 std::uint32_t opds{512}; // for quick testing by default
544 if (const char *p{std::getenv("REAL_TEST_OPERANDS")}) {
545 // Use 8192 or 16384 for more exhaustive testing.
546 opds = std::atol(p);
547 }
548 roundTest(0, Rounding{RoundingMode::TiesToEven}, opds);
549 roundTest(1, Rounding{RoundingMode::ToZero}, opds);
550 roundTest(2, Rounding{RoundingMode::Up}, opds);
551 roundTest(3, Rounding{RoundingMode::Down}, opds);
552 // TODO: how to test Rounding::TiesAwayFromZero on x86?
553 return testing::Complete();
554}

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

1//===-- include/flang/Evaluate/real.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_REAL_H_
10#define FORTRAN_EVALUATE_REAL_H_
11
12#include "formatting.h"
13#include "integer.h"
14#include "rounding-bits.h"
15#include "flang/Common/real.h"
16#include "flang/Evaluate/target.h"
17#include <cinttypes>
18#include <limits>
19#include <string>
20
21// Some environments, viz. clang on Darwin, allow the macro HUGE
22// to leak out of <math.h> even when it is never directly included.
23#undef HUGE
24
25namespace llvm {
26class raw_ostream;
27}
28namespace Fortran::evaluate::value {
29
30// LOG10(2.)*1E12
31static constexpr std::int64_t ScaledLogBaseTenOfTwo{301029995664};
32
33// Models IEEE binary floating-point numbers (IEEE 754-2008,
34// ISO/IEC/IEEE 60559.2011). The first argument to this
35// class template must be (or look like) an instance of Integer<>;
36// the second specifies the number of effective bits (binary precision)
37// in the fraction.
38template <typename WORD, int PREC>
39class Real : public common::RealDetails<PREC> {
40public:
41 using Word = WORD;
42 static constexpr int binaryPrecision{PREC};
43 using Details = common::RealDetails<PREC>;
44 using Details::exponentBias;
45 using Details::exponentBits;
46 using Details::isImplicitMSB;
47 using Details::maxExponent;
48 using Details::significandBits;
49
50 static constexpr int bits{Word::bits};
51 static_assert(bits >= Details::bits);
52 using Fraction = Integer<binaryPrecision>; // all bits made explicit
53
54 template <typename W, int P> friend class Real;
55
56 constexpr Real() {} // +0.0
57 constexpr Real(const Real &) = default;
58 constexpr Real(Real &&) = default;
59 constexpr Real(const Word &bits) : word_{bits} {}
60 constexpr Real &operator=(const Real &) = default;
61 constexpr Real &operator=(Real &&) = default;
62
63 constexpr bool operator==(const Real &that) const {
64 return word_ == that.word_;
65 }
66
67 constexpr bool IsSignBitSet() const { return word_.BTEST(bits - 1); }
68 constexpr bool IsNegative() const {
69 return !IsNotANumber() && IsSignBitSet();
70 }
71 constexpr bool IsNotANumber() const {
72 return Exponent() == maxExponent && !GetSignificand().IsZero();
73 }
74 constexpr bool IsQuietNaN() const {
75 return Exponent() == maxExponent &&
76 GetSignificand().BTEST(significandBits - 1);
77 }
78 constexpr bool IsSignalingNaN() const {
79 return IsNotANumber() && !GetSignificand().BTEST(significandBits - 1);
80 }
81 constexpr bool IsInfinite() const {
82 return Exponent() == maxExponent && GetSignificand().IsZero();
83 }
84 constexpr bool IsFinite() const { return Exponent() != maxExponent; }
85 constexpr bool IsZero() const {
86 return Exponent() == 0 && GetSignificand().IsZero();
87 }
88 constexpr bool IsSubnormal() const {
89 return Exponent() == 0 && !GetSignificand().IsZero();
90 }
91 constexpr bool IsNormal() const {
92 return !(IsInfinite() || IsNotANumber() || IsSubnormal());
93 }
94
95 constexpr Real ABS() const { // non-arithmetic, no flags returned
96 return {word_.IBCLR(bits - 1)};
97 }
98 constexpr Real SetSign(bool toNegative) const { // non-arithmetic
99 if (toNegative) {
100 return {word_.IBSET(bits - 1)};
101 } else {
102 return ABS();
103 }
104 }
105 constexpr Real SIGN(const Real &x) const { return SetSign(x.IsSignBitSet()); }
106
107 constexpr Real Negate() const { return {word_.IEOR(word_.MASKL(1))}; }
108
109 Relation Compare(const Real &) const;
110 ValueWithRealFlags<Real> Add(const Real &,
111 Rounding rounding = TargetCharacteristics::defaultRounding) const;
112 ValueWithRealFlags<Real> Subtract(const Real &y,
113 Rounding rounding = TargetCharacteristics::defaultRounding) const {
114 return Add(y.Negate(), rounding);
115 }
116 ValueWithRealFlags<Real> Multiply(const Real &,
117 Rounding rounding = TargetCharacteristics::defaultRounding) const;
118 ValueWithRealFlags<Real> Divide(const Real &,
119 Rounding rounding = TargetCharacteristics::defaultRounding) const;
120
121 ValueWithRealFlags<Real> SQRT(
122 Rounding rounding = TargetCharacteristics::defaultRounding) const;
123 // NEAREST(), IEEE_NEXT_AFTER(), IEEE_NEXT_UP(), and IEEE_NEXT_DOWN()
124 ValueWithRealFlags<Real> NEAREST(bool upward) const;
125 // HYPOT(x,y)=SQRT(x**2 + y**2) computed so as to avoid spurious
126 // intermediate overflows.
127 ValueWithRealFlags<Real> HYPOT(const Real &,
128 Rounding rounding = TargetCharacteristics::defaultRounding) const;
129 // DIM(X,Y) = MAX(X-Y, 0)
130 ValueWithRealFlags<Real> DIM(const Real &,
131 Rounding rounding = TargetCharacteristics::defaultRounding) const;
132 // MOD(x,y) = x - AINT(x/y)*y
133 // MODULO(x,y) = x - FLOOR(x/y)*y
134 ValueWithRealFlags<Real> MOD(const Real &,
135 Rounding rounding = TargetCharacteristics::defaultRounding) const;
136 ValueWithRealFlags<Real> MODULO(const Real &,
137 Rounding rounding = TargetCharacteristics::defaultRounding) const;
138
139 template <typename INT> constexpr INT EXPONENT() const {
140 if (Exponent() == maxExponent) {
141 return INT::HUGE();
142 } else if (IsZero()) {
143 return {0};
144 } else {
145 return {UnbiasedExponent() + 1};
146 }
147 }
148
149 static constexpr Real EPSILON() {
150 Real epsilon;
151 epsilon.Normalize(
152 false, exponentBias + 1 - binaryPrecision, Fraction::MASKL(1));
153 return epsilon;
154 }
155 static constexpr Real HUGE() {
156 Real huge;
157 huge.Normalize(false, maxExponent - 1, Fraction::MASKR(binaryPrecision));
158 return huge;
159 }
160 static constexpr Real TINY() {
161 Real tiny;
162 tiny.Normalize(false, 1, Fraction::MASKL(1)); // minimum *normal* number
163 return tiny;
164 }
165
166 static constexpr int DIGITS{binaryPrecision};
167 static constexpr int PRECISION{Details::decimalPrecision};
168 static constexpr int RANGE{Details::decimalRange};
169 static constexpr int MAXEXPONENT{maxExponent - exponentBias};
170 static constexpr int MINEXPONENT{2 - exponentBias};
171 Real RRSPACING() const;
172 Real SPACING() const;
173 Real SET_EXPONENT(std::int64_t) const;
174 Real FRACTION() const;
175
176 // SCALE(); also known as IEEE_SCALB and (in IEEE-754 '08) ScaleB.
177 template <typename INT>
178 ValueWithRealFlags<Real> SCALE(const INT &by,
179 Rounding rounding = TargetCharacteristics::defaultRounding) const {
180 // Normalize a fraction with just its LSB set and then multiply.
181 // (Set the LSB, not the MSB, in case the scale factor needs to
182 // be subnormal.)
183 auto adjust{exponentBias + binaryPrecision - 1};
184 auto expo{adjust + by.ToInt64()};
185 Real twoPow;
186 RealFlags flags;
187 int rMask{1};
188 if (IsZero()) {
189 expo = exponentBias; // ignore by, don't overflow
190 } else if (by > INT{maxExponent}) {
191 expo = maxExponent + binaryPrecision - 1;
192 } else if (by < INT{-adjust}) { // underflow
193 expo = 0;
194 rMask = 0;
195 flags.set(RealFlag::Underflow);
196 }
197 flags |=
198 twoPow.Normalize(false, static_cast<int>(expo), Fraction::MASKR(rMask));
199 ValueWithRealFlags<Real> result{Multiply(twoPow, rounding)};
200 result.flags |= flags;
201 return result;
202 }
203
204 constexpr Real FlushSubnormalToZero() const {
205 if (IsSubnormal()) {
206 return Real{};
207 }
208 return *this;
209 }
210
211 // TODO: Configurable NotANumber representations
212 static constexpr Real NotANumber() {
213 return {Word{maxExponent}
214 .SHIFTL(significandBits)
215 .IBSET(significandBits - 1)
216 .IBSET(significandBits - 2)};
217 }
218
219 static constexpr Real PositiveZero() { return Real{}; }
220
221 static constexpr Real NegativeZero() { return {Word{}.MASKL(1)}; }
222
223 static constexpr Real Infinity(bool negative) {
224 Word infinity{maxExponent};
225 infinity = infinity.SHIFTL(significandBits);
226 if (negative) {
227 infinity = infinity.IBSET(infinity.bits - 1);
228 }
229 return {infinity};
230 }
231
232 template <typename INT>
233 static ValueWithRealFlags<Real> FromInteger(const INT &n,
234 Rounding rounding = TargetCharacteristics::defaultRounding) {
235 bool isNegative{n.IsNegative()};
236 INT absN{n};
237 if (isNegative) {
238 absN = n.Negate().value; // overflow is safe to ignore
239 }
240 int leadz{absN.LEADZ()};
241 if (leadz >= absN.bits) {
242 return {}; // all bits zero -> +0.0
243 }
244 ValueWithRealFlags<Real> result;
245 int exponent{exponentBias + absN.bits - leadz - 1};
246 int bitsNeeded{absN.bits - (leadz + isImplicitMSB)};
247 int bitsLost{bitsNeeded - significandBits};
248 if (bitsLost <= 0) {
249 Fraction fraction{Fraction::ConvertUnsigned(absN).value};
250 result.flags |= result.value.Normalize(
251 isNegative, exponent, fraction.SHIFTL(-bitsLost));
252 } else {
253 Fraction fraction{Fraction::ConvertUnsigned(absN.SHIFTR(bitsLost)).value};
254 result.flags |= result.value.Normalize(isNegative, exponent, fraction);
255 RoundingBits roundingBits{absN, bitsLost};
256 result.flags |= result.value.Round(rounding, roundingBits);
257 }
258 return result;
259 }
260
261 // Conversion to integer in the same real format (AINT(), ANINT())
262 ValueWithRealFlags<Real> ToWholeNumber(
263 common::RoundingMode = common::RoundingMode::ToZero) const;
264
265 // Conversion to an integer (INT(), NINT(), FLOOR(), CEILING())
266 template <typename INT>
267 constexpr ValueWithRealFlags<INT> ToInteger(
268 common::RoundingMode mode = common::RoundingMode::ToZero) const {
269 ValueWithRealFlags<INT> result;
25
'result' initialized here
270 if (IsNotANumber()) {
26
Taking false branch
271 result.flags.set(RealFlag::InvalidArgument);
272 result.value = result.value.HUGE();
273 return result;
274 }
275 ValueWithRealFlags<Real> intPart{ToWholeNumber(mode)};
276 result.flags |= intPart.flags;
277 int exponent{intPart.value.Exponent()};
278 // shift positive -> left shift, negative -> right shift
279 int shift{exponent - exponentBias - binaryPrecision + 1};
280 // Apply any right shift before moving to the result type
281 auto rshifted{intPart.value.GetFraction().SHIFTR(-shift)};
282 auto converted{result.value.ConvertUnsigned(rshifted)};
283 if (converted.overflow
26.1
Field 'overflow' is false
26.1
Field 'overflow' is false
26.1
Field 'overflow' is false
) {
27
Taking false branch
284 result.flags.set(RealFlag::Overflow);
285 }
286 result.value = converted.value.SHIFTL(shift);
287 if (converted.value.CompareUnsigned(result.value.SHIFTR(shift)) !=
28
Taking true branch
288 Ordering::Equal) {
289 result.flags.set(RealFlag::Overflow);
290 }
291 if (IsSignBitSet()) {
29
Taking true branch
292 result.value = result.value.Negate().value;
30
Assigning value
293 }
294 if (!result.value.IsZero()) {
31
Taking true branch
295 if (IsSignBitSet() != result.value.IsNegative()) {
32
Taking false branch
296 result.flags.set(RealFlag::Overflow);
297 }
298 }
299 if (result.flags.test(RealFlag::Overflow)) {
33
Taking false branch
300 result.value =
301 IsSignBitSet() ? result.value.MASKL(1) : result.value.HUGE();
302 }
303 return result;
34
Assigning value
304 }
305
306 template <typename A>
307 static ValueWithRealFlags<Real> Convert(
308 const A &x, Rounding rounding = TargetCharacteristics::defaultRounding) {
309 ValueWithRealFlags<Real> result;
310 if (x.IsNotANumber()) {
311 result.flags.set(RealFlag::InvalidArgument);
312 result.value = NotANumber();
313 return result;
314 }
315 bool isNegative{x.IsNegative()};
316 A absX{x};
317 if (isNegative) {
318 absX = x.Negate();
319 }
320 int exponent{exponentBias + x.UnbiasedExponent()};
321 int bitsLost{A::binaryPrecision - binaryPrecision};
322 if (exponent < 1) {
323 bitsLost += 1 - exponent;
324 exponent = 1;
325 }
326 typename A::Fraction xFraction{x.GetFraction()};
327 if (bitsLost <= 0) {
328 Fraction fraction{
329 Fraction::ConvertUnsigned(xFraction).value.SHIFTL(-bitsLost)};
330 result.flags |= result.value.Normalize(isNegative, exponent, fraction);
331 } else {
332 Fraction fraction{
333 Fraction::ConvertUnsigned(xFraction.SHIFTR(bitsLost)).value};
334 result.flags |= result.value.Normalize(isNegative, exponent, fraction);
335 RoundingBits roundingBits{xFraction, bitsLost};
336 result.flags |= result.value.Round(rounding, roundingBits);
337 }
338 return result;
339 }
340
341 constexpr Word RawBits() const { return word_; }
342
343 // Extracts "raw" biased exponent field.
344 constexpr int Exponent() const {
345 return word_.IBITS(significandBits, exponentBits).ToUInt64();
346 }
347
348 // Extracts the fraction; any implied bit is made explicit.
349 constexpr Fraction GetFraction() const {
350 Fraction result{Fraction::ConvertUnsigned(word_).value};
351 if constexpr (!isImplicitMSB) {
352 return result;
353 } else {
354 int exponent{Exponent()};
355 if (exponent > 0 && exponent < maxExponent) {
356 return result.IBSET(significandBits);
357 } else {
358 return result.IBCLR(significandBits);
359 }
360 }
361 }
362
363 // Extracts unbiased exponent value.
364 // Corrects the exponent value of a subnormal number.
365 // Note that the result is one less than the EXPONENT intrinsic;
366 // UnbiasedExponent(1.0) is 0, not 1.
367 constexpr int UnbiasedExponent() const {
368 int exponent{Exponent() - exponentBias};
369 if (IsSubnormal()) {
370 ++exponent;
371 }
372 return exponent;
373 }
374
375 static ValueWithRealFlags<Real> Read(const char *&,
376 Rounding rounding = TargetCharacteristics::defaultRounding);
377 std::string DumpHexadecimal() const;
378
379 // Emits a character representation for an equivalent Fortran constant
380 // or parenthesized constant expression that produces this value.
381 llvm::raw_ostream &AsFortran(
382 llvm::raw_ostream &, int kind, bool minimal = false) const;
383
384private:
385 using Significand = Integer<significandBits>; // no implicit bit
386
387 constexpr Significand GetSignificand() const {
388 return Significand::ConvertUnsigned(word_).value;
389 }
390
391 constexpr int CombineExponents(const Real &y, bool forDivide) const {
392 int exponent = Exponent(), yExponent = y.Exponent();
393 // A zero exponent field value has the same weight as 1.
394 exponent += !exponent;
395 yExponent += !yExponent;
396 if (forDivide) {
397 exponent += exponentBias - yExponent;
398 } else {
399 exponent += yExponent - exponentBias + 1;
400 }
401 return exponent;
402 }
403
404 static constexpr bool NextQuotientBit(
405 Fraction &top, bool &msb, const Fraction &divisor) {
406 bool greaterOrEqual{msb || top.CompareUnsigned(divisor) != Ordering::Less};
407 if (greaterOrEqual) {
408 top = top.SubtractSigned(divisor).value;
409 }
410 auto doubled{top.AddUnsigned(top)};
411 top = doubled.value;
412 msb = doubled.carry;
413 return greaterOrEqual;
414 }
415
416 // Normalizes and marshals the fields of a floating-point number in place.
417 // The value is a number, and a zero fraction means a zero value (i.e.,
418 // a maximal exponent and zero fraction doesn't signify infinity, although
419 // this member function will detect overflow and encode infinities).
420 RealFlags Normalize(bool negative, int exponent, const Fraction &fraction,
421 Rounding rounding = TargetCharacteristics::defaultRounding,
422 RoundingBits *roundingBits = nullptr);
423
424 // Rounds a result, if necessary, in place.
425 RealFlags Round(Rounding, const RoundingBits &, bool multiply = false);
426
427 static void NormalizeAndRound(ValueWithRealFlags<Real> &result,
428 bool isNegative, int exponent, const Fraction &, Rounding, RoundingBits,
429 bool multiply = false);
430
431 Word word_{}; // an Integer<>
432};
433
434extern template class Real<Integer<16>, 11>; // IEEE half format
435extern template class Real<Integer<16>, 8>; // the "other" half format
436extern template class Real<Integer<32>, 24>; // IEEE single
437extern template class Real<Integer<64>, 53>; // IEEE double
438extern template class Real<Integer<80>, 64>; // 80387 extended precision
439extern template class Real<Integer<128>, 113>; // IEEE quad
440// N.B. No "double-double" support.
441} // namespace Fortran::evaluate::value
442#endif // FORTRAN_EVALUATE_REAL_H_

/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
39.1
'filled' is < 'maxBits'
39.1
'filled' is < 'maxBits'
39.1
'filled' is < 'maxBits'
< maxBits && j < parts; ++j, filled += partBits) {
39
'j' initialized to 1
40
Loop condition is true. Entering loop body
471 n |= UINT{LEPart(j)} << filled;
41
Passing the value 1 via 1st parameter 'part'
42
Calling 'Integer::LEPart'
45
Returning from 'Integer::LEPart'
46
The result of the left shift is undefined due to shifting '-1' by '32', which is unrepresentable in the unsigned version of the return type 'unsigned long'
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 < maxBits) {
481 n |= -(n >> (bits - 1)) << bits;
482 }
483 return n;
484 }
485
486 constexpr std::uint64_t ToUInt64() const { return ToUInt<std::uint64_t>(); }
38
Calling 'Integer::ToUInt'
487
488 constexpr std::int64_t ToInt64() const {
489 return ToSInt<std::int64_t, std::uint64_t>();
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
42.1
'littleEndian' is true
42.1
'littleEndian' is true
42.1
'littleEndian' is true
) {
43
Taking true branch
1010 return part_[part];
44
Returning value
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_