FLANG
common.h
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/api-attrs.h"
13#include "flang/Common/enum-set.h"
14#include "flang/Common/idioms.h"
15#include "flang/Common/indirection.h"
16#include "flang/Common/restorer.h"
17#include "flang/Common/target-rounding.h"
18#include "flang/Parser/char-block.h"
19#include "flang/Parser/message.h"
21#include "flang/Support/Fortran-features.h"
22#include "flang/Support/Fortran.h"
23#include "flang/Support/default-kinds.h"
24#include <cinttypes>
25#include <map>
26#include <set>
27#include <string>
28
29namespace Fortran::semantics {
30class DerivedTypeSpec;
31}
32
33namespace Fortran::evaluate {
34class IntrinsicProcTable;
36
37using common::ConstantSubscript;
38using common::RealFlag;
39using common::RealFlags;
40using common::RelationalOperator;
41
42// Integers are always ordered; reals may not be.
43ENUM_CLASS(Ordering, Less, Equal, Greater)
44ENUM_CLASS(Relation, Less, Equal, Greater, Unordered)
45
46template <typename A>
47static constexpr Ordering Compare(const A &x, const A &y) {
48 if (x < y) {
49 return Ordering::Less;
50 } else if (x > y) {
51 return Ordering::Greater;
52 } else {
53 return Ordering::Equal;
54 }
55}
56
57template <typename CH>
58static constexpr Ordering Compare(
59 const std::basic_string<CH> &x, const std::basic_string<CH> &y) {
60 std::size_t xLen{x.size()}, yLen{y.size()};
61 using String = std::basic_string<CH>;
62 // Fortran CHARACTER comparison is defined with blank padding
63 // to extend a shorter operand.
64 if (xLen < yLen) {
65 return Compare(String{x}.append(yLen - xLen, CH{' '}), y);
66 } else if (xLen > yLen) {
67 return Compare(x, String{y}.append(xLen - yLen, CH{' '}));
68 } else if (x < y) {
69 return Ordering::Less;
70 } else if (x > y) {
71 return Ordering::Greater;
72 } else {
73 return Ordering::Equal;
74 }
75}
76
77static constexpr Ordering Reverse(Ordering ordering) {
78 if (ordering == Ordering::Less) {
79 return Ordering::Greater;
80 } else if (ordering == Ordering::Greater) {
81 return Ordering::Less;
82 } else {
83 return Ordering::Equal;
84 }
85}
86
87static constexpr Relation RelationFromOrdering(Ordering ordering) {
88 if (ordering == Ordering::Less) {
89 return Relation::Less;
90 } else if (ordering == Ordering::Greater) {
91 return Relation::Greater;
92 } else {
93 return Relation::Equal;
94 }
95}
96
97static constexpr Relation Reverse(Relation relation) {
98 if (relation == Relation::Less) {
99 return Relation::Greater;
100 } else if (relation == Relation::Greater) {
101 return Relation::Less;
102 } else {
103 return relation;
104 }
105}
106
107static constexpr bool Satisfies(RelationalOperator op, Ordering order) {
108 switch (order) {
109 case Ordering::Less:
110 return op == RelationalOperator::LT || op == RelationalOperator::LE ||
111 op == RelationalOperator::NE;
112 case Ordering::Equal:
113 return op == RelationalOperator::LE || op == RelationalOperator::EQ ||
114 op == RelationalOperator::GE;
115 case Ordering::Greater:
116 return op == RelationalOperator::NE || op == RelationalOperator::GE ||
117 op == RelationalOperator::GT;
118 }
119 return false; // silence g++ warning
120}
121
122static constexpr bool Satisfies(RelationalOperator op, Relation relation) {
123 switch (relation) {
124 case Relation::Less:
125 return Satisfies(op, Ordering::Less);
126 case Relation::Equal:
127 return Satisfies(op, Ordering::Equal);
128 case Relation::Greater:
129 return Satisfies(op, Ordering::Greater);
130 case Relation::Unordered:
131 return op == RelationalOperator::NE;
132 }
133 return false; // silence g++ warning
134}
135
136template <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
146constexpr bool isHostLittleEndian{false};
147#elif FLANG_LITTLE_ENDIAN
148constexpr 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.
155template <bool LE8, bool LE16, bool LE32, bool LE64> struct SmallestUInt {};
156template <> struct SmallestUInt<true, true, true, true> {
157 using type = std::uint8_t;
158};
159template <> struct SmallestUInt<false, true, true, true> {
160 using type = std::uint16_t;
161};
162template <> struct SmallestUInt<false, false, true, true> {
163 using type = std::uint32_t;
164};
165template <> struct SmallestUInt<false, false, false, true> {
166 using type = std::uint64_t;
167};
168template <int BITS>
169using HostUnsignedInt =
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
215template <typename A> class Expr;
216
217class FoldingContext {
218public:
219 FoldingContext(const common::IntrinsicTypeDefaultKinds &d,
220 const IntrinsicProcTable &t, const TargetCharacteristics &c,
222 std::set<std::string> &tempNames,
223 common::FPMaxminBehavior fpMaxminBehavior =
224 common::FPMaxminBehavior::Legacy)
225 : defaults_{d}, intrinsics_{t}, targetCharacteristics_{c},
226 languageFeatures_{lfc}, tempNames_{tempNames},
227 fpMaxminBehavior_{fpMaxminBehavior} {}
228 FoldingContext(const parser::ContextualMessages &m,
229 const common::IntrinsicTypeDefaultKinds &d, const IntrinsicProcTable &t,
231 std::set<std::string> &tempNames,
232 common::FPMaxminBehavior fpMaxminBehavior =
233 common::FPMaxminBehavior::Legacy)
234 : messages_{m}, defaults_{d}, intrinsics_{t}, targetCharacteristics_{c},
235 languageFeatures_{lfc}, tempNames_{tempNames},
236 fpMaxminBehavior_{fpMaxminBehavior} {}
237 FoldingContext(const FoldingContext &that)
238 : messages_{that.messages_}, defaults_{that.defaults_},
239 intrinsics_{that.intrinsics_},
240 targetCharacteristics_{that.targetCharacteristics_},
241 pdtInstance_{that.pdtInstance_},
242 analyzingPDTComponentKindSelector_{
243 that.analyzingPDTComponentKindSelector_},
244 impliedDos_{that.impliedDos_},
245 languageFeatures_{that.languageFeatures_}, tempNames_{that.tempNames_},
246 fpMaxminBehavior_{that.fpMaxminBehavior_} {}
247 FoldingContext(
248 const FoldingContext &that, const parser::ContextualMessages &m)
249 : messages_{m}, defaults_{that.defaults_}, intrinsics_{that.intrinsics_},
250 targetCharacteristics_{that.targetCharacteristics_},
251 pdtInstance_{that.pdtInstance_},
252 analyzingPDTComponentKindSelector_{
253 that.analyzingPDTComponentKindSelector_},
254 impliedDos_{that.impliedDos_},
255 languageFeatures_{that.languageFeatures_}, tempNames_{that.tempNames_},
256 fpMaxminBehavior_{that.fpMaxminBehavior_} {}
257
258 parser::ContextualMessages &messages() { return messages_; }
259 const parser::ContextualMessages &messages() const { return messages_; }
260 const common::IntrinsicTypeDefaultKinds &defaults() const {
261 return defaults_;
262 }
263 const semantics::DerivedTypeSpec *pdtInstance() const { return pdtInstance_; }
264 bool analyzingPDTComponentKindSelector() const {
265 return analyzingPDTComponentKindSelector_;
266 }
267 const IntrinsicProcTable &intrinsics() const { return intrinsics_; }
268 const TargetCharacteristics &targetCharacteristics() const {
269 return targetCharacteristics_;
270 }
271 const common::LanguageFeatureControl &languageFeatures() const {
272 return languageFeatures_;
273 }
274 common::FPMaxminBehavior fpMaxminBehavior() const {
275 return fpMaxminBehavior_;
276 }
277 template <typename... A>
278 parser::Message *Warn(common::LanguageFeature feature, A &&...args) {
279 return messages_.Warn(
280 IsInModuleFile(), languageFeatures_, feature, std::forward<A>(args)...);
281 }
282 template <typename... A>
283 parser::Message *Warn(common::UsageWarning warning, A &&...args) {
284 return messages_.Warn(
285 IsInModuleFile(), languageFeatures_, warning, std::forward<A>(args)...);
286 }
287 std::optional<parser::CharBlock> moduleFileName() const {
288 return moduleFileName_;
289 }
290 FoldingContext &set_moduleFileName(std::optional<parser::CharBlock> n) {
291 moduleFileName_ = n;
292 return *this;
293 }
294 bool IsInModuleFile() const { return moduleFileName_.has_value(); }
295
296 ConstantSubscript &StartImpliedDo(parser::CharBlock, ConstantSubscript = 1);
297 std::optional<ConstantSubscript> GetImpliedDo(parser::CharBlock) const;
298 void EndImpliedDo(parser::CharBlock);
299
300 std::map<parser::CharBlock, ConstantSubscript> &impliedDos() {
301 return impliedDos_;
302 }
303
305 const semantics::DerivedTypeSpec &spec) {
306 return common::ScopedSet(pdtInstance_, &spec);
307 }
309 return common::ScopedSet(pdtInstance_, nullptr);
310 }
311
312 common::Restorer<bool> AnalyzingPDTComponentKindSelector() {
313 return common::ScopedSet(analyzingPDTComponentKindSelector_, true);
314 }
315
316 common::Restorer<std::string> SetRealFlagWarningContext(std::string str) {
317 return common::ScopedSet(realFlagWarningContext_, str);
318 }
319
320 parser::CharBlock SaveTempName(std::string &&name) {
321 return {*tempNames_.emplace(std::move(name)).first};
322 }
323
324 void RealFlagWarnings(const RealFlags &, const char *op);
325
326private:
328 const common::IntrinsicTypeDefaultKinds &defaults_;
329 const IntrinsicProcTable &intrinsics_;
330 const TargetCharacteristics &targetCharacteristics_;
331 const semantics::DerivedTypeSpec *pdtInstance_{nullptr};
332 bool analyzingPDTComponentKindSelector_{false};
333 std::optional<parser::CharBlock> moduleFileName_;
334 std::map<parser::CharBlock, ConstantSubscript> impliedDos_;
335 const common::LanguageFeatureControl &languageFeatures_;
336 std::set<std::string> &tempNames_;
337 std::string realFlagWarningContext_;
338 common::FPMaxminBehavior fpMaxminBehavior_{common::FPMaxminBehavior::Legacy};
339};
340
341} // namespace Fortran::evaluate
342#endif // FORTRAN_EVALUATE_COMMON_H_
Definition default-kinds.h:26
Definition Fortran-features.h:93
Definition restorer.h:24
Definition common.h:215
Definition char-block.h:28
Definition message.h:396
Definition message.h:200
FPMaxminBehavior
Definition FPMaxminBehavior.h:29
Definition call.h:34
Definition common.h:155