FLANG
host.h
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-exception
6//
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 host
13// hardware types if possible. The purpose is to avoid having to do any kind of
14// assumption on whether a "float" matches the Scalar<Type<TypeCategory::Real,
15// 4>> outside of this header. The main tools are HostTypeExists<T> and
16// HostType<T>. HostTypeExists<T>() will return true if and only if a host
17// hardware type maps to Fortran intrinsic type T. Then HostType<T> can be used
18// to safely refer to this hardware type.
19
20#if HAS_QUADMATHLIB
21#include "quadmath_wrapper.h"
22#include "flang/Common/float128.h"
23#endif
24#include "flang/Evaluate/type.h"
25#include "flang/Evaluate/typekind-traits.h"
26#include <cfenv>
27#include <complex>
28#include <cstdint>
29#include <limits>
30#include <type_traits>
31
32namespace Fortran::evaluate {
33namespace host {
34
35// Helper class to handle host runtime traps, status flag and errno
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#endif
51 RealFlags flags_;
52 bool hasSubnormalFlushingHardwareControl_{false};
53 bool hardwareFlagsAreReliable_{true};
54};
55
56// Type mapping from F18 types to host types
57struct UnsupportedType {}; // There is no host type for the F18 type
58
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 defined
69// after all HosTypeHelper definition because it reverses them to avoid
70// duplication.
71
72// Scalar conversion utilities from host scalars to F18 scalars
73template <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 Scalar<FTN_T>::bytesStored(FTN_T::kind) != sizeof(HostType<FTN_T>)) {
78 // X87 is usually padded to 12 or 16bytes. Need to cast piecewise for
79 // complex
80 return Scalar<FTN_T>{CastHostToFortran<typename FTN_T::Part>(std::real(x)),
81 CastHostToFortran<typename FTN_T::Part>(std::imag(x))};
82 } else {
83 static_assert(
84 Scalar<FTN_T>::bytesStored(FTN_T::kind) == sizeof(HostType<FTN_T>));
85 return Scalar<FTN_T>::FromRawBytes(FTN_T::kind, &x, sizeof(x));
86 }
87}
88
89// Scalar conversion utilities from F18 scalars to host scalars.
90template <typename FTN_T>
91inline constexpr HostType<FTN_T> CastFortranToHost(const Scalar<FTN_T> &x) {
92 static_assert(HostTypeExists<FTN_T>());
93 if constexpr (FTN_T::category == TypeCategory::Complex &&
94 Scalar<FTN_T>::bytesStored(FTN_T::kind) != sizeof(HostType<FTN_T>)) {
95 using FortranPartType = typename FTN_T::Part;
96 return HostType<FTN_T>{CastFortranToHost<FortranPartType>(x.REAL()),
97 CastFortranToHost<FortranPartType>(x.AIMAG())};
98 } else {
99 static_assert(
100 Scalar<FTN_T>::bytesStored(FTN_T::kind) == sizeof(HostType<FTN_T>));
101 HostType<FTN_T> result;
102 x.StoreRawBytes(&result, sizeof(result));
103 return result;
104 }
105}
106
107template <> struct HostTypeHelper<TypeKind<TypeCategory::Integer, 1>> {
108 using Type = std::int8_t;
109};
110
111template <> struct HostTypeHelper<TypeKind<TypeCategory::Integer, 2>> {
112 using Type = std::int16_t;
113};
114
115template <> struct HostTypeHelper<TypeKind<TypeCategory::Integer, 4>> {
116 using Type = std::int32_t;
117};
118
119template <> struct HostTypeHelper<TypeKind<TypeCategory::Integer, 8>> {
120 using Type = std::int64_t;
121};
122
123template <> struct HostTypeHelper<TypeKind<TypeCategory::Integer, 16>> {
124#if (defined(__GNUC__) || defined(__clang__)) && defined(__SIZEOF_INT128__)
125 using Type = __int128_t;
126#else
127 using Type = UnsupportedType;
128#endif
129};
130
131// TODO no mapping to host types are defined currently for 16bits float
132// It should be defined when gcc/clang have a better support for it.
133
134template <>
136 TypeKind<TypeCategory::Real, common::RealKindForPrecision(24)>> {
137 // IEEE 754 32bits
138 using Type = std::conditional_t<sizeof(float) == 4 &&
140 float, UnsupportedType>;
141};
142
143template <>
145 TypeKind<TypeCategory::Real, common::RealKindForPrecision(53)>> {
146 // IEEE 754 64bits
147 using Type = std::conditional_t<sizeof(double) == 8 &&
149 double, UnsupportedType>;
150};
151
152template <>
154 TypeKind<TypeCategory::Real, common::RealKindForPrecision(64)>> {
155 // X87 80bits
156 using Type = std::conditional_t<sizeof(long double) >= 10 &&
159 long double, UnsupportedType>;
160};
161
162#if HAS_QUADMATHLIB
163template <> struct HostTypeHelper<TypeKind<TypeCategory::Real, 16>> {
164 // IEEE 754 128bits
165 using Type = __float128;
166};
167#else
168template <> struct HostTypeHelper<TypeKind<TypeCategory::Real, 16>> {
169 // IEEE 754 128bits
170 using Type = std::conditional_t<sizeof(long double) == 16 &&
173 long double, UnsupportedType>;
174};
175#endif
176
177template <int KIND>
178struct HostTypeHelper<TypeKind<TypeCategory::Complex, KIND>> {
180 using Type = std::conditional_t<HostTypeExists<RealT>(),
181 std::complex<HostType<RealT>>, UnsupportedType>;
182};
183
184#if HAS_QUADMATHLIB
185template <> struct HostTypeHelper<TypeKind<TypeCategory::Complex, 16>> {
187 using Type = __complex128;
188};
189#endif
190
191template <int KIND>
192struct HostTypeHelper<TypeKind<TypeCategory::Logical, KIND>> {
193 using Type = std::conditional_t<KIND <= 8, std::uint8_t, UnsupportedType>;
194};
195
196template <int KIND>
197struct HostTypeHelper<TypeKind<TypeCategory::Character, KIND>> {
199};
200
201// Type mapping from host types to F18 types. This need to be placed after all
202// HostTypeHelper specializations.
203template <typename T, typename... TT> struct IndexInTupleHelper {};
204template <typename T, typename... TT>
205struct IndexInTupleHelper<T, std::tuple<TT...>> {
206 static constexpr int value{common::TypeIndex<T, TT...>};
207};
208struct UnknownType {}; // the host type does not match any F18 types
209template <typename HOST_T> struct FortranTypeHelper {
210 using HostTypeMapping =
211 common::MapTemplate<HostType, AllIntrinsicKindTypes, std::tuple>;
212 static constexpr int index{
214 // Both conditional types are "instantiated", so a valid type must be
215 // created for invalid index even if not used.
216 using Type = std::conditional_t<index >= 0,
217 std::tuple_element_t<(index >= 0) ? index : 0, AllIntrinsicKindTypes>,
219};
220
221template <typename HOST_T>
222using FortranType = typename FortranTypeHelper<HOST_T>::Type;
223
224template <typename... HT> constexpr inline bool FortranTypeExists() {
225 return (... && (!std::is_same_v<FortranType<HT>, UnknownType>));
226}
227
228} // namespace host
229} // namespace Fortran::evaluate
230
231#endif // FORTRAN_EVALUATE_HOST_H_
Definition common.h:224
Definition type.h:61
typename std::conditional_t< detail::numeric_limits< T >::is_specialized && !std::numeric_limits< T >::is_specialized, detail::numeric_limits< T >, std::numeric_limits< T > > numeric_limits
Definition numeric-limits.h:118
Definition call.h:34
Definition typekind-traits.h:46