1 //===-- Common header for helpers to set exceptional values -----*- 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 LLVM_LIBC_SRC___SUPPORT_FPUTIL_EXCEPT_VALUE_UTILS_H 10 #define LLVM_LIBC_SRC___SUPPORT_FPUTIL_EXCEPT_VALUE_UTILS_H 11 12 #include "FEnvImpl.h" 13 #include "FPBits.h" 14 #include "cast.h" 15 #include "rounding_mode.h" 16 #include "src/__support/CPP/optional.h" 17 #include "src/__support/macros/config.h" 18 #include "src/__support/macros/optimization.h" // LIBC_UNLIKELY 19 #include "src/__support/macros/properties/cpu_features.h" 20 #include "src/__support/macros/properties/types.h" 21 22 namespace LIBC_NAMESPACE_DECL { 23 24 namespace fputil { 25 26 // This file contains utility functions and classes to manage exceptional values 27 // when there are many of them. 28 // 29 // Example usage: 30 // 31 // Define list of exceptional inputs and outputs: 32 // static constexpr int N = ...; // Number of exceptional values. 33 // static constexpr fputil::ExceptValues<StorageType, N> Excepts { 34 // <list of input bits, output bits and offsets> 35 // }; 36 // 37 // Check for exceptional inputs: 38 // if (auto r = Excepts.lookup(x_bits); LIBC_UNLIKELY(r.has_value())) 39 // return r.value(); 40 41 template <typename T, size_t N> struct ExceptValues { 42 static_assert(cpp::is_floating_point_v<T>, "Must be a floating point type."); 43 44 using StorageType = typename FPBits<T>::StorageType; 45 46 struct Mapping { 47 StorageType input; 48 StorageType rnd_towardzero_result; 49 StorageType rnd_upward_offset; 50 StorageType rnd_downward_offset; 51 StorageType rnd_tonearest_offset; 52 }; 53 54 Mapping values[N]; 55 lookupExceptValues56 LIBC_INLINE constexpr cpp::optional<T> lookup(StorageType x_bits) const { 57 for (size_t i = 0; i < N; ++i) { 58 if (LIBC_UNLIKELY(x_bits == values[i].input)) { 59 StorageType out_bits = values[i].rnd_towardzero_result; 60 switch (fputil::quick_get_round()) { 61 case FE_UPWARD: 62 out_bits += values[i].rnd_upward_offset; 63 break; 64 case FE_DOWNWARD: 65 out_bits += values[i].rnd_downward_offset; 66 break; 67 case FE_TONEAREST: 68 out_bits += values[i].rnd_tonearest_offset; 69 break; 70 } 71 return FPBits<T>(out_bits).get_val(); 72 } 73 } 74 return cpp::nullopt; 75 } 76 lookup_oddExceptValues77 LIBC_INLINE constexpr cpp::optional<T> lookup_odd(StorageType x_abs, 78 bool sign) const { 79 for (size_t i = 0; i < N; ++i) { 80 if (LIBC_UNLIKELY(x_abs == values[i].input)) { 81 StorageType out_bits = values[i].rnd_towardzero_result; 82 switch (fputil::quick_get_round()) { 83 case FE_UPWARD: 84 out_bits += sign ? values[i].rnd_downward_offset 85 : values[i].rnd_upward_offset; 86 break; 87 case FE_DOWNWARD: 88 out_bits += sign ? values[i].rnd_upward_offset 89 : values[i].rnd_downward_offset; 90 break; 91 case FE_TONEAREST: 92 out_bits += values[i].rnd_tonearest_offset; 93 break; 94 } 95 T result = FPBits<T>(out_bits).get_val(); 96 if (sign) 97 result = -result; 98 99 return result; 100 } 101 } 102 return cpp::nullopt; 103 } 104 }; 105 106 // Helper functions to set results for exceptional cases. round_result_slightly_down(T value_rn)107template <typename T> LIBC_INLINE T round_result_slightly_down(T value_rn) { 108 volatile T tmp = value_rn; 109 tmp -= FPBits<T>::min_normal().get_val(); 110 return tmp; 111 } 112 round_result_slightly_up(T value_rn)113template <typename T> LIBC_INLINE T round_result_slightly_up(T value_rn) { 114 volatile T tmp = value_rn; 115 tmp += FPBits<T>::min_normal().get_val(); 116 return tmp; 117 } 118 119 #if defined(LIBC_TYPES_HAS_FLOAT16) && \ 120 !defined(LIBC_TARGET_CPU_HAS_FAST_FLOAT16_OPS) round_result_slightly_down(float16 value_rn)121template <> LIBC_INLINE float16 round_result_slightly_down(float16 value_rn) { 122 volatile float tmp = value_rn; 123 tmp -= FPBits<float16>::min_normal().get_val(); 124 return cast<float16>(tmp); 125 } 126 round_result_slightly_up(float16 value_rn)127template <> LIBC_INLINE float16 round_result_slightly_up(float16 value_rn) { 128 volatile float tmp = value_rn; 129 tmp += FPBits<float16>::min_normal().get_val(); 130 return cast<float16>(tmp); 131 } 132 #endif 133 134 } // namespace fputil 135 136 } // namespace LIBC_NAMESPACE_DECL 137 138 #endif // LLVM_LIBC_SRC___SUPPORT_FPUTIL_EXCEPT_VALUE_UTILS_H 139