diff --git a/libc/src/__support/FPUtil/CMakeLists.txt b/libc/src/__support/FPUtil/CMakeLists.txt --- a/libc/src/__support/FPUtil/CMakeLists.txt +++ b/libc/src/__support/FPUtil/CMakeLists.txt @@ -13,12 +13,14 @@ NormalFloat.h PlatformDefs.h builtin_wrappers.h + except_value_utils.h DEPENDS libc.include.math libc.include.errno libc.include.fenv libc.src.__support.common libc.src.__support.CPP.bit + libc.src.__support.CPP.optional libc.src.__support.CPP.type_traits libc.src.__support.CPP.uint128 libc.src.errno.errno diff --git a/libc/src/__support/FPUtil/except_value_utils.h b/libc/src/__support/FPUtil/except_value_utils.h new file mode 100644 --- /dev/null +++ b/libc/src/__support/FPUtil/except_value_utils.h @@ -0,0 +1,112 @@ +//===-- Common header for helpers to set exceptional values -----*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC_SUPPORT_FPUTIL_EXCEPT_VALUE_UTILS_H +#define LLVM_LIBC_SRC_SUPPORT_FPUTIL_EXCEPT_VALUE_UTILS_H + +#include "FEnvImpl.h" +#include "FPBits.h" +#include "src/__support/CPP/Optional.h" + +namespace __llvm_libc { + +namespace fputil { + +// This file contains utility functions and classes to manage exceptional values +// when there are many of them. +// +// Example usage: +// +// Define list of exceptional inputs and outputs: +// static constexpr int N = ...; // Number of exceptional values. +// static constexpr fputil::ExceptValues Excepts { +// { }, +// { } +// }; +// +// Check for exceptional inputs: +// if (auto result = check_except_values(Excepts, x_bits); +// unlikely(result.has_value())) +// return result.value(); + +template struct ExceptValueOutput { + T rnd_towardzero_result; + T rnd_upward_offset; + T rnd_downward_offset; + T rnd_tonearest_offset; +}; + +template struct ExceptValues { + using UIntType = typename FPBits::UIntType; + static constexpr int SIZE = N; + // Input bits. + UIntType inputs[SIZE]; + ExceptValueOutput outputs[SIZE]; +}; + +template +cpp::Optional check_except_values(const ExceptValues &ExceptVals, + typename FPBits::UIntType x_bits) { + using UIntType = typename FPBits::UIntType; + for (int i = 0; i < N; ++i) { + if (unlikely(x_bits == ExceptVals.inputs[i])) { + UIntType out_bits = ExceptVals.outputs[i].rnd_towardzero_result; + switch (fputil::get_round()) { + case FE_UPWARD: + out_bits += ExceptVals.outputs[i].rnd_upward_offset; + break; + case FE_DOWNWARD: + out_bits += ExceptVals.outputs[i].rnd_downward_offset; + break; + case FE_TONEAREST: + out_bits += ExceptVals.outputs[i].rnd_tonearest_offset; + break; + } + return FPBits(out_bits).get_val(); + } + } + return cpp::Nullopt; +} + +// Check exceptional values for odd functions: f(-x) = -f(x). +template +cpp::Optional +check_odd_func_except_values(const ExceptValues &ExceptVals, + typename FPBits::UIntType x_abs, bool sign) { + using UIntType = typename FPBits::UIntType; + for (int i = 0; i < N; ++i) { + if (unlikely(x_abs == ExceptVals.inputs[i])) { + UIntType out_bits = ExceptVals.outputs[i].rnd_towardzero_result; + switch (fputil::get_round()) { + case FE_UPWARD: + out_bits += sign ? ExceptVals.outputs[i].rnd_downward_offset + : ExceptVals.outputs[i].rnd_upward_offset; + break; + case FE_DOWNWARD: + out_bits += sign ? ExceptVals.outputs[i].rnd_upward_offset + : ExceptVals.outputs[i].rnd_downward_offset; + break; + case FE_TONEAREST: + out_bits += ExceptVals.outputs[i].rnd_tonearest_offset; + break; + } + result = FPBits(out_bits).get_val(); + if (sign) + result = -result; + + return result; + } + } + return cpp::Nullopt; +} + +} // namespace fputil + +} // namespace __llvm_libc + +#endif // LLVM_LIBC_SRC_SUPPORT_FPUTIL_EXCEPT_VALUE_UTILS_H diff --git a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel --- a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel +++ b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel @@ -161,6 +161,7 @@ "src/__support/FPUtil/NormalFloat.h", "src/__support/FPUtil/PlatformDefs.h", "src/__support/FPUtil/builtin_wrappers.h", + "src/__support/FPUtil/except_value_utils.h", ] fputil_hdrs = selects.with_or({