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