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 inConstantContext_{that.inConstantContext_},
245 impliedDos_{that.impliedDos_},
246 languageFeatures_{that.languageFeatures_}, tempNames_{that.tempNames_},
247 fpMaxminBehavior_{that.fpMaxminBehavior_} {}
248 FoldingContext(
249 const FoldingContext &that, const parser::ContextualMessages &m)
250 : messages_{m}, defaults_{that.defaults_}, intrinsics_{that.intrinsics_},
251 targetCharacteristics_{that.targetCharacteristics_},
252 pdtInstance_{that.pdtInstance_},
253 analyzingPDTComponentKindSelector_{
254 that.analyzingPDTComponentKindSelector_},
255 inConstantContext_{that.inConstantContext_},
256 impliedDos_{that.impliedDos_},
257 languageFeatures_{that.languageFeatures_}, tempNames_{that.tempNames_},
258 fpMaxminBehavior_{that.fpMaxminBehavior_} {}
259
260 parser::ContextualMessages &messages() { return messages_; }
261 const parser::ContextualMessages &messages() const { return messages_; }
262 const common::IntrinsicTypeDefaultKinds &defaults() const {
263 return defaults_;
264 }
265 const semantics::DerivedTypeSpec *pdtInstance() const { return pdtInstance_; }
266 bool analyzingPDTComponentKindSelector() const {
267 return analyzingPDTComponentKindSelector_;
268 }
269 const IntrinsicProcTable &intrinsics() const { return intrinsics_; }
270 const TargetCharacteristics &targetCharacteristics() const {
271 return targetCharacteristics_;
272 }
273 const common::LanguageFeatureControl &languageFeatures() const {
274 return languageFeatures_;
275 }
276 common::FPMaxminBehavior fpMaxminBehavior() const {
277 return fpMaxminBehavior_;
278 }
279 template <typename... A>
280 parser::Message *Warn(common::LanguageFeature feature, A &&...args) {
281 return messages_.Warn(
282 IsInModuleFile(), languageFeatures_, feature, std::forward<A>(args)...);
283 }
284 template <typename... A>
285 parser::Message *Warn(common::UsageWarning warning, A &&...args) {
286 return messages_.Warn(
287 IsInModuleFile(), languageFeatures_, warning, std::forward<A>(args)...);
288 }
289 std::optional<parser::CharBlock> moduleFileName() const {
290 return moduleFileName_;
291 }
292 FoldingContext &set_moduleFileName(std::optional<parser::CharBlock> n) {
293 moduleFileName_ = n;
294 return *this;
295 }
296 bool IsInModuleFile() const { return moduleFileName_.has_value(); }
297
298 ConstantSubscript &StartImpliedDo(parser::CharBlock, ConstantSubscript = 1);
299 std::optional<ConstantSubscript> GetImpliedDo(parser::CharBlock) const;
300 void EndImpliedDo(parser::CharBlock);
301
302 std::map<parser::CharBlock, ConstantSubscript> &impliedDos() {
303 return impliedDos_;
304 }
305
307 const semantics::DerivedTypeSpec &spec) {
308 return common::ScopedSet(pdtInstance_, &spec);
309 }
311 return common::ScopedSet(pdtInstance_, nullptr);
312 }
313
314 common::Restorer<bool> AnalyzingPDTComponentKindSelector() {
315 return common::ScopedSet(analyzingPDTComponentKindSelector_, true);
316 }
317
318 bool inConstantContext() const { return inConstantContext_; }
319 common::Restorer<bool> WithConstantContext() {
320 return common::ScopedSet(inConstantContext_, true);
321 }
322
323 common::Restorer<std::string> SetRealFlagWarningContext(std::string str) {
324 return common::ScopedSet(realFlagWarningContext_, str);
325 }
326
327 parser::CharBlock SaveTempName(std::string &&name) {
328 return {*tempNames_.emplace(std::move(name)).first};
329 }
330
331 void RealFlagWarnings(const RealFlags &, const char *op);
332
333private:
335 const common::IntrinsicTypeDefaultKinds &defaults_;
336 const IntrinsicProcTable &intrinsics_;
337 const TargetCharacteristics &targetCharacteristics_;
338 const semantics::DerivedTypeSpec *pdtInstance_{nullptr};
339 bool analyzingPDTComponentKindSelector_{false};
340 // True while folding an expression that is required to be constant (e.g. a
341 // named-constant or type-parameter initializer). Used to promote certain
342 // deferred-to-runtime conditions into compile-time diagnostics.
343 bool inConstantContext_{false};
344 std::optional<parser::CharBlock> moduleFileName_;
345 std::map<parser::CharBlock, ConstantSubscript> impliedDos_;
346 const common::LanguageFeatureControl &languageFeatures_;
347 std::set<std::string> &tempNames_;
348 std::string realFlagWarningContext_;
349 common::FPMaxminBehavior fpMaxminBehavior_{common::FPMaxminBehavior::Legacy};
350};
351
352} // namespace Fortran::evaluate
353#endif // FORTRAN_EVALUATE_COMMON_H_
Definition default-kinds.h:26
Definition Fortran-features.h:101
Definition restorer.h:24
Definition common.h:215
Definition char-block.h:26
Definition message.h:397
Definition message.h:200
FPMaxminBehavior
Definition FPMaxminBehavior.h:29
Definition call.h:34
Definition common.h:155