// Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #ifndef FORTRAN_EVALUATE_COMMON_H_ #define FORTRAN_EVALUATE_COMMON_H_ #include "../common/enum-set.h" #include "../common/idioms.h" #include "../common/indirection.h" #include "../parser/message.h" #include namespace Fortran::evaluate { // Integers are always ordered; reals may not be. ENUM_CLASS(Ordering, Less, Equal, Greater) ENUM_CLASS(Relation, Less, Equal, Greater, Unordered) template static constexpr Ordering Compare(const A &x, const A &y) { if (x < y) { return Ordering::Less; } else if (x > y) { return Ordering::Greater; } else { return Ordering::Equal; } } static constexpr Ordering Reverse(Ordering ordering) { if (ordering == Ordering::Less) { return Ordering::Greater; } else if (ordering == Ordering::Greater) { return Ordering::Less; } else { return Ordering::Equal; } } static constexpr Relation RelationFromOrdering(Ordering ordering) { if (ordering == Ordering::Less) { return Relation::Less; } else if (ordering == Ordering::Greater) { return Relation::Greater; } else { return Relation::Equal; } } static constexpr Relation Reverse(Relation relation) { if (relation == Relation::Less) { return Relation::Greater; } else if (relation == Relation::Greater) { return Relation::Less; } else { return relation; } } ENUM_CLASS( RealFlag, Overflow, DivideByZero, InvalidArgument, Underflow, Inexact) using RealFlags = common::EnumSet; template struct ValueWithRealFlags { A AccumulateFlags(RealFlags &f) { f |= flags; return value; } A value; RealFlags flags; }; ENUM_CLASS(Rounding, TiesToEven, ToZero, Down, Up, TiesAwayFromZero) static constexpr Rounding defaultRounding{Rounding::TiesToEven}; #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ constexpr bool IsHostLittleEndian{false}; #elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ constexpr bool IsHostLittleEndian{true}; #else #error host endianness is not known #endif // HostUnsignedInt finds the smallest native unsigned integer type // whose size is >= BITS. template struct SmallestUInt {}; template<> struct SmallestUInt { using type = std::uint8_t; }; template<> struct SmallestUInt { using type = std::uint16_t; }; template<> struct SmallestUInt { using type = std::uint32_t; }; template<> struct SmallestUInt { using type = std::uint64_t; }; template using HostUnsignedInt = typename SmallestUInt::type; // Many classes in this library follow a common paradigm. // - There is no default constructor (Class() {}), usually to prevent the // need for std::monostate as a default constituent in a std::variant<>. // - There are full copy and move semantics for construction and assignment. // - Discriminated unions have a std::variant<> member "u" and support // explicit copy and move constructors. #define DEFAULT_CONSTRUCTORS_AND_ASSIGNMENTS(t) \ t(const t &) = default; \ t(t &&) = default; \ t &operator=(const t &) = default; \ t &operator=(t &&) = default; #define CLASS_BOILERPLATE(t) \ t() = delete; \ DEFAULT_CONSTRUCTORS_AND_ASSIGNMENTS(t) #define EVALUATE_UNION_CLASS_BOILERPLATE(t) \ CLASS_BOILERPLATE(t) \ template explicit t(const _A &x) : u{x} {} \ template \ explicit t(std::enable_if_t, _A> &&x) \ : u(std::move(x)) {} // Force availability of copy construction and assignment template using CopyableIndirection = common::Indirection; // Classes that support a Fold(FoldingContext &) member function have the // IsFoldableTrait. CLASS_TRAIT(IsFoldableTrait) struct FoldingContext { explicit FoldingContext(const parser::ContextualMessages &m, Rounding round = defaultRounding, bool flush = false) : messages{m}, rounding{round}, flushDenormalsToZero{flush} {} FoldingContext(const parser::ContextualMessages &m, const FoldingContext &c) : messages{m}, rounding{c.rounding}, flushDenormalsToZero{ c.flushDenormalsToZero} {} // For narrowed contexts FoldingContext(const FoldingContext &c, const parser::ContextualMessages &m) : messages{m}, rounding{c.rounding}, flushDenormalsToZero{ c.flushDenormalsToZero} {} parser::ContextualMessages messages; Rounding rounding{defaultRounding}; bool flushDenormalsToZero{false}; }; void RealFlagWarnings(FoldingContext &, const RealFlags &, const char *op); } // namespace Fortran::evaluate #endif // FORTRAN_EVALUATE_COMMON_H_