FLANG
integer-value.h
1//===-- include/flang/Evaluate/integer-value.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_VALUE_H_
10#define FORTRAN_EVALUATE_INTEGER_VALUE_H_
11
12#include "flang/Common/uint128.h"
13#include "flang/Evaluate/common.h"
14#include "flang/Evaluate/object-sizes.h"
15#include "llvm/Support/Compiler.h"
16#include "llvm/Support/raw_ostream.h"
17#include <cstddef>
18#include <cstdint>
19#include <type_traits>
20
21// Some environments, viz. glibc 2.17 and *BSD, allow the macro HUGE
22// to leak out of <math.h>.
23#undef HUGE
24
25namespace Fortran::evaluate::value {
27
35class IntegerValue {
36 friend class RealValueImpl;
37
38public:
39 struct ValueWithOverflow;
40 struct ValueWithCarry;
41 struct Product;
43 struct PowerWithErrors;
44
45 IntegerValue();
46#if FLANG_TRIVIALLY_COPYABLE_VALUE_IMPL
47 ~IntegerValue() = default;
48 IntegerValue(const IntegerValue &) = default;
49 IntegerValue(IntegerValue &&) = default;
50 IntegerValue &operator=(const IntegerValue &) = default;
51 IntegerValue &operator=(IntegerValue &&) = default;
52#else
53 ~IntegerValue();
54 IntegerValue(const IntegerValue &);
55 IntegerValue(IntegerValue &&);
56 IntegerValue &operator=(const IntegerValue &);
57 IntegerValue &operator=(IntegerValue &&);
58#endif
59
60 IntegerValue(int kind, const IntegerValue &x) : IntegerValue(x) {
61 CHECK(x.kind() == kind);
62 }
63 IntegerValue(int kind, IntegerValue &&x) : IntegerValue(std::move(x)) {
64 CHECK(x.kind() == kind);
65 }
66
67 // Fortran::common::int128_t/uint128_t are 128-bit values -- either the
68 // host's native __int128/unsigned __int128, or the portable
69 // Fortran::common::Int128<> fallback when there is no native type -- and
70 // are handled by the dedicated branch below rather than by the general
71 // integral case, since some standard libraries don't consider native
72 // __int128 types to satisfy std::is_integral_v, and the portable fallback
73 // is a class type that never does.
74 template <typename INT,
75 typename = std::enable_if_t<common::numeric_limits<INT>::is_integer>>
76 IntegerValue(int kind, INT v) {
77 if constexpr (sizeof(INT) > 8) {
78 static_assert(sizeof(INT) == 16);
79 ConstructFromIntegral(kind, static_cast<common::uint128_t>(v));
80 } else if constexpr (std::is_signed_v<INT>) {
81 ConstructFromIntegral(
82 kind, static_cast<uint64_t>(static_cast<int64_t>(v)), true);
83 } else {
84 ConstructFromIntegral(kind, static_cast<uint64_t>(v), false);
85 }
86 }
87
91 static IntegerValue Zero(int kind);
92
93 void print(llvm::raw_ostream &os) const;
94
95#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
96 LLVM_DUMP_METHOD void dump() const;
97#endif
98
101 bool IsNull() const;
102
104 int kind() const;
105
106 int bits() const { return bits(kind()); }
107 static constexpr int bits(int kind) { return bytesStored(kind) * 8; }
108
110 std::size_t bytesStored() const { return bytesStored(kind()); }
111 static constexpr std::size_t bytesStored(int kind) {
112 switch (kind) {
113 case 3:
114 // REAL(3) is bfloat16; RealValue uses integer as storage, therefore this
115 // case is relevant.
116 return 2;
117 case 10:
118 // Similarly, REAL(10) is x87 extended double precision; RealValue's
119 // storage is an integer of KIND 10, but uses 16 bytes including
120 // alignment.
121 return 16;
122 default:
123 return kind;
124 }
125 }
126
127 bool operator<(const IntegerValue &y) const {
128 return CompareSigned(y) == Ordering::Less;
129 }
130 bool operator<=(const IntegerValue &y) const {
131 return CompareSigned(y) != Ordering::Greater;
132 }
133 bool operator==(const IntegerValue &y) const {
134 return CompareSigned(y) == Ordering::Equal;
135 }
136 bool operator!=(const IntegerValue &y) const {
137 return CompareSigned(y) != Ordering::Equal;
138 }
139 bool operator>=(const IntegerValue &y) const {
140 return CompareSigned(y) != Ordering::Less;
141 }
142 bool operator>(const IntegerValue &y) const {
143 return CompareSigned(y) == Ordering::Greater;
144 }
145
147 static IntegerValue MASKL(int kind, int places);
148
150 static IntegerValue MASKR(int kind, int places);
151
152 static ValueWithOverflow Read(
153 int kind, const char *&pp, int base, bool isSigned);
154
157 int toKind, const IntegerValue &from);
158
160 static ValueWithOverflow ConvertSigned(int toKind, const IntegerValue &from);
161
162 std::string UnsignedDecimal() const;
163
164 std::string SignedDecimal() const;
165
167 std::string Hexadecimal() const;
168
169 static constexpr int DIGITS(int kind) {
170 // don't count the sign bit
171 return bits(kind) - 1;
172 }
173
174 static IntegerValue HUGE(int kind);
175
176 static IntegerValue Least(int kind);
177
178 static int RANGE(int kind);
179
180 static int UnsignedRANGE(int kind);
181
182 bool IsZero() const;
183
184 bool IsNegative() const;
185
186 Ordering CompareToZeroSigned() const;
187
190 int LEADZ() const;
191
193 int POPCNT() const;
194
196 bool POPPAR() const;
197
198 int TRAILZ() const;
199
200 bool BTEST(int pos) const;
201
202 Ordering CompareUnsigned(const IntegerValue &y) const;
203
204 Ordering CompareSigned(const IntegerValue &y) const;
205
206 bool BGE(const IntegerValue &y) const {
207 return CompareUnsigned(y) != Ordering::Less;
208 }
209 bool BGT(const IntegerValue &y) const {
210 return CompareUnsigned(y) == Ordering::Greater;
211 }
212 bool BLE(const IntegerValue &y) const { return !BGT(y); }
213 bool BLT(const IntegerValue &y) const { return !BGE(y); }
214
215 std::uint64_t ToUInt64() const;
216
217 std::int64_t ToInt64() const;
218
219 Fortran::common::uint128_t ToUInt128() const;
220
221 Fortran::common::int128_t ToInt128() const;
222
223 template <typename INT,
224 typename = std::enable_if_t<std::is_signed_v<INT> ||
225 std::is_same_v<INT, Fortran::common::int128_t>>>
226 INT ToSInt() const {
227 if constexpr (std::is_same_v<INT, Fortran::common::int128_t>) {
228 return ToInt128();
229 } else {
230 return ToInt64();
231 }
232 }
233
234 template <typename INT,
235 typename = std::enable_if_t<std::is_unsigned_v<INT> ||
236 std::is_same_v<INT, Fortran::common::uint128_t>>>
237 INT ToUInt() const {
238 if constexpr (std::is_same_v<INT, Fortran::common::uint128_t>) {
239 return ToUInt128();
240 } else {
241 return ToUInt64();
242 }
243 }
244
246 IntegerValue NOT() const;
247
252
253 ValueWithOverflow ABS() const;
254
257 IntegerValue ISHFT(int count) const {
258 return count < 0 ? SHIFTR(-count) : SHIFTL(count);
259 }
260
262 IntegerValue SHIFTL(int count) const;
263
268 IntegerValue ISHFTC(int count, int size) const;
269 IntegerValue ISHFTC(int count) const;
270
272 IntegerValue DSHIFTL(const IntegerValue &fill, int count) const;
273
275 IntegerValue DSHIFTR(const IntegerValue &v2, int count) const;
276
278 IntegerValue SHIFTR(int count) const;
279
282 IntegerValue SHIFTA(int count) const;
283
285 IntegerValue IBCLR(int pos) const;
286
288 IntegerValue IBSET(int pos) const;
289
291 IntegerValue IBITS(int pos, int size) const;
292
293 IntegerValue IAND(const IntegerValue &y) const;
294
295 IntegerValue IOR(const IntegerValue &y) const;
296
297 IntegerValue IEOR(const IntegerValue &y) const;
298
299 IntegerValue MERGE_BITS(
300 const IntegerValue &y, const IntegerValue &mask) const;
301
302 IntegerValue MAX(const IntegerValue &y) const {
303 return CompareSigned(y) == Ordering::Less ? y : *this;
304 }
305
306 IntegerValue MIN(const IntegerValue &y) const {
307 return CompareSigned(y) == Ordering::Less ? *this : y;
308 }
309
310 ValueWithCarry AddUnsigned(const IntegerValue &y, bool carryIn = false) const;
311
312 ValueWithOverflow AddSigned(const IntegerValue &y) const;
313
314 ValueWithOverflow SubtractSigned(const IntegerValue &y) const;
315
317 ValueWithOverflow DIM(const IntegerValue &y) const;
318
319 ValueWithOverflow SIGN(const IntegerValue &sign) const;
320
321 Product MultiplyUnsigned(const IntegerValue &y) const;
322
323 Product MultiplySigned(const IntegerValue &y) const;
324
325 QuotientWithRemainder DivideUnsigned(const IntegerValue &y) const;
326
330 QuotientWithRemainder DivideSigned(const IntegerValue &y) const;
331
334 ValueWithOverflow MODULO(const IntegerValue &y) const;
335
336 PowerWithErrors Power(const IntegerValue &e) const;
337
338 static IntegerValue FromRawBytes(
339 int kind, const void *raw, std::size_t expectedSize);
340 void StoreRawBytes(void *dst, size_t size, bool *changed = nullptr) const;
341
342private:
343 void ConstructFromIntegral(int kind, std::uint64_t n, bool isSigned);
344 void ConstructFromIntegral(int kind, Fortran::common::uint128_t n);
345
346 static IntegerValue FromImpl(const IntegerValueImpl &x);
347 static IntegerValue FromImpl(IntegerValueImpl &&x);
348
349 IntegerValueImpl &impl();
350 const IntegerValueImpl &impl() const;
351
352 alignas(detail::kIntegerObjectAlign)
353 std::byte opaque_[detail::kIntegerObjectSize];
354};
355
357 IntegerValue value;
358 bool overflow{false};
359};
360
362 IntegerValue value;
363 bool carry{false};
364};
365
367 IntegerValue upper, lower;
368 bool SignedMultiplicationOverflowed() const { return overflow; }
369 bool overflow{false};
370};
371
373 IntegerValue quotient, remainder;
374 bool divisionByZero{false}, overflow{false};
375};
376
378 IntegerValue power;
379 bool divisionByZero{false}, overflow{false}, zeroToZero{false};
380};
381
382} // namespace Fortran::evaluate::value
383
384namespace llvm {
386inline raw_ostream &operator<<(
387 raw_ostream &os, const Fortran::evaluate::value::IntegerValue &v) {
388 v.print(os);
389 return os;
390}
391} // namespace llvm
392
393#endif // FORTRAN_EVALUATE_INTEGER_VALUE_H_
Definition integer-value-impl.h:26
Definition integer-value.h:35
static IntegerValue Zero(int kind)
Definition integer-value.cpp:55
static ValueWithOverflow ConvertSigned(int toKind, const IntegerValue &from)
SExt or Trunc.
Definition integer-value.cpp:89
IntegerValue ISHFTC(int count, int size) const
Definition integer-value.cpp:170
IntegerValue SHIFTA(int count) const
Definition integer-value.cpp:190
QuotientWithRemainder DivideSigned(const IntegerValue &y) const
Definition integer-value.cpp:274
ValueWithOverflow DIM(const IntegerValue &y) const
DIM(X,Y)=MAX(X-Y, 0)
Definition integer-value.cpp:241
IntegerValue IBSET(int pos) const
Sets a single bit.
Definition integer-value.cpp:198
int LEADZ() const
Definition integer-value.cpp:121
ValueWithOverflow Negate() const
Definition integer-value.cpp:157
IntegerValue NOT() const
Ones'-complement (i.e., C's ~)
Definition integer-value.cpp:155
bool IsNull() const
Definition integer-value.cpp:59
std::string Hexadecimal() const
Omits a leading "0x".
Definition integer-value.cpp:103
IntegerValue DSHIFTL(const IntegerValue &fill, int count) const
DSHIFTL(I,J) shifts I:J left; the second argument is the right fill.
Definition integer-value.cpp:178
IntegerValue IBCLR(int pos) const
Clears a single bit.
Definition integer-value.cpp:194
static ValueWithOverflow ConvertUnsigned(int toKind, const IntegerValue &from)
ZExt or Trunc.
Definition integer-value.cpp:83
IntegerValue SHIFTL(int count) const
Left shift with zero fill.
Definition integer-value.cpp:166
IntegerValue IBITS(int pos, int size) const
Extracts a field.
Definition integer-value.cpp:202
ValueWithOverflow MODULO(const IntegerValue &y) const
Definition integer-value.cpp:281
static IntegerValue MASKL(int kind, int places)
Left-justified mask (e.g., MASKL(1) has only its sign bit set)
Definition integer-value.cpp:69
IntegerValue DSHIFTR(const IntegerValue &v2, int count) const
DSHIFTR(I,J) shifts I:J right; the first argument is the left fill.
Definition integer-value.cpp:182
IntegerValue SHIFTR(int count) const
Vacated upper bits are filled with zeroes.
Definition integer-value.cpp:186
static IntegerValue MASKR(int kind, int places)
Right-justified mask (e.g., MASKR(1) == 1, MASKR(2) == 3, &c.)
Definition integer-value.cpp:73
bool POPPAR() const
True when POPCNT is odd.
Definition integer-value.cpp:125
IntegerValue ISHFT(int count) const
Definition integer-value.h:257
int POPCNT() const
Count the number of bit positions that are set.
Definition integer-value.cpp:123
std::size_t bytesStored() const
Number of bytes accessed by FromRawBytes/StoreRawBytes.
Definition integer-value.h:110
int kind() const
The kind of the value currently stored.
Definition integer-value.cpp:61