• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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)103 template <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)109 template <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