This PR adds a new option ~~`LIBC_MATH_ALWAYS_ROUND_NEAREST`~~ `LIBC_MATH_ASSUME_ROUND_NEAREST_ONLY` to LLVM libm. There are some UBs that I kept as-is from the original code to keep the changes non-disruptive (which I've marked with TODO comments) Benchmarks (from `files.zip` in the comment https://github.com/llvm/llvm-project/issues/198276#issue-4468816457): - System libm: ``` overflow (>710) 1.55 ns/call (644M ops/sec) underflow to 0 (<-746) 1.34 ns/call (747M ops/sec) normal [-10,10] 4.41 ns/call (227M ops/sec) denormals [-740,-735] 2.25 ns/call (444M ops/sec) near-uflow [-700,-690] 2.25 ns/call (444M ops/sec) ``` - LLVM libm (without the option being set): ``` overflow (>710) 5.21 ns/call (192M ops/sec) underflow to 0 (<-746) 7.20 ns/call (139M ops/sec) normal [-10,10] 4.06 ns/call (246M ops/sec) denormals [-740,-735] 5.85 ns/call (171M ops/sec) near-uflow [-700,-690] 4.06 ns/call (246M ops/sec) ``` - LLVM libm (with the option being **set**, `bench-exp-paths-inc.cc`) ``` overflow (>710) 1.95 ns/call (514M ops/sec) underflow to 0 (<-746) 2.23 ns/call (449M ops/sec) normal [-10,10] 3.43 ns/call (292M ops/sec) denormals [-740,-735] 5.19 ns/call (193M ops/sec) near-uflow [-700,-690] 3.43 ns/call (292M ops/sec) ``` Notice that in the `bench-exp-paths-inc.cc` file, I've changed the option name from `LIBC_MATH_ROUND_NEAREST` to `LIBC_MATH_ASSUME_ROUND_NEAREST_ONLY` Benchmark system: macOS 26.5, Apple M3.
63 lines
1.7 KiB
C++
63 lines
1.7 KiB
C++
//===-- RoundingModeUtils.cpp ---------------------------------------------===//
|
|
//
|
|
// 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#undef LIBC_MATH_USE_SYSTEM_FENV
|
|
|
|
#include "RoundingModeUtils.h"
|
|
#include "src/__support/FPUtil/FEnvImpl.h"
|
|
#include "src/__support/FPUtil/rounding_mode.h"
|
|
|
|
#include "hdr/fenv_macros.h"
|
|
#include "src/__support/macros/config.h"
|
|
|
|
namespace LIBC_NAMESPACE_DECL {
|
|
namespace fputil {
|
|
namespace testing {
|
|
|
|
int get_fe_rounding(RoundingMode mode) {
|
|
switch (mode) {
|
|
case RoundingMode::Upward:
|
|
return FE_UPWARD;
|
|
case RoundingMode::Downward:
|
|
return FE_DOWNWARD;
|
|
case RoundingMode::TowardZero:
|
|
return FE_TOWARDZERO;
|
|
case RoundingMode::Nearest:
|
|
return FE_TONEAREST;
|
|
}
|
|
__builtin_unreachable();
|
|
}
|
|
|
|
ForceRoundingMode::ForceRoundingMode(RoundingMode mode) {
|
|
#ifdef LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY
|
|
old_rounding_mode = FE_TONEAREST;
|
|
rounding_mode = FE_TONEAREST;
|
|
success = (mode == RoundingMode::Nearest);
|
|
#else
|
|
old_rounding_mode = quick_get_round();
|
|
rounding_mode = get_fe_rounding(mode);
|
|
if (old_rounding_mode != rounding_mode) {
|
|
int status = set_round(rounding_mode);
|
|
success = (status == 0);
|
|
} else {
|
|
success = true;
|
|
}
|
|
#endif // LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY
|
|
}
|
|
|
|
ForceRoundingMode::~ForceRoundingMode() {
|
|
#ifndef LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY
|
|
if (old_rounding_mode != rounding_mode)
|
|
set_round(old_rounding_mode);
|
|
#endif
|
|
}
|
|
|
|
} // namespace testing
|
|
} // namespace fputil
|
|
} // namespace LIBC_NAMESPACE_DECL
|