Files
Hoàng Minh Thiên 582643f1ec [libc][math] Adding LIBC_MATH_ASSUME_ROUND_NEAREST_ONLY option (#201154)
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.
2026-06-11 13:42:28 -04:00

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