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