brintos

brintos / llvm-project-archived public Read only

0
0
Text · 8.0 KiB · fbb52f2 Raw
231 lines · c
1//===-- lib/Evaluate/host.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-exception6//7//===----------------------------------------------------------------------===//8 9#ifndef FORTRAN_EVALUATE_HOST_H_10#define FORTRAN_EVALUATE_HOST_H_11 12// Define a compile-time mapping between Fortran intrinsic types and host13// hardware types if possible. The purpose is to avoid having to do any kind of14// assumption on whether a "float" matches the Scalar<Type<TypeCategory::Real,15// 4>> outside of this header. The main tools are HostTypeExists<T> and16// HostType<T>. HostTypeExists<T>() will return true if and only if a host17// hardware type maps to Fortran intrinsic type T. Then HostType<T> can be used18// to safely refer to this hardware type.19 20#if HAS_QUADMATHLIB21#include "quadmath_wrapper.h"22#include "flang/Common/float128.h"23#endif24#include "flang/Evaluate/type.h"25#include <cfenv>26#include <complex>27#include <cstdint>28#include <limits>29#include <string>30#include <type_traits>31 32namespace Fortran::evaluate {33namespace host {34 35// Helper class to handle host runtime traps, status flag and errno36class HostFloatingPointEnvironment {37public:38  void SetUpHostFloatingPointEnvironment(FoldingContext &);39  void CheckAndRestoreFloatingPointEnvironment(FoldingContext &);40  bool hasSubnormalFlushingHardwareControl() const {41    return hasSubnormalFlushingHardwareControl_;42  }43  void SetFlag(RealFlag flag) { flags_.set(flag); }44  bool hardwareFlagsAreReliable() const { return hardwareFlagsAreReliable_; }45 46private:47  std::fenv_t originalFenv_;48#if __x86_64__49  unsigned int originalMxcsr;50#endif51  RealFlags flags_;52  bool hasSubnormalFlushingHardwareControl_{false};53  bool hardwareFlagsAreReliable_{true};54};55 56// Type mapping from F18 types to host types57struct UnsupportedType {}; // There is no host type for the F18 type58 59template <typename FTN_T> struct HostTypeHelper {60  using Type = UnsupportedType;61};62template <typename FTN_T> using HostType = typename HostTypeHelper<FTN_T>::Type;63 64template <typename... T> constexpr inline bool HostTypeExists() {65  return (... && (!std::is_same_v<HostType<T>, UnsupportedType>));66}67 68// Type mapping from host types to F18 types FortranType<HOST_T> is defined69// after all HosTypeHelper definition because it reverses them to avoid70// duplication.71 72// Scalar conversion utilities from host scalars to F18 scalars73template <typename FTN_T>74inline constexpr Scalar<FTN_T> CastHostToFortran(const HostType<FTN_T> &x) {75  static_assert(HostTypeExists<FTN_T>());76  if constexpr (FTN_T::category == TypeCategory::Complex &&77      sizeof(Scalar<FTN_T>) != sizeof(HostType<FTN_T>)) {78    // X87 is usually padded to 12 or 16bytes. Need to cast piecewise for79    // complex80    return Scalar<FTN_T>{CastHostToFortran<typename FTN_T::Part>(std::real(x)),81        CastHostToFortran<typename FTN_T::Part>(std::imag(x))};82  } else {83    return *reinterpret_cast<const Scalar<FTN_T> *>(&x);84  }85}86 87// Scalar conversion utilities from F18 scalars to host scalars.88template <typename FTN_T>89inline constexpr HostType<FTN_T> CastFortranToHost(const Scalar<FTN_T> &x) {90  static_assert(HostTypeExists<FTN_T>());91  if constexpr (FTN_T::category == TypeCategory::Complex) {92    using FortranPartType = typename FTN_T::Part;93    return HostType<FTN_T>{CastFortranToHost<FortranPartType>(x.REAL()),94        CastFortranToHost<FortranPartType>(x.AIMAG())};95  } else if constexpr (std::is_same_v<FTN_T, Type<TypeCategory::Real, 10>>) {96    // x87 80-bit floating-point occupies 16 bytes as a C "long double";97    // copy the data to avoid a legitimate (but benign due to little-endianness)98    // warning from GCC >= 11.2.0.99    HostType<FTN_T> y;100    std::memcpy(&y, &x, sizeof x);101    return y;102  } else {103    static_assert(sizeof x == sizeof(HostType<FTN_T>));104    return *reinterpret_cast<const HostType<FTN_T> *>(&x);105  }106}107 108template <> struct HostTypeHelper<Type<TypeCategory::Integer, 1>> {109  using Type = std::int8_t;110};111 112template <> struct HostTypeHelper<Type<TypeCategory::Integer, 2>> {113  using Type = std::int16_t;114};115 116template <> struct HostTypeHelper<Type<TypeCategory::Integer, 4>> {117  using Type = std::int32_t;118};119 120template <> struct HostTypeHelper<Type<TypeCategory::Integer, 8>> {121  using Type = std::int64_t;122};123 124template <> struct HostTypeHelper<Type<TypeCategory::Integer, 16>> {125#if (defined(__GNUC__) || defined(__clang__)) && defined(__SIZEOF_INT128__)126  using Type = __int128_t;127#else128  using Type = UnsupportedType;129#endif130};131 132// TODO no mapping to host types are defined currently for 16bits float133// It should be defined when gcc/clang have a better support for it.134 135template <>136struct HostTypeHelper<137    Type<TypeCategory::Real, common::RealKindForPrecision(24)>> {138  // IEEE 754 32bits139  using Type = std::conditional_t<sizeof(float) == 4 &&140          std::numeric_limits<float>::is_iec559,141      float, UnsupportedType>;142};143 144template <>145struct HostTypeHelper<146    Type<TypeCategory::Real, common::RealKindForPrecision(53)>> {147  // IEEE 754 64bits148  using Type = std::conditional_t<sizeof(double) == 8 &&149          std::numeric_limits<double>::is_iec559,150      double, UnsupportedType>;151};152 153template <>154struct HostTypeHelper<155    Type<TypeCategory::Real, common::RealKindForPrecision(64)>> {156  // X87 80bits157  using Type = std::conditional_t<sizeof(long double) >= 10 &&158          std::numeric_limits<long double>::digits == 64 &&159          std::numeric_limits<long double>::max_exponent == 16384,160      long double, UnsupportedType>;161};162 163#if HAS_QUADMATHLIB164template <> struct HostTypeHelper<Type<TypeCategory::Real, 16>> {165  // IEEE 754 128bits166  using Type = __float128;167};168#else169template <> struct HostTypeHelper<Type<TypeCategory::Real, 16>> {170  // IEEE 754 128bits171  using Type = std::conditional_t<sizeof(long double) == 16 &&172          std::numeric_limits<long double>::digits == 113 &&173          std::numeric_limits<long double>::max_exponent == 16384,174      long double, UnsupportedType>;175};176#endif177 178template <int KIND> struct HostTypeHelper<Type<TypeCategory::Complex, KIND>> {179  using RealT = Fortran::evaluate::Type<TypeCategory::Real, KIND>;180  using Type = std::conditional_t<HostTypeExists<RealT>(),181      std::complex<HostType<RealT>>, UnsupportedType>;182};183 184#if HAS_QUADMATHLIB185template <> struct HostTypeHelper<Type<TypeCategory::Complex, 16>> {186  using RealT = Fortran::evaluate::Type<TypeCategory::Real, 16>;187  using Type = __complex128;188};189#endif190 191template <int KIND> struct HostTypeHelper<Type<TypeCategory::Logical, KIND>> {192  using Type = std::conditional_t<KIND <= 8, std::uint8_t, UnsupportedType>;193};194 195template <int KIND> struct HostTypeHelper<Type<TypeCategory::Character, KIND>> {196  using Type =197      Scalar<typename Fortran::evaluate::Type<TypeCategory::Character, KIND>>;198};199 200// Type mapping from host types to F18 types. This need to be placed after all201// HostTypeHelper specializations.202template <typename T, typename... TT> struct IndexInTupleHelper {};203template <typename T, typename... TT>204struct IndexInTupleHelper<T, std::tuple<TT...>> {205  static constexpr int value{common::TypeIndex<T, TT...>};206};207struct UnknownType {}; // the host type does not match any F18 types208template <typename HOST_T> struct FortranTypeHelper {209  using HostTypeMapping =210      common::MapTemplate<HostType, AllIntrinsicTypes, std::tuple>;211  static constexpr int index{212      IndexInTupleHelper<HOST_T, HostTypeMapping>::value};213  // Both conditional types are "instantiated", so a valid type must be214  // created for invalid index even if not used.215  using Type = std::conditional_t<index >= 0,216      std::tuple_element_t<(index >= 0) ? index : 0, AllIntrinsicTypes>,217      UnknownType>;218};219 220template <typename HOST_T>221using FortranType = typename FortranTypeHelper<HOST_T>::Type;222 223template <typename... HT> constexpr inline bool FortranTypeExists() {224  return (... && (!std::is_same_v<FortranType<HT>, UnknownType>));225}226 227} // namespace host228} // namespace Fortran::evaluate229 230#endif // FORTRAN_EVALUATE_HOST_H_231