From a4d48e3b0b66cacb8c42be8421608f7efd170c24 Mon Sep 17 00:00:00 2001 From: Tue Ly Date: Thu, 1 Sep 2022 14:30:51 -0400 Subject: [PATCH] [libc][NFC] Use cpp::optional for checking exceptional values of math functions. Update the utility functions for checking exceptional values of math functions to use cpp::optional return values. Reviewed By: sivachandra Differential Revision: https://reviews.llvm.org/D133134 --- libc/src/__support/FPUtil/CMakeLists.txt | 1 + libc/src/__support/FPUtil/except_value_utils.h | 89 ++++++++++++++++++-------- libc/src/math/generic/cosf.cpp | 44 ++++++------- libc/src/math/generic/tanf.cpp | 51 ++++++--------- 4 files changed, 100 insertions(+), 85 deletions(-) diff --git a/libc/src/__support/FPUtil/CMakeLists.txt b/libc/src/__support/FPUtil/CMakeLists.txt index 5a66139..a3b0850 100644 --- a/libc/src/__support/FPUtil/CMakeLists.txt +++ b/libc/src/__support/FPUtil/CMakeLists.txt @@ -102,6 +102,7 @@ add_header_library( DEPENDS .fp_bits .fenv_impl + libc.src.__support.CPP.optional ) diff --git a/libc/src/__support/FPUtil/except_value_utils.h b/libc/src/__support/FPUtil/except_value_utils.h index a8a9ba8..684647c2 100644 --- a/libc/src/__support/FPUtil/except_value_utils.h +++ b/libc/src/__support/FPUtil/except_value_utils.h @@ -11,55 +11,88 @@ #include "FEnvImpl.h" #include "FPBits.h" +#include "src/__support/CPP/optional.h" namespace __llvm_libc { namespace fputil { -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]; -}; +// 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 r = Excepts.lookup(x_bits); unlikely(r.has_value())) +// return r.value(); + +template struct ExceptValues { + static_assert(cpp::is_floating_point_v, "Must be a floating point type."); -template struct ExceptionChecker { using UIntType = typename FPBits::UIntType; - using FPBits = FPBits; - using ExceptionalValues = ExceptionalValues; - 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 + struct Mapping { + UIntType input; + UIntType rnd_towardzero_result; + UIntType rnd_upward_offset; + UIntType rnd_downward_offset; + UIntType rnd_tonearest_offset; + }; + + Mapping values[N]; + + constexpr cpp::optional lookup(UIntType x_bits) const { + for (size_t i = 0; i < N; ++i) { + if (unlikely(x_bits == values[i].input)) { + UIntType out_bits = values[i].rnd_towardzero_result; + switch (fputil::get_round()) { + case FE_UPWARD: + out_bits += values[i].rnd_upward_offset; + break; + case FE_DOWNWARD: + out_bits += values[i].rnd_downward_offset; + break; + case FE_TONEAREST: + out_bits += values[i].rnd_tonearest_offset; + break; + } + return FPBits(out_bits).get_val(); + } + } + return cpp::nullopt; + } + + constexpr cpp::optional lookup_odd(UIntType x_abs, bool sign) const { + for (size_t i = 0; i < N; ++i) { + if (unlikely(x_abs == values[i].input)) { + UIntType out_bits = values[i].rnd_towardzero_result; switch (fputil::get_round()) { case FE_UPWARD: - out_bits += - sign ? ExceptVals.outputs[i][2] : ExceptVals.outputs[i][1]; + out_bits += sign ? values[i].rnd_downward_offset + : values[i].rnd_upward_offset; break; case FE_DOWNWARD: - out_bits += - sign ? ExceptVals.outputs[i][1] : ExceptVals.outputs[i][2]; + out_bits += sign ? values[i].rnd_upward_offset + : values[i].rnd_downward_offset; break; case FE_TONEAREST: - out_bits += ExceptVals.outputs[i][3]; + out_bits += values[i].rnd_tonearest_offset; break; } - result = FPBits(out_bits).get_val(); + T result = FPBits(out_bits).get_val(); if (sign) result = -result; - return true; + return result; } } - return false; + return cpp::nullopt; } }; diff --git a/libc/src/math/generic/cosf.cpp b/libc/src/math/generic/cosf.cpp index 58f499f..ebccc99 100644 --- a/libc/src/math/generic/cosf.cpp +++ b/libc/src/math/generic/cosf.cpp @@ -20,27 +20,23 @@ namespace __llvm_libc { // Exceptional cases for cosf. -static constexpr int COSF_EXCEPTS = 6; +static constexpr size_t N_EXCEPTS = 6; -static constexpr fputil::ExceptionalValues CosfExcepts{ - /* inputs */ { - 0x55325019, // x = 0x1.64a032p43 - 0x5922aa80, // x = 0x1.4555p51 - 0x5aa4542c, // x = 0x1.48a858p54 - 0x5f18b878, // x = 0x1.3170fp63 - 0x6115cb11, // x = 0x1.2b9622p67 - 0x7beef5ef, // x = 0x1.ddebdep120 - }, - /* outputs (RZ, RU offset, RD offset, RN offset) */ - { - {0x3f4ea5d2, 1, 0, 0}, // x = 0x1.64a032p43, cos(x) = 0x1.9d4ba4p-1 (RZ) - {0x3f08aebe, 1, 0, 1}, // x = 0x1.4555p51, cos(x) = 0x1.115d7cp-1 (RZ) - {0x3efa40a4, 1, 0, 0}, // x = 0x1.48a858p54, cos(x) = 0x1.f48148p-2 (RZ) - {0x3f7f14bb, 1, 0, 0}, // x = 0x1.3170fp63, cos(x) = 0x1.fe2976p-1 (RZ) - {0x3f78142e, 1, 0, 1}, // x = 0x1.2b9622p67, cos(x) = 0x1.f0285cp-1 (RZ) - {0x3f08a21c, 1, 0, - 0}, // x = 0x1.ddebdep120, cos(x) = 0x1.114438p-1 (RZ) - }}; +static constexpr fputil::ExceptValues COSF_EXCEPTS{{ + // (inputs, RZ output, RU offset, RD offset, RN offset) + // x = 0x1.64a032p43, cos(x) = 0x1.9d4ba4p-1 (RZ) + {0x55325019, 0x3f4ea5d2, 1, 0, 0}, + // x = 0x1.4555p51, cos(x) = 0x1.115d7cp-1 (RZ) + {0x5922aa80, 0x3f08aebe, 1, 0, 1}, + // x = 0x1.48a858p54, cos(x) = 0x1.f48148p-2 (RZ) + {0x5aa4542c, 0x3efa40a4, 1, 0, 0}, + // x = 0x1.3170fp63, cos(x) = 0x1.fe2976p-1 (RZ) + {0x5f18b878, 0x3f7f14bb, 1, 0, 0}, + // x = 0x1.2b9622p67, cos(x) = 0x1.f0285cp-1 (RZ) + {0x6115cb11, 0x3f78142e, 1, 0, 1}, + // x = 0x1.ddebdep120, cos(x) = 0x1.114438p-1 (RZ) + {0x7beef5ef, 0x3f08a21c, 1, 0, 0}, +}}; LLVM_LIBC_FUNCTION(float, cosf, (float x)) { using FPBits = typename fputil::FPBits; @@ -110,12 +106,8 @@ LLVM_LIBC_FUNCTION(float, cosf, (float x)) { #endif // LIBC_TARGET_HAS_FMA } - using ExceptChecker = typename fputil::ExceptionChecker; - { - float result; - if (ExceptChecker::check_odd_func(CosfExcepts, x_abs, false, result)) - return result; - } + if (auto r = COSF_EXCEPTS.lookup(x_abs); unlikely(r.has_value())) + return r.value(); // x is inf or nan. if (unlikely(x_abs >= 0x7f80'0000U)) { diff --git a/libc/src/math/generic/tanf.cpp b/libc/src/math/generic/tanf.cpp index 42a2d49..601939a 100644 --- a/libc/src/math/generic/tanf.cpp +++ b/libc/src/math/generic/tanf.cpp @@ -56,29 +56,23 @@ static constexpr double TAN_K_PI_OVER_32[32] = { }; // Exceptional cases for tanf. -static constexpr int TANF_EXCEPTS = 6; - -static constexpr fputil::ExceptionalValues TanfExcepts{ - /* inputs */ { - 0x531d744c, // x = 0x1.3ae898p39 - 0x57d7b0ed, // x = 0x1.af61dap48 - 0x65ee8695, // x = 0x1.dd0d2ap76 - 0x6798fe4f, // x = 0x1.31fc9ep80 - 0x6ad36709, // x = 0x1.a6ce12p86 - 0x72b505bb, // x = 0x1.6a0b76p102 - }, - /* outputs (RZ, RU offset, RD offset, RN offset) */ - { - {0x4591ea1e, 1, 0, 1}, // x = 0x1.3ae898p39, tan(x) = 0x1.23d43cp12 (RZ) - {0x3eb068e3, 1, 0, 1}, // x = 0x1.af61dap48, tan(x) = 0x1.60d1c6p-2 (RZ) - {0xcaa32f8e, 0, 1, - 0}, // x = 0x1.dd0d2ap76, tan(x) = -0x1.465f1cp22 (RZ) - {0x461e09f7, 1, 0, 0}, // x = 0x1.31fc9ep80, tan(x) = 0x1.3c13eep13 (RZ) - {0xbf62b097, 0, 1, - 0}, // x = 0x1.a6ce12p86, tan(x) = -0x1.c5612ep-1 (RZ) - {0xbff2150f, 0, 1, - 0}, // x = 0x1.6a0b76p102, tan(x) = -0x1.e42a1ep0 (RZ) - }}; +static constexpr size_t N_EXCEPTS = 6; + +static constexpr fputil::ExceptValues TANF_EXCEPTS{{ + // (inputs, RZ output, RU offset, RD offset, RN offset) + // x = 0x1.3ae898p39, tan(x) = 0x1.23d43cp12 (RZ) + {0x531d744c, 0x4591ea1e, 1, 0, 1}, + // x = 0x1.af61dap48, tan(x) = 0x1.60d1c6p-2 (RZ) + {0x57d7b0ed, 0x3eb068e3, 1, 0, 1}, + // x = 0x1.dd0d2ap76, tan(x) = -0x1.465f1cp22 (RZ) + {0x65ee8695, 0xcaa32f8e, 0, 1, 0}, + // x = 0x1.31fc9ep80, tan(x) = 0x1.3c13eep13 (RZ) + {0x6798fe4f, 0x461e09f7, 1, 0, 0}, + // x = 0x1.a6ce12p86, tan(x) = -0x1.c5612ep-1 (RZ) + {0x6ad36709, 0xbf62b097, 0, 1, 0}, + // x = 0x1.6a0b76p102, tan(x) = -0x1.e42a1ep0 (RZ) + {0x72b505bb, 0xbff2150f, 0, 1, 0}, +}}; LLVM_LIBC_FUNCTION(float, tanf, (float x)) { using FPBits = typename fputil::FPBits; @@ -200,14 +194,9 @@ LLVM_LIBC_FUNCTION(float, tanf, (float x)) { k = small_range_reduction(xd, y); } else { - using ExceptChecker = - typename fputil::ExceptionChecker; - { - float result; - if (ExceptChecker::check_odd_func(TanfExcepts, x_abs, x_sign <= 0.0, - result)) - return result; - } + if (auto r = TANF_EXCEPTS.lookup_odd(x_abs, x_sign <= 0.0); + unlikely(r.has_value())) + return r.value(); fputil::FPBits x_bits(x_abs); k = large_range_reduction(xd, x_bits.get_exponent(), y); -- 2.7.4