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