#ifndef FORTRAN_EVALUATE_HOST_H_
#define FORTRAN_EVALUATE_HOST_H_
#if HAS_QUADMATHLIB
#include "quadmath.h"
#include "flang/Common/float128.h"
#endif
#include "flang/Evaluate/type.h"
#include <cfenv>
#include <complex>
#include <cstdint>
#include <limits>
#include <string>
#include <type_traits>
namespace Fortran::evaluate {
namespace host {
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};
};
struct UnsupportedType {};
template <typename FTN_T> struct HostTypeHelper {
using Type = UnsupportedType;
};
template <typename FTN_T> using HostType = typename HostTypeHelper<FTN_T>::Type;
template <typename... T> constexpr inline bool HostTypeExists() {
return (... && (!std::is_same_v<HostType<T>, UnsupportedType>));
}
template <typename FTN_T>
inline constexpr Scalar<FTN_T> CastHostToFortran(const HostType<FTN_T> &x) {
static_assert(HostTypeExists<FTN_T>());
if constexpr (FTN_T::category == TypeCategory::Complex &&
sizeof(Scalar<FTN_T>) != sizeof(HostType<FTN_T>)) {
return Scalar<FTN_T>{CastHostToFortran<typename FTN_T::Part>(std::real(x)),
CastHostToFortran<typename FTN_T::Part>(std::imag(x))};
} else {
return *reinterpret_cast<const Scalar<FTN_T> *>(&x);
}
}
template <typename FTN_T>
inline constexpr HostType<FTN_T> CastFortranToHost(const Scalar<FTN_T> &x) {
static_assert(HostTypeExists<FTN_T>());
if constexpr (FTN_T::category == TypeCategory::Complex) {
using FortranPartType = typename FTN_T::Part;
return HostType<FTN_T>{CastFortranToHost<FortranPartType>(x.REAL()),
CastFortranToHost<FortranPartType>(x.AIMAG())};
} else if constexpr (std::is_same_v<FTN_T, Type<TypeCategory::Real, 10>>) {
HostType<FTN_T> y;
std::memcpy(&y, &x, sizeof x);
return y;
} else {
static_assert(sizeof x == sizeof(HostType<FTN_T>));
return *reinterpret_cast<const HostType<FTN_T> *>(&x);
}
}
template <> struct HostTypeHelper<Type<TypeCategory::Integer, 1>> {
using Type = std::int8_t;
};
template <> struct HostTypeHelper<Type<TypeCategory::Integer, 2>> {
using Type = std::int16_t;
};
template <> struct HostTypeHelper<Type<TypeCategory::Integer, 4>> {
using Type = std::int32_t;
};
template <> struct HostTypeHelper<Type<TypeCategory::Integer, 8>> {
using Type = std::int64_t;
};
template <> struct HostTypeHelper<Type<TypeCategory::Integer, 16>> {
#if (defined(__GNUC__) || defined(__clang__)) && defined(__SIZEOF_INT128__)
using Type = __int128_t;
#else
using Type = UnsupportedType;
#endif
};
template <>
struct HostTypeHelper<
Type<TypeCategory::Real, common::RealKindForPrecision(24)>> {
using Type = std::conditional_t<sizeof(float) == 4 &&
std::numeric_limits<float>::is_iec559,
float, UnsupportedType>;
};
template <>
struct HostTypeHelper<
Type<TypeCategory::Real, common::RealKindForPrecision(53)>> {
using Type = std::conditional_t<sizeof(double) == 8 &&
std::numeric_limits<double>::is_iec559,
double, UnsupportedType>;
};
template <>
struct HostTypeHelper<
Type<TypeCategory::Real, common::RealKindForPrecision(64)>> {
using Type = std::conditional_t<sizeof(long double) >= 10 &&
std::numeric_limits<long double>::digits == 64 &&
std::numeric_limits<long double>::max_exponent == 16384,
long double, UnsupportedType>;
};
#if HAS_QUADMATHLIB
template <> struct HostTypeHelper<Type<TypeCategory::Real, 16>> {
using Type = __float128;
};
#else
template <> struct HostTypeHelper<Type<TypeCategory::Real, 16>> {
using Type = std::conditional_t<sizeof(long double) == 16 &&
std::numeric_limits<long double>::digits == 113 &&
std::numeric_limits<long double>::max_exponent == 16384,
long double, UnsupportedType>;
};
#endif
template <int KIND> struct HostTypeHelper<Type<TypeCategory::Complex, KIND>> {
using RealT = Fortran::evaluate::Type<TypeCategory::Real, KIND>;
using Type = std::conditional_t<HostTypeExists<RealT>(),
std::complex<HostType<RealT>>, UnsupportedType>;
};
#if HAS_QUADMATHLIB
template <> struct HostTypeHelper<Type<TypeCategory::Complex, 16>> {
using RealT = Fortran::evaluate::Type<TypeCategory::Real, 16>;
using Type = __complex128;
};
#endif
template <int KIND> struct HostTypeHelper<Type<TypeCategory::Logical, KIND>> {
using Type = std::conditional_t<KIND <= 8, std::uint8_t, UnsupportedType>;
};
template <int KIND> struct HostTypeHelper<Type<TypeCategory::Character, KIND>> {
using Type =
Scalar<typename Fortran::evaluate::Type<TypeCategory::Character, KIND>>;
};
template <typename T, typename... TT> struct IndexInTupleHelper {};
template <typename T, typename... TT>
struct IndexInTupleHelper<T, std::tuple<TT...>> {
static constexpr int value{common::TypeIndex<T, TT...>};
};
struct UnknownType {};
template <typename HOST_T> struct FortranTypeHelper {
using HostTypeMapping =
common::MapTemplate<HostType, AllIntrinsicTypes, std::tuple>;
static constexpr int index{
IndexInTupleHelper<HOST_T, HostTypeMapping>::value};
using Type = std::conditional_t<index >= 0,
std::tuple_element_t<(index >= 0) ? index : 0, AllIntrinsicTypes>,
UnknownType>;
};
template <typename HOST_T>
using FortranType = typename FortranTypeHelper<HOST_T>::Type;
template <typename... HT> constexpr inline bool FortranTypeExists() {
return (... && (!std::is_same_v<FortranType<HT>, UnknownType>));
}
}
}
#endif