// Copyright (c) 2019, 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_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 "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 &); private: std::fenv_t originalFenv_; std::fenv_t currentFenv_; }; // 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); } } template struct BiggerOrSameHostTypeHelper { using Type = std::conditional_t(), HostType, UnsupportedType>; using FortranType = T; }; template using BiggerOrSameHostType = typename BiggerOrSameHostTypeHelper::Type; template using BiggerOrSameFortranTypeSupportedOnHost = typename BiggerOrSameHostTypeHelper::FortranType; template constexpr inline bool BiggerOrSameHostTypeExists() { return (... && (!std::is_same_v, UnsupportedType>)); } // 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> { // IEE 754 64bits using Type = std::conditional_t::is_iec559, float, UnsupportedType>; }; template<> struct HostTypeHelper> { // IEE 754 64bits using Type = std::conditional_t::is_iec559, double, UnsupportedType>; }; template<> struct HostTypeHelper> { // 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> { // IEE 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}; using Type = std::conditional_t= 0, std::tuple_element_t, UnknownType>; }; template using FortranType = typename FortranTypeHelper::Type; template constexpr inline bool FortranTypeExists() { return (... && (!std::is_same_v, UnknownType>)); } // Utility to find "bigger" types that exist on host. By bigger, it is meant // that the bigger type can represent all the values of the smaller types // without information loss. template struct NextBiggerReal { using Type = void; }; template struct NextBiggerReal { using Type = Fortran::evaluate::Type; }; template struct NextBiggerReal { using Type = Fortran::evaluate::Type; }; template struct NextBiggerReal { using Type = Fortran::evaluate::Type; }; template struct NextBiggerReal { using Type = Fortran::evaluate::Type; }; template struct NextBiggerReal { using Type = Fortran::evaluate::Type; }; template struct BiggerOrSameHostTypeHelper> { using T = Fortran::evaluate::Type; using NextT = typename NextBiggerReal::Type; using Type = std::conditional_t(), HostType, typename BiggerOrSameHostTypeHelper::Type>; using FortranType = std::conditional_t(), T, typename BiggerOrSameHostTypeHelper::FortranType>; }; template struct BiggerOrSameHostTypeHelper> { using T = Fortran::evaluate::Type; using NextT = typename NextBiggerReal::Type; using Type = std::conditional_t(), HostType, typename BiggerOrSameHostTypeHelper::Type>; using FortranType = std::conditional_t(), T, typename BiggerOrSameHostTypeHelper::FortranType>; }; } } #endif // FORTRAN_EVALUATE_HOST_H_