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 27 namespace Fortran::semantics { 28 class DerivedTypeSpec; 29 } 30 31 namespace Fortran::evaluate { 32 class IntrinsicProcTable; 33 class TargetCharacteristics; 34 35 using common::ConstantSubscript; 36 using common::RealFlag; 37 using common::RealFlags; 38 using common::RelationalOperator; 39 40 // Integers are always ordered; reals may not be. 41 ENUM_CLASS(Ordering, Less, Equal, Greater) 42 ENUM_CLASS(Relation, Less, Equal, Greater, Unordered) 43 44 template <typename A> 45 static 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 55 template <typename CH> 56 static 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 75 static 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 85 static 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 95 static 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 105 static 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 120 static 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 134 template <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 144 constexpr bool isHostLittleEndian{false}; 145 #elif FLANG_LITTLE_ENDIAN 146 constexpr 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. 153 template <bool LE8, bool LE16, bool LE32, bool LE64> struct SmallestUInt {}; 154 template <> struct SmallestUInt<true, true, true, true> { 155 using type = std::uint8_t; 156 }; 157 template <> struct SmallestUInt<false, true, true, true> { 158 using type = std::uint16_t; 159 }; 160 template <> struct SmallestUInt<false, false, true, true> { 161 using type = std::uint32_t; 162 }; 163 template <> struct SmallestUInt<false, false, false, true> { 164 using type = std::uint64_t; 165 }; 166 template <int BITS> 167 using HostUnsignedInt = 168 typename SmallestUInt<BITS <= 8, BITS <= 16, BITS <= 32, BITS <= 64>::type; 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 213 template <typename A> class Expr; 214 215 class FoldingContext { 216 public: 217 FoldingContext(const common::IntrinsicTypeDefaultKinds &d, 218 const IntrinsicProcTable &t, const TargetCharacteristics &c, 219 const common::LanguageFeatureControl &lfc, 220 std::set<std::string> &tempNames) 221 : defaults_{d}, intrinsics_{t}, targetCharacteristics_{c}, 222 languageFeatures_{lfc}, tempNames_{tempNames} {} 223 FoldingContext(const parser::ContextualMessages &m, 224 const common::IntrinsicTypeDefaultKinds &d, const IntrinsicProcTable &t, 225 const TargetCharacteristics &c, const common::LanguageFeatureControl &lfc, 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 } 236 FoldingContext( 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 273 common::Restorer<const semantics::DerivedTypeSpec *> WithPDTInstance( 274 const semantics::DerivedTypeSpec &spec) { 275 return common::ScopedSet(pdtInstance_, &spec); 276 } 277 common::Restorer<const semantics::DerivedTypeSpec *> WithoutPDTInstance() { 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 285 private: 286 parser::ContextualMessages messages_; 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 297 void RealFlagWarnings(FoldingContext &, const RealFlags &, const char *op); 298 } // namespace Fortran::evaluate 299 #endif // FORTRAN_EVALUATE_COMMON_H_ 300