Warning: This file is not a C or C++ file. It does not have highlighting.
1 | //===-- include/flang/Evaluate/common.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_COMMON_H_ |
10 | #define FORTRAN_EVALUATE_COMMON_H_ |
11 | |
12 | #include "flang/Common/Fortran-features.h" |
13 | #include "flang/Common/Fortran.h" |
14 | #include "flang/Common/default-kinds.h" |
15 | #include "flang/Common/enum-set.h" |
16 | #include "flang/Common/idioms.h" |
17 | #include "flang/Common/indirection.h" |
18 | #include "flang/Common/restorer.h" |
19 | #include "flang/Parser/char-block.h" |
20 | #include "flang/Parser/message.h" |
21 | #include <cinttypes> |
22 | #include <map> |
23 | #include <set> |
24 | #include <string> |
25 | |
26 | namespace Fortran::semantics { |
27 | class DerivedTypeSpec; |
28 | } |
29 | |
30 | namespace Fortran::evaluate { |
31 | class IntrinsicProcTable; |
32 | class TargetCharacteristics; |
33 | |
34 | using common::ConstantSubscript; |
35 | using common::RelationalOperator; |
36 | |
37 | // Integers are always ordered; reals may not be. |
38 | ENUM_CLASS(Ordering, Less, Equal, Greater) |
39 | ENUM_CLASS(Relation, Less, Equal, Greater, Unordered) |
40 | |
41 | template <typename A> |
42 | static constexpr Ordering Compare(const A &x, const A &y) { |
43 | if (x < y) { |
44 | return Ordering::Less; |
45 | } else if (x > y) { |
46 | return Ordering::Greater; |
47 | } else { |
48 | return Ordering::Equal; |
49 | } |
50 | } |
51 | |
52 | template <typename CH> |
53 | static constexpr Ordering Compare( |
54 | const std::basic_string<CH> &x, const std::basic_string<CH> &y) { |
55 | std::size_t xLen{x.size()}, yLen{y.size()}; |
56 | using String = std::basic_string<CH>; |
57 | // Fortran CHARACTER comparison is defined with blank padding |
58 | // to extend a shorter operand. |
59 | if (xLen < yLen) { |
60 | return Compare(String{x}.append(yLen - xLen, CH{' '}), y); |
61 | } else if (xLen > yLen) { |
62 | return Compare(x, String{y}.append(xLen - yLen, CH{' '})); |
63 | } else if (x < y) { |
64 | return Ordering::Less; |
65 | } else if (x > y) { |
66 | return Ordering::Greater; |
67 | } else { |
68 | return Ordering::Equal; |
69 | } |
70 | } |
71 | |
72 | static constexpr Ordering Reverse(Ordering ordering) { |
73 | if (ordering == Ordering::Less) { |
74 | return Ordering::Greater; |
75 | } else if (ordering == Ordering::Greater) { |
76 | return Ordering::Less; |
77 | } else { |
78 | return Ordering::Equal; |
79 | } |
80 | } |
81 | |
82 | static constexpr Relation RelationFromOrdering(Ordering ordering) { |
83 | if (ordering == Ordering::Less) { |
84 | return Relation::Less; |
85 | } else if (ordering == Ordering::Greater) { |
86 | return Relation::Greater; |
87 | } else { |
88 | return Relation::Equal; |
89 | } |
90 | } |
91 | |
92 | static constexpr Relation Reverse(Relation relation) { |
93 | if (relation == Relation::Less) { |
94 | return Relation::Greater; |
95 | } else if (relation == Relation::Greater) { |
96 | return Relation::Less; |
97 | } else { |
98 | return relation; |
99 | } |
100 | } |
101 | |
102 | static constexpr bool Satisfies(RelationalOperator op, Ordering order) { |
103 | switch (order) { |
104 | case Ordering::Less: |
105 | return op == RelationalOperator::LT || op == RelationalOperator::LE || |
106 | op == RelationalOperator::NE; |
107 | case Ordering::Equal: |
108 | return op == RelationalOperator::LE || op == RelationalOperator::EQ || |
109 | op == RelationalOperator::GE; |
110 | case Ordering::Greater: |
111 | return op == RelationalOperator::NE || op == RelationalOperator::GE || |
112 | op == RelationalOperator::GT; |
113 | } |
114 | return false; // silence g++ warning |
115 | } |
116 | |
117 | static constexpr bool Satisfies(RelationalOperator op, Relation relation) { |
118 | switch (relation) { |
119 | case Relation::Less: |
120 | return Satisfies(op, Ordering::Less); |
121 | case Relation::Equal: |
122 | return Satisfies(op, Ordering::Equal); |
123 | case Relation::Greater: |
124 | return Satisfies(op, Ordering::Greater); |
125 | case Relation::Unordered: |
126 | return op == RelationalOperator::NE; |
127 | } |
128 | return false; // silence g++ warning |
129 | } |
130 | |
131 | ENUM_CLASS( |
132 | RealFlag, Overflow, DivideByZero, InvalidArgument, Underflow, Inexact) |
133 | |
134 | using RealFlags = common::EnumSet<RealFlag, RealFlag_enumSize>; |
135 | |
136 | template <typename A> struct ValueWithRealFlags { |
137 | A AccumulateFlags(RealFlags &f) { |
138 | f |= flags; |
139 | return value; |
140 | } |
141 | A value; |
142 | RealFlags flags{}; |
143 | }; |
144 | |
145 | #if FLANG_BIG_ENDIAN |
146 | constexpr bool isHostLittleEndian{false}; |
147 | #elif FLANG_LITTLE_ENDIAN |
148 | constexpr bool isHostLittleEndian{true}; |
149 | #else |
150 | #error host endianness is not known |
151 | #endif |
152 | |
153 | // HostUnsignedInt<BITS> finds the smallest native unsigned integer type |
154 | // whose size is >= BITS. |
155 | template <bool LE8, bool LE16, bool LE32, bool LE64> struct SmallestUInt {}; |
156 | template <> struct SmallestUInt<true, true, true, true> { |
157 | using type = std::uint8_t; |
158 | }; |
159 | template <> struct SmallestUInt<false, true, true, true> { |
160 | using type = std::uint16_t; |
161 | }; |
162 | template <> struct SmallestUInt<false, false, true, true> { |
163 | using type = std::uint32_t; |
164 | }; |
165 | template <> struct SmallestUInt<false, false, false, true> { |
166 | using type = std::uint64_t; |
167 | }; |
168 | template <int BITS> |
169 | using HostUnsignedInt = |
170 | typename SmallestUInt<BITS <= 8, BITS <= 16, BITS <= 32, BITS <= 64>::type; |
171 | |
172 | // Many classes in this library follow a common paradigm. |
173 | // - There is no default constructor (Class() {}), usually to prevent the |
174 | // need for std::monostate as a default constituent in a std::variant<>. |
175 | // - There are full copy and move semantics for construction and assignment. |
176 | // - Discriminated unions have a std::variant<> member "u" and support |
177 | // explicit copy and move constructors as well as comparison for equality. |
178 | #define DECLARE_CONSTRUCTORS_AND_ASSIGNMENTS(t) \ |
179 | t(const t &); \ |
180 | t(t &&); \ |
181 | t &operator=(const t &); \ |
182 | t &operator=(t &&); |
183 | #define DEFAULT_CONSTRUCTORS_AND_ASSIGNMENTS(t) \ |
184 | t(const t &) = default; \ |
185 | t(t &&) = default; \ |
186 | t &operator=(const t &) = default; \ |
187 | t &operator=(t &&) = default; |
188 | #define DEFINE_DEFAULT_CONSTRUCTORS_AND_ASSIGNMENTS(t) \ |
189 | t::t(const t &) = default; \ |
190 | t::t(t &&) = default; \ |
191 | t &t::operator=(const t &) = default; \ |
192 | t &t::operator=(t &&) = default; |
193 | #define CONSTEXPR_CONSTRUCTORS_AND_ASSIGNMENTS(t) \ |
194 | constexpr t(const t &) = default; \ |
195 | constexpr t(t &&) = default; \ |
196 | constexpr t &operator=(const t &) = default; \ |
197 | constexpr t &operator=(t &&) = default; |
198 | |
199 | #define CLASS_BOILERPLATE(t) \ |
200 | t() = delete; \ |
201 | DEFAULT_CONSTRUCTORS_AND_ASSIGNMENTS(t) |
202 | |
203 | #define UNION_CONSTRUCTORS(t) \ |
204 | template <typename _A> explicit t(const _A &x) : u{x} {} \ |
205 | template <typename _A, typename = common::NoLvalue<_A>> \ |
206 | explicit t(_A &&x) : u(std::move(x)) {} |
207 | |
208 | #define EVALUATE_UNION_CLASS_BOILERPLATE(t) \ |
209 | CLASS_BOILERPLATE(t) \ |
210 | UNION_CONSTRUCTORS(t) \ |
211 | bool operator==(const t &) const; |
212 | |
213 | // Forward definition of Expr<> so that it can be indirectly used in its own |
214 | // definition |
215 | template <typename A> class Expr; |
216 | |
217 | class FoldingContext { |
218 | public: |
219 | FoldingContext(const common::IntrinsicTypeDefaultKinds &d, |
220 | const IntrinsicProcTable &t, const TargetCharacteristics &c, |
221 | const common::LanguageFeatureControl &lfc, |
222 | std::set<std::string> &tempNames) |
223 | : defaults_{d}, intrinsics_{t}, targetCharacteristics_{c}, |
224 | languageFeatures_{lfc}, tempNames_{tempNames} {} |
225 | FoldingContext(const parser::ContextualMessages &m, |
226 | const common::IntrinsicTypeDefaultKinds &d, const IntrinsicProcTable &t, |
227 | const TargetCharacteristics &c, const common::LanguageFeatureControl &lfc, |
228 | std::set<std::string> &tempNames) |
229 | : messages_{m}, defaults_{d}, intrinsics_{t}, targetCharacteristics_{c}, |
230 | languageFeatures_{lfc}, tempNames_{tempNames} {} |
231 | FoldingContext(const FoldingContext &that) |
232 | : messages_{that.messages_}, defaults_{that.defaults_}, |
233 | intrinsics_{that.intrinsics_}, |
234 | targetCharacteristics_{that.targetCharacteristics_}, |
235 | pdtInstance_{that.pdtInstance_}, impliedDos_{that.impliedDos_}, |
236 | languageFeatures_{that.languageFeatures_}, tempNames_{that.tempNames_} { |
237 | } |
238 | FoldingContext( |
239 | const FoldingContext &that, const parser::ContextualMessages &m) |
240 | : messages_{m}, defaults_{that.defaults_}, intrinsics_{that.intrinsics_}, |
241 | targetCharacteristics_{that.targetCharacteristics_}, |
242 | pdtInstance_{that.pdtInstance_}, impliedDos_{that.impliedDos_}, |
243 | languageFeatures_{that.languageFeatures_}, tempNames_{that.tempNames_} { |
244 | } |
245 | |
246 | parser::ContextualMessages &messages() { return messages_; } |
247 | const parser::ContextualMessages &messages() const { return messages_; } |
248 | const common::IntrinsicTypeDefaultKinds &defaults() const { |
249 | return defaults_; |
250 | } |
251 | const semantics::DerivedTypeSpec *pdtInstance() const { return pdtInstance_; } |
252 | const IntrinsicProcTable &intrinsics() const { return intrinsics_; } |
253 | const TargetCharacteristics &targetCharacteristics() const { |
254 | return targetCharacteristics_; |
255 | } |
256 | const common::LanguageFeatureControl &languageFeatures() const { |
257 | return languageFeatures_; |
258 | } |
259 | std::optional<parser::CharBlock> moduleFileName() const { |
260 | return moduleFileName_; |
261 | } |
262 | FoldingContext &set_moduleFileName(std::optional<parser::CharBlock> n) { |
263 | moduleFileName_ = n; |
264 | return *this; |
265 | } |
266 | |
267 | ConstantSubscript &StartImpliedDo(parser::CharBlock, ConstantSubscript = 1); |
268 | std::optional<ConstantSubscript> GetImpliedDo(parser::CharBlock) const; |
269 | void EndImpliedDo(parser::CharBlock); |
270 | |
271 | std::map<parser::CharBlock, ConstantSubscript> &impliedDos() { |
272 | return impliedDos_; |
273 | } |
274 | |
275 | common::Restorer<const semantics::DerivedTypeSpec *> WithPDTInstance( |
276 | const semantics::DerivedTypeSpec &spec) { |
277 | return common::ScopedSet(pdtInstance_, &spec); |
278 | } |
279 | common::Restorer<const semantics::DerivedTypeSpec *> WithoutPDTInstance() { |
280 | return common::ScopedSet(pdtInstance_, nullptr); |
281 | } |
282 | |
283 | parser::CharBlock SaveTempName(std::string &&name) { |
284 | return {*tempNames_.emplace(std::move(name)).first}; |
285 | } |
286 | |
287 | private: |
288 | parser::ContextualMessages messages_; |
289 | const common::IntrinsicTypeDefaultKinds &defaults_; |
290 | const IntrinsicProcTable &intrinsics_; |
291 | const TargetCharacteristics &targetCharacteristics_; |
292 | const semantics::DerivedTypeSpec *pdtInstance_{nullptr}; |
293 | std::optional<parser::CharBlock> moduleFileName_; |
294 | std::map<parser::CharBlock, ConstantSubscript> impliedDos_; |
295 | const common::LanguageFeatureControl &languageFeatures_; |
296 | std::set<std::string> &tempNames_; |
297 | }; |
298 | |
299 | void RealFlagWarnings(FoldingContext &, const RealFlags &, const char *op); |
300 | } // namespace Fortran::evaluate |
301 | #endif // FORTRAN_EVALUATE_COMMON_H_ |
302 |
Warning: This file is not a C or C++ file. It does not have highlighting.