Skip to content

Commit 67b6be6

Browse files
committed
- Address comment.
- Add trap on raise fp except option that will match glibc's behavior. - Fix bazel build.
1 parent 89dd2e4 commit 67b6be6

File tree

9 files changed

+63
-22
lines changed

9 files changed

+63
-22
lines changed

libc/cmake/modules/LLVMLibCCompileOptionRules.cmake

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,10 @@ function(_get_compile_options_from_config output_var)
116116
list(APPEND config_options "-DLIBC_THREAD_MODE=${LIBC_CONF_THREAD_MODE}")
117117
endif()
118118

119+
if(LIBC_CONF_TRAP_ON_RAISE_FP_EXCEPT)
120+
list(APPEND config_options "-DLIBC_TRAP_ON_RAISE_FP_EXCEPT")
121+
endif()
122+
119123
set(${output_var} ${config_options} PARENT_SCOPE)
120124
endfunction(_get_compile_options_from_config)
121125

libc/config/config.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,5 +130,11 @@
130130
"value": true,
131131
"doc": "Add nullptr checks in the library's implementations to some functions for which passing nullptr is undefined behavior."
132132
}
133+
},
134+
"fenv": {
135+
"LIBC_CONF_TRAP_ON_RAISE_FP_EXCEPT": {
136+
"value": false,
137+
"doc": "Trap with SIGFPE when feraiseexcept is called with unmasked floating point exceptions, similar to glibc's behavior. This is currently working only on x86 with SSE."
138+
}
133139
}
134140
}

libc/docs/configure.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ to learn about the defaults for your platform and target.
3030
- ``LIBC_CONF_KEEP_FRAME_POINTER``: Keep frame pointer in functions for better debugging experience.
3131
* **"errno" options**
3232
- ``LIBC_CONF_ERRNO_MODE``: The implementation used for errno, acceptable values are LIBC_ERRNO_MODE_DEFAULT, LIBC_ERRNO_MODE_UNDEFINED, LIBC_ERRNO_MODE_THREAD_LOCAL, LIBC_ERRNO_MODE_SHARED, LIBC_ERRNO_MODE_EXTERNAL, and LIBC_ERRNO_MODE_SYSTEM_INLINE.
33+
* **"fenv" options**
34+
- ``LIBC_CONF_TRAP_ON_RAISE_FP_EXCEPT``: Trap with SIGFPE when feraiseexcept is called with unmasked floating point exceptions, similar to glibc's behavior. This is currently working only on x86 with SSE.
3335
* **"general" options**
3436
- ``LIBC_ADD_NULL_CHECKS``: Add nullptr checks in the library's implementations to some functions for which passing nullptr is undefined behavior.
3537
* **"math" options**

