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,6 +13,7 @@ NormalFloat.h PlatformDefs.h builtin_wrappers.h + except_value_utils.h DEPENDS libc.include.math libc.include.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,111 @@ +//===-- 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" + +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::ExceptionalValues Excepts { +// { }, +// { } +// }; +// +// Check for exceptional inputs: +// using ExceptChecker = typename fputil::ExceptionChecker; +// if (float result; ExceptChecker::check(Excepts, x_bits, result)) +// return result; + +template struct ExceptionalValues { + using UIntType = typename FPBits::UIntType; + static constexpr int SIZE = N; + // Input bits. + UIntType inputs[SIZE]; + // Output bits contains 4 values: + // output[i][0]: output bits corresponding to FE_TOWARDZERO + // output[i][1]: offset for FE_UPWARD + // output[i][2]: offset for FE_DOWNWARD + // output[i][3]: offset for FE_TONEAREST + UIntType outputs[SIZE][4]; +}; + +template struct ExceptionChecker { + using UIntType = typename FPBits::UIntType; + using FPBits = FPBits; + using ExceptionalValues = ExceptionalValues; + + static bool check(const ExceptionalValues &ExceptionalValues, UIntType x_bits, + T &result) { + for (int i = 0; i < N; ++i) { + if (unlikely(x_bits == ExceptVals.inputs[i])) { + UIntType out_bits = ExceptVals.outputs[i][0]; // FE_TOWARDZERO + switch (fputil::get_round()) { + case FE_UPWARD: + out_bits += ExceptVals.outputs[i][1]; + break; + case FE_DOWNWARD: + out_bits += ExceptVals.outputs[i][2]; + break; + case FE_TONEAREST: + out_bits += ExceptVals.outputs[i][3]; + break; + } + result = FPBits(out_bits).get_val(); + + return true; + } + } + return false; + } + + static bool check_odd_func(const ExceptionalValues &ExceptVals, + UIntType x_abs, bool sign, T &result) { + for (int i = 0; i < N; ++i) { + if (unlikely(x_abs == ExceptVals.inputs[i])) { + UIntType out_bits = ExceptVals.outputs[i][0]; // FE_TOWARDZERO + switch (fputil::get_round()) { + case FE_UPWARD: + out_bits += + sign ? ExceptVals.outputs[i][2] : ExceptVals.outputs[i][1]; + break; + case FE_DOWNWARD: + out_bits += + sign ? ExceptVals.outputs[i][1] : ExceptVals.outputs[i][2]; + break; + case FE_TONEAREST: + out_bits += ExceptVals.outputs[i][3]; + break; + } + result = FPBits(out_bits).get_val(); + if (sign) + result = -result; + + return true; + } + } + return false; + } +}; + +} // 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({