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