//===-- lib/Evaluate/host.h -------------------------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #ifndef FORTRAN_EVALUATE_HOST_H_ #define FORTRAN_EVALUATE_HOST_H_ // Define a compile-time mapping between Fortran intrinsic types and host // hardware types if possible. The purpose is to avoid having to do any kind of // assumption on whether a "float" matches the Scalar> outside of this header. The main tools are HostTypeExists and // HostType. HostTypeExists() will return true if and only if a host // hardware type maps to Fortran intrinsic type T. Then HostType can be used // to safely refer to this hardware type. #include "flang/Evaluate/type.h" #include #include #include #include #include #include namespace Fortran::evaluate { namespace host { // Helper class to handle host runtime traps, status flag and errno class HostFloatingPointEnvironment { public: void SetUpHostFloatingPointEnvironment(FoldingContext &); void CheckAndRestoreFloatingPointEnvironment(FoldingContext &); bool hasSubnormalFlushingHardwareControl() const { return hasSubnormalFlushingHardwareControl_; } void SetFlag(RealFlag flag) { flags_.set(flag); } bool hardwareFlagsAreReliable() const { return hardwareFlagsAreReliable_; } private: std::fenv_t originalFenv_; #if __x86_64__ unsigned int originalMxcsr; #endif RealFlags flags_; bool hasSubnormalFlushingHardwareControl_{false}; bool hardwareFlagsAreReliable_{true}; }; // Type mapping from F18 types to host types struct UnsupportedType {}; // There is no host type for the F18 type template struct HostTypeHelper { using Type = UnsupportedType; }; template using HostType = typename HostTypeHelper::Type; template constexpr inline bool HostTypeExists() { return (... && (!std::is_same_v, UnsupportedType>)); } // Type mapping from host types to F18 types FortranType is defined // after all HosTypeHelper definition because it reverses them to avoid // duplication. // Scalar conversion utilities from host scalars to F18 scalars template inline constexpr Scalar CastHostToFortran(const HostType &x) { static_assert(HostTypeExists()); if constexpr (FTN_T::category == TypeCategory::Complex && sizeof(Scalar) != sizeof(HostType)) { // X87 is usually padded to 12 or 16bytes. Need to cast piecewise for // complex return Scalar{CastHostToFortran(std::real(x)), CastHostToFortran(std::imag(x))}; } else { return *reinterpret_cast *>(&x); } } // Scalar conversion utilities from F18 scalars to host scalars template inline constexpr HostType CastFortranToHost(const Scalar &x) { static_assert(HostTypeExists()); if constexpr (FTN_T::category == TypeCategory::Complex && sizeof(Scalar) != sizeof(HostType)) { // X87 is usually padded to 12 or 16bytes. Need to cast piecewise for // complex return HostType{CastFortranToHost(x.REAL()), CastFortranToHost(x.AIMAG())}; } else { return *reinterpret_cast *>(&x); } } // Defining the actual mapping template <> struct HostTypeHelper> { using Type = std::int8_t; }; template <> struct HostTypeHelper> { using Type = std::int16_t; }; template <> struct HostTypeHelper> { using Type = std::int32_t; }; template <> struct HostTypeHelper> { using Type = std::int64_t; }; template <> struct HostTypeHelper> { #if (defined(__GNUC__) || defined(__clang__)) && defined(__SIZEOF_INT128__) using Type = __int128_t; #else using Type = UnsupportedType; #endif }; // TODO no mapping to host types are defined currently for 16bits float // It should be defined when gcc/clang have a better support for it. template <> struct HostTypeHelper< Type> { // IEEE 754 32bits using Type = std::conditional_t::is_iec559, float, UnsupportedType>; }; template <> struct HostTypeHelper< Type> { // IEEE 754 64bits using Type = std::conditional_t::is_iec559, double, UnsupportedType>; }; template <> struct HostTypeHelper< Type> { // X87 80bits using Type = std::conditional_t= 10 && std::numeric_limits::digits == 64 && std::numeric_limits::max_exponent == 16384, long double, UnsupportedType>; }; template <> struct HostTypeHelper< Type> { // IEEE 754 128bits using Type = std::conditional_t::digits == 113 && std::numeric_limits::max_exponent == 16384, long double, UnsupportedType>; }; template struct HostTypeHelper> { using RealT = Fortran::evaluate::Type; using Type = std::conditional_t(), std::complex>, UnsupportedType>; }; template struct HostTypeHelper> { using Type = std::conditional_t; }; template struct HostTypeHelper> { using Type = Scalar>; }; // Type mapping from host types to F18 types. This need to be placed after all // HostTypeHelper specializations. template struct IndexInTupleHelper {}; template struct IndexInTupleHelper> { static constexpr int value{common::TypeIndex}; }; struct UnknownType {}; // the host type does not match any F18 types template struct FortranTypeHelper { using HostTypeMapping = common::MapTemplate; static constexpr int index{ IndexInTupleHelper::value}; // Both conditional types are "instantiated", so a valid type must be // created for invalid index even if not used. using Type = std::conditional_t= 0, std::tuple_element_t<(index >= 0) ? index : 0, AllIntrinsicTypes>, UnknownType>; }; template using FortranType = typename FortranTypeHelper::Type; template constexpr inline bool FortranTypeExists() { return (... && (!std::is_same_v, UnknownType>)); } } // namespace host } // namespace Fortran::evaluate #endif // FORTRAN_EVALUATE_HOST_H_