FLANG
real-value-impl.h
1//===-- lib/Evaluate/real-value-impl.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_VALUE_IMPL_H_
10#define FORTRAN_EVALUATE_REAL_VALUE_IMPL_H_
11
12#include "flang/Evaluate/real.h"
13#include "llvm/Support/ErrorHandling.h"
14#include <type_traits>
15#include <utility>
16#include <variant>
17
18// Some environments, viz. glibc 2.17 and *BSD, allow the macro HUGE
19// to leak out of <math.h>.
20#undef HUGE
21
22namespace llvm {
23class raw_ostream;
24}
25
26namespace Fortran::evaluate::value {
27class IntegerValue;
28
29class RealValueImpl {
30public:
31 using R2 = Real<Integer<16>, 11>; // IEEE half
32 using R3 = Real<Integer<16>, 8>; // bfloat16
33 using R4 = Real<Integer<32>, 24>; // IEEE single
34 using R8 = Real<Integer<64>, 53>; // IEEE double
35 using R10 = Real<X87IntegerContainer, 64>; // 80387 extended precision
36 using R16 = Real<Integer<128>, 113>; // IEEE quad
37 using Storage = std::variant<std::monostate, R2, R3, R4, R8, R10, R16>;
38 using Word = IntegerValue;
39
40 // rule-of-five
41 ~RealValueImpl() = default;
42 RealValueImpl(const RealValueImpl &) = default;
43 RealValueImpl(RealValueImpl &&) = default;
44 RealValueImpl &operator=(const RealValueImpl &) = default;
45 RealValueImpl &operator=(RealValueImpl &&) = default;
46
47 RealValueImpl() = default;
48
49 // Interpret w as the raw bit pattern of a value of the given runtime kind.
50 RealValueImpl(int kind, const Word &w);
51
52 RealValueImpl(int kind, double x);
53
54 static RealValueImpl Zero(int kind);
55
56 template <typename T> static RealValueImpl FromWord(const T &r) {
57 RealValueImpl v;
58 v.storage_ = r;
59 return v;
60 }
61
62 template <typename T>
64 const ValueWithRealFlags<T> &x) {
66 r.value = FromWord(x.value);
67 r.flags = x.flags;
68 return r;
69 }
70
71 static RealValueImpl FromRawBytes(
72 int kind, const void *raw, std::size_t expectedSize);
73
74 void print(llvm::raw_ostream &os) const;
75
76#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
77 LLVM_DUMP_METHOD void dump() const;
78#endif
79
80 bool IsNull() const { return storage_.index() == 0; }
81 int kind() const;
82
83 int bits() const;
84
85 std::size_t bytesStored() const { return bytesStored(kind()); }
86 static constexpr std::size_t bytesStored(int kind) {
87 switch (kind) {
88 case 3:
89 return 2;
90 case 10:
91 return 16;
92 default:
93 return kind;
94 }
95 }
96
97 bool IsZero() const;
98
99 // Comparison operators
100 bool operator==(const RealValueImpl &y) const;
101 bool operator!=(const RealValueImpl &y) const { return !(*this == y); }
102
103 // Kind-property inquiries, formerly compile-time constants derived from the
104 // PREC template parameter; now selected by the runtime KIND.
105 static int DIGITS(int kind);
106 static int PRECISION(int kind);
107 static int RANGE(int kind);
108 static int MAXEXPONENT(int kind);
109 static int MINEXPONENT(int kind);
110
111 static RealValueImpl HUGE(int kind);
112 static RealValueImpl EPSILON(int kind);
113 static RealValueImpl TINY(int kind);
114 static RealValueImpl NotANumber(int kind);
115 static RealValueImpl Infinity(int kind, bool negative = false);
116 static RealValueImpl NegativeZero(int kind);
117
118 // Runtime kind / width accessors
119 bool IsNegative() const;
120 bool IsNotANumber() const;
121 bool IsSignalingNaN() const;
122 bool IsInfinite() const;
123 bool IsFinite() const;
124 bool IsNormal() const;
125 int Exponent() const;
126 void StoreRawBytes(void *dst, size_t size, bool *changed) const;
127
128 // The raw bit pattern at the value's runtime width.
129 IntegerValue RawBits() const;
130
131 // Comparisons
132 Relation Compare(const RealValueImpl &y) const;
133
134 // Unary operations
135 RealValueImpl ABS() const;
136 RealValueImpl Negate() const;
137 RealValueImpl SIGN(const RealValueImpl &x) const;
138 RealValueImpl SetSign(bool toNegative) const;
139 RealValueImpl FlushSubnormalToZero() const;
140
141 // Binary arithmetic
142 ValueWithRealFlags<RealValueImpl> Add(const RealValueImpl &y,
143 Rounding rounding = TargetCharacteristics::defaultRounding) const;
144 ValueWithRealFlags<RealValueImpl> Subtract(const RealValueImpl &y,
145 Rounding rounding = TargetCharacteristics::defaultRounding) const;
146 ValueWithRealFlags<RealValueImpl> Multiply(const RealValueImpl &y,
147 Rounding rounding = TargetCharacteristics::defaultRounding) const;
148 ValueWithRealFlags<RealValueImpl> Divide(const RealValueImpl &y,
149 Rounding rounding = TargetCharacteristics::defaultRounding) const;
151 Rounding rounding = TargetCharacteristics::defaultRounding) const;
152 ValueWithRealFlags<RealValueImpl> HYPOT(const RealValueImpl &y,
153 Rounding rounding = TargetCharacteristics::defaultRounding) const;
154 ValueWithRealFlags<RealValueImpl> MOD(const RealValueImpl &y,
155 Rounding rounding = TargetCharacteristics::defaultRounding) const;
156 ValueWithRealFlags<RealValueImpl> MODULO(const RealValueImpl &y,
157 Rounding rounding = TargetCharacteristics::defaultRounding) const;
158 ValueWithRealFlags<RealValueImpl> DIM(const RealValueImpl &y,
159 Rounding rounding = TargetCharacteristics::defaultRounding) const;
160
161 RealValueImpl FRACTION() const;
162 RealValueImpl RRSPACING() const;
163 RealValueImpl SPACING() const;
164 RealValueImpl SET_EXPONENT(std::int64_t e) const;
165
166 ValueWithRealFlags<RealValueImpl> NEAREST(bool upward) const;
168 common::RoundingMode mode = common::RoundingMode::ToZero) const;
169 // Convert this real to an integer of the given bit width.
171 common::RoundingMode mode = common::RoundingMode::ToZero,
172 int toBits = 0) const;
173
175 Rounding rounding = TargetCharacteristics::defaultRounding) const;
176
177 ValueWithRealFlags<RealValueImpl> KahanSummation(const RealValueImpl &y,
178 RealValueImpl &correction,
179 Rounding rounding = TargetCharacteristics::defaultRounding) const;
180
181 IntegerValue EXPONENT() const;
182
183 // Conversion from an integer facade (REAL()).
184 static ValueWithRealFlags<RealValueImpl> FromInteger(int kind,
185 const IntegerValue &n, bool isUnsigned = false,
186 Rounding rounding = TargetCharacteristics::defaultRounding);
187
188 // Conversion between real kinds.
189 static ValueWithRealFlags<RealValueImpl> Convert(int kind,
190 const RealValueImpl &from,
191 Rounding rounding = TargetCharacteristics::defaultRounding);
192
193 static ValueWithRealFlags<RealValueImpl> Read(int kind, const char *&pp,
194 Rounding rounding = TargetCharacteristics::defaultRounding);
195
196 std::string DumpHexadecimal() const;
197 llvm::raw_ostream &AsFortran(
198 llvm::raw_ostream &o, int kind, bool minimal = false) const;
199
200 // Compile-time dispatchers to current/specified kind
201
204 template <typename T> T GetWord() const {
205 // Null means default-initialized of the requested word (== 0.0)
206 if (IsNull()) {
207 // Immutable null constant since we return a reference
208 static const T null;
209 return null;
210 }
211
212 // std::get throws std::bad_variant_access, but we do not want to rely soley
213 // on exceptions here.
214 if (!std::holds_alternative<T>(storage_)) {
215 DIE("value does not store the requested kind");
216 }
217
218 return std::get<T>(storage_);
219 }
220
221 template <typename F> static inline auto WithWordProto(int kind, F &&f) {
222 using namespace Fortran::evaluate::value;
223 switch (kind) {
224 case 2:
225 return f(RealValueImpl::R2{});
226 case 3:
227 return f(RealValueImpl::R3{});
228 case 4:
229 return f(RealValueImpl::R4{});
230 case 8:
231 return f(RealValueImpl::R8{});
232 case 10:
233 return f(RealValueImpl::R10{});
234 case 16:
235 return f(RealValueImpl::R16{});
236 default:
237 DIE("arbitrary bits not yet supported");
238 }
239 }
240
241 template <typename F> auto WithWord(F &&f) const {
242 switch (storage_.index()) {
243 case 1:
244 return f(std::get<1>(storage_));
245 case 2:
246 return f(std::get<2>(storage_));
247 case 3:
248 return f(std::get<3>(storage_));
249 case 4:
250 return f(std::get<4>(storage_));
251 case 5:
252 return f(std::get<5>(storage_));
253 case 6:
254 return f(std::get<6>(storage_));
255 default:
256 DIE("operation on uninitialized RealValueImpl");
257 }
258 }
259
260private:
261 Storage storage_;
262};
263
264} // namespace Fortran::evaluate::value
265
266namespace llvm {
268inline raw_ostream &operator<<(
269 raw_ostream &os, const Fortran::evaluate::value::RealValueImpl &v) {
270 v.print(os);
271 return os;
272}
273} // namespace llvm
274
275#endif // FORTRAN_EVALUATE_REAL_VALUE_IMPL_H_
Definition integer-value.h:34
T GetWord() const
Definition real-value-impl.h:204
Definition real.h:44
Definition target-rounding.h:18