mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-11-28 16:11:29 +00:00
[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
This commit is contained in:
parent
0caa4a9559
commit
a4d48e3b0b
@ -102,6 +102,7 @@ add_header_library(
|
||||
DEPENDS
|
||||
.fp_bits
|
||||
.fenv_impl
|
||||
libc.src.__support.CPP.optional
|
||||
)
|
||||
|
||||
|
||||
|
@ -11,55 +11,88 @@
|
||||
|
||||
#include "FEnvImpl.h"
|
||||
#include "FPBits.h"
|
||||
#include "src/__support/CPP/optional.h"
|
||||
|
||||
namespace __llvm_libc {
|
||||
|
||||
namespace fputil {
|
||||
|
||||
template <typename T, int N> struct ExceptionalValues {
|
||||
using UIntType = typename FPBits<T>::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<UIntType, N> Excepts {
|
||||
// <list of input bits, output bits and offsets>
|
||||
// };
|
||||
//
|
||||
// Check for exceptional inputs:
|
||||
// if (auto r = Excepts.lookup(x_bits); unlikely(r.has_value()))
|
||||
// return r.value();
|
||||
|
||||
template <typename T, int N> struct ExceptionChecker {
|
||||
using UIntType = typename FPBits<T>::UIntType;
|
||||
using FPBits = FPBits<T>;
|
||||
using ExceptionalValues = ExceptionalValues<T, N>;
|
||||
template <typename T, size_t N> struct ExceptValues {
|
||||
static_assert(cpp::is_floating_point_v<T>, "Must be a floating point type.");
|
||||
|
||||
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
|
||||
using UIntType = typename FPBits<T>::UIntType;
|
||||
|
||||
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<T> 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 +=
|
||||
sign ? ExceptVals.outputs[i][2] : ExceptVals.outputs[i][1];
|
||||
out_bits += values[i].rnd_upward_offset;
|
||||
break;
|
||||
case FE_DOWNWARD:
|
||||
out_bits +=
|
||||
sign ? ExceptVals.outputs[i][1] : ExceptVals.outputs[i][2];
|
||||
out_bits += 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();
|
||||
return FPBits<T>(out_bits).get_val();
|
||||
}
|
||||
}
|
||||
return cpp::nullopt;
|
||||
}
|
||||
|
||||
constexpr cpp::optional<T> 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 ? values[i].rnd_downward_offset
|
||||
: values[i].rnd_upward_offset;
|
||||
break;
|
||||
case FE_DOWNWARD:
|
||||
out_bits += sign ? values[i].rnd_upward_offset
|
||||
: values[i].rnd_downward_offset;
|
||||
break;
|
||||
case FE_TONEAREST:
|
||||
out_bits += values[i].rnd_tonearest_offset;
|
||||
break;
|
||||
}
|
||||
T result = FPBits<T>(out_bits).get_val();
|
||||
if (sign)
|
||||
result = -result;
|
||||
|
||||
return true;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return cpp::nullopt;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -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<float, COSF_EXCEPTS> 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<float, N_EXCEPTS> 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<float>;
|
||||
@ -110,12 +106,8 @@ LLVM_LIBC_FUNCTION(float, cosf, (float x)) {
|
||||
#endif // LIBC_TARGET_HAS_FMA
|
||||
}
|
||||
|
||||
using ExceptChecker = typename fputil::ExceptionChecker<float, COSF_EXCEPTS>;
|
||||
{
|
||||
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)) {
|
||||
|
@ -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 size_t N_EXCEPTS = 6;
|
||||
|
||||
static constexpr fputil::ExceptionalValues<float, TANF_EXCEPTS> 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 fputil::ExceptValues<float, N_EXCEPTS> 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<float>;
|
||||
@ -200,14 +194,9 @@ LLVM_LIBC_FUNCTION(float, tanf, (float x)) {
|
||||
k = small_range_reduction(xd, y);
|
||||
} else {
|
||||
|
||||
using ExceptChecker =
|
||||
typename fputil::ExceptionChecker<float, TANF_EXCEPTS>;
|
||||
{
|
||||
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<float> x_bits(x_abs);
|
||||
k = large_range_reduction(xd, x_bits.get_exponent(), y);
|
||||
|
Loading…
Reference in New Issue
Block a user