libc/src/__support/FPUtil/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ add_header_library(
77
libc.hdr.fenv_macros
88
libc.hdr.math_macros
99
libc.hdr.stdint_proxy
10+
libc.src.__support.CPP.bit
1011
libc.src.__support.CPP.type_traits
1112
libc.src.__support.macros.attributes
1213
libc.src.errno.errno

libc/src/__support/FPUtil/x86_64/FEnvImpl.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ LIBC_INLINE static int get_env(fenv_t *env) {
179179
return 0;
180180
}
181181

182-
LIBC_INLINE int set_env(const fenv_t *env) {
182+
LIBC_INLINE static int set_env(const fenv_t *env) {
183183
if (env == FE_DFL_ENV) {
184184
#ifndef LIBC_COMPILER_IS_MSVC
185185
x87::initialize_x87_state();

libc/src/__support/FPUtil/x86_64/fenv_mxcsr_utils.h

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
#include "hdr/stdint_proxy.h"
1313
#include "hdr/types/fenv_t.h"
14+
#include "src/__support/CPP/bit.h"
1415
#include "src/__support/FPUtil/x86_64/fenv_x86_common.h"
1516
#include "src/__support/macros/attributes.h" // LIBC_INLINE
1617
#include "src/__support/macros/config.h"
@@ -85,6 +86,40 @@ LIBC_INLINE static void raise_except(uint16_t excepts) {
8586
uint32_t mxcsr = _MM_GET_EXCEPTION_STATE();
8687
mxcsr |= excepts;
8788
_MM_SET_EXCEPTION_STATE(mxcsr);
89+
#ifdef LIBC_TRAP_ON_RAISE_FP_EXCEPT
90+
// We will try to trigger the SIGFPE if floating point exceptions are not
91+
// masked. Since we already set all the floating point exception flags, we
92+
// only need to trigger the trap on one of them.
93+
static constexpr float EXCEPTION_INPUTS[6][2] = {
94+
// FE_INVALID: 0.0 * inf
95+
{0.0f, cpp::bit_cast<float>(0x7f80'0000U)},
96+
// FE_DENORM: 1.0 * 0x1.0p-128
97+
{1.0f, 0x1.0p-128f},
98+
// FE_DIVBYZERO: 1.0 / 0.0
99+
{1.0f, 0.0f},
100+
// FE_OVERFLOW: 0x1.0p127 * 0x1.0p127
101+
{0x1.0p127f, 0x1.0p127f},
102+
// FE_UNDERFLOW: 0x1.0p-126 * 0x1.0p-126
103+
{0x1.0p-126f, 0x1.0p-126f},
104+
// FE_INEXACT: (1 + 2^-12) * (1 + 2^-12)
105+
{0x1.001p0f, 0x1.001p0f}};
106+
107+
uint32_t except_masks =
108+
(~(get_mxcsr() >> ExceptionFlags::MXCSR_EXCEPTION_MASK_BIT_POSITION)) &
109+
excepts;
110+
if (except_masks) {
111+
int idx = cpp::countr_zero(except_masks);
112+
if (idx == 2) {
113+
// FE_DIVBYZERO, we need floating point division operations.
114+
[[maybe_unused]] volatile float z = EXCEPTION_INPUTS[idx][0];
115+
z /= EXCEPTION_INPUTS[idx][1];
116+
} else {
117+
// For the remaining exceptions, we floating point multiplications.
118+
[[maybe_unused]] volatile float z = EXCEPTION_INPUTS[idx][0];
119+
z *= EXCEPTION_INPUTS[idx][1];
120+
}
121+
}
122+
#endif // LIBC_TRAP_ON_RAISE_FP_EXCEPT
88123
}
89124

90125
LIBC_INLINE static uint16_t enable_except(uint16_t excepts) {

libc/src/__support/FPUtil/x86_64/fenv_x86_common.h

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
#ifndef LLVM_LIBC_SRC___SUPPORT_FPUTIL_X86_64_FENV_X86_COMMON_H
1010
#define LLVM_LIBC_SRC___SUPPORT_FPUTIL_X86_64_FENV_X86_COMMON_H
1111

12+
#include <stdbool.h>
13+
1214
#include "hdr/stdint_proxy.h"
1315
#include "hdr/types/fenv_t.h"
1416
#include "src/__support/macros/attributes.h"
@@ -23,12 +25,12 @@ namespace fputil {
2325
namespace internal {
2426

2527
// Default order of floating point exception flags in x87 and mxcsr registers:
26-
// - Bit 1: Invalid Operations
27-
// - Bit 2: Denormal
28-
// - Bit 3: Divide-by-zero
29-
// - Bit 4: Overflow
30-
// - Bit 5: Underflow
31-
// - Bit 6: Inexact
28+
// - Bit 0: Invalid Operations
29+
// - Bit 1: Denormal
30+
// - Bit 2: Divide-by-zero
31+
// - Bit 3: Overflow
32+
// - Bit 4: Underflow
33+
// - Bit 5: Inexact
3234
struct ExceptionFlags {
3335
static constexpr uint16_t INVALID_F = 0x1;
3436
// Some libcs define __FE_DENORM corresponding to the denormal input

libc/test/src/fenv/enabled_exceptions_test.cpp

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -26,21 +26,6 @@ using LlvmLibcExceptionStatusTest = LIBC_NAMESPACE::testing::FEnvSafeTest;
2626
// This test enables an exception and verifies that raising that exception
2727
// triggers SIGFPE.
2828
TEST_F(LlvmLibcExceptionStatusTest, RaiseAndCrash) {
29-
#if defined(LIBC_TARGET_ARCH_IS_ANY_ARM) || \
30-
defined(LIBC_TARGET_ARCH_IS_ANY_RISCV)
31-
// Few Arm HW implementations do not trap exceptions. We skip this test
32-
// completely on such HW.
33-
//
34-
// Whether HW supports trapping exceptions or not is deduced by enabling an
35-
// exception and reading back to see if the exception got enabled. If the
36-
// exception did not get enabled, then it means that the HW does not support
37-
// trapping exceptions.
38-
LIBC_NAMESPACE::fputil::disable_except(FE_ALL_EXCEPT);
39-
LIBC_NAMESPACE::fputil::enable_except(FE_DIVBYZERO);
40-
if (LIBC_NAMESPACE::fputil::get_except() == 0)
41-
return;
42-
#endif // Architectures where exception trapping is not supported
43-
4429
// TODO: Install a floating point exception handler and verify that the
4530
// the expected exception was raised. One will have to longjmp back from
4631
// that exception handler, so such a testing can be done after we have
@@ -61,6 +46,7 @@ TEST_F(LlvmLibcExceptionStatusTest, RaiseAndCrash) {
6146
ASSERT_EQ(LIBC_NAMESPACE::fetestexcept(others), others);
6247
}
6348

49+
#if defined(LIBC_TRAP_ON_RAISE_FP_EXCEPT) && defined(__SSE__)
6450
ASSERT_RAISES_FP_EXCEPT([=] {
6551
// In test frameworks like Fuchsia's zxtest, this translates to
6652
// a death test which runs this closure in a different thread. So,
@@ -69,6 +55,7 @@ TEST_F(LlvmLibcExceptionStatusTest, RaiseAndCrash) {
6955
LIBC_NAMESPACE::fputil::enable_except(e);
7056
LIBC_NAMESPACE::feraiseexcept(e);
7157
});
58+
#endif // LIBC_TRAP_ON_RAISE_FP_EXCEPT
7259

7360
// Cleanup.
7461
LIBC_NAMESPACE::fputil::disable_except(FE_ALL_EXCEPT);

utils/bazel/llvm-project-overlay/libc/BUILD.bazel

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1225,6 +1225,10 @@ libc_support_library(
12251225
name = "__support_fputil_fenv_impl",
12261226
hdrs = ["src/__support/FPUtil/FEnvImpl.h"],
12271227
textual_hdrs = [
1228+
"src/__support/FPUtil/x86_64/fenv_mxcsr_utils.h",
1229+
"src/__support/FPUtil/x86_64/fenv_x86_common.h",
1230+
"src/__support/FPUtil/x86_64/fenv_x87_only.h",
1231+
"src/__support/FPUtil/x86_64/fenv_x87_utils.h",
12281232
"src/__support/FPUtil/x86_64/FEnvImpl.h",
12291233
"src/__support/FPUtil/aarch64/FEnvImpl.h",
12301234
"src/__support/FPUtil/aarch64/fenv_darwin_impl.h",

0 commit comments

Comments
 (0)