diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt --- a/libc/config/linux/aarch64/entrypoints.txt +++ b/libc/config/linux/aarch64/entrypoints.txt @@ -62,7 +62,10 @@ set(TARGET_LIBM_ENTRYPOINTS # fenv.h entrypoints libc.src.fenv.feclearexcept + libc.src.fenv.fedisableexcept + libc.src.fenv.feenableexcept libc.src.fenv.fegetenv + libc.src.fenv.fegetexcept libc.src.fenv.fegetexceptflag libc.src.fenv.fegetround libc.src.fenv.feholdexcept diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt --- a/libc/config/linux/x86_64/entrypoints.txt +++ b/libc/config/linux/x86_64/entrypoints.txt @@ -62,7 +62,10 @@ set(TARGET_LIBM_ENTRYPOINTS # fenv.h entrypoints libc.src.fenv.feclearexcept + libc.src.fenv.fedisableexcept + libc.src.fenv.feenableexcept libc.src.fenv.fegetenv + libc.src.fenv.fegetexcept libc.src.fenv.fegetexceptflag libc.src.fenv.fegetround libc.src.fenv.feholdexcept diff --git a/libc/spec/gnu_ext.td b/libc/spec/gnu_ext.td --- a/libc/spec/gnu_ext.td +++ b/libc/spec/gnu_ext.td @@ -41,9 +41,33 @@ ] >; + HeaderSpec FEnv = HeaderSpec< + "fenv.h", + [], // Macros + [], // Types + [], // Enumerations + [ + FunctionSpec< + "fedisableexcept", + RetValSpec, + [ArgSpec] + >, + FunctionSpec< + "feenableexcept", + RetValSpec, + [ArgSpec] + >, + FunctionSpec< + "fegetexcept", + RetValSpec, + [] + > + ] + >; let Headers = [ CType, + FEnv, Math, String, ]; diff --git a/libc/src/fenv/CMakeLists.txt b/libc/src/fenv/CMakeLists.txt --- a/libc/src/fenv/CMakeLists.txt +++ b/libc/src/fenv/CMakeLists.txt @@ -140,3 +140,42 @@ COMPILE_OPTIONS -O2 ) + +add_entrypoint_object( + feenableexcept + SRCS + feenableexcept.cpp + HDRS + feenableexcept.h + DEPENDS + libc.include.fenv + libc.src.__support.FPUtil.fputil + COMPILE_OPTIONS + -O2 +) + +add_entrypoint_object( + fedisableexcept + SRCS + fedisableexcept.cpp + HDRS + fedisableexcept.h + DEPENDS + libc.include.fenv + libc.src.__support.FPUtil.fputil + COMPILE_OPTIONS + -O2 +) + +add_entrypoint_object( + fegetexcept + SRCS + fegetexcept.cpp + HDRS + fegetexcept.h + DEPENDS + libc.include.fenv + libc.src.__support.FPUtil.fputil + COMPILE_OPTIONS + -O2 +) diff --git a/libc/src/fenv/fedisableexcept.h b/libc/src/fenv/fedisableexcept.h new file mode 100644 --- /dev/null +++ b/libc/src/fenv/fedisableexcept.h @@ -0,0 +1,18 @@ +//===-- Implementation header for fedisableexcept ---------------*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC_FENV_FEDISABLEEXCEPT_H +#define LLVM_LIBC_SRC_FENV_FEDISABLEEXCEPT_H + +namespace __llvm_libc { + +int fedisableexcept(int); + +} // namespace __llvm_libc + +#endif // LLVM_LIBC_SRC_FENV_FEDISABLEEXCEPT_H diff --git a/libc/src/fenv/fedisableexcept.cpp b/libc/src/fenv/fedisableexcept.cpp new file mode 100644 --- /dev/null +++ b/libc/src/fenv/fedisableexcept.cpp @@ -0,0 +1,19 @@ +//===-- Implementation of fedisableexcept function ------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "src/fenv/fedisableexcept.h" +#include "src/__support/FPUtil/FEnvUtils.h" +#include "src/__support/common.h" + +namespace __llvm_libc { + +LLVM_LIBC_FUNCTION(int, fedisableexcept, (int e)) { + return fputil::disableExcept(e); +} + +} // namespace __llvm_libc diff --git a/libc/src/fenv/feenableexcept.h b/libc/src/fenv/feenableexcept.h new file mode 100644 --- /dev/null +++ b/libc/src/fenv/feenableexcept.h @@ -0,0 +1,18 @@ +//===-- Implementation header for feenableexcept ----------------*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC_FENV_FEENABLEEXCEPT_H +#define LLVM_LIBC_SRC_FENV_FEENABLEEXCEPT_H + +namespace __llvm_libc { + +int feenableexcept(int); + +} // namespace __llvm_libc + +#endif // LLVM_LIBC_SRC_FENV_FEENABLEEXCEPT_H diff --git a/libc/src/fenv/feenableexcept.cpp b/libc/src/fenv/feenableexcept.cpp new file mode 100644 --- /dev/null +++ b/libc/src/fenv/feenableexcept.cpp @@ -0,0 +1,19 @@ +//===-- Implementation of feenableexcept function -------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "src/fenv/feenableexcept.h" +#include "src/__support/FPUtil/FEnvUtils.h" +#include "src/__support/common.h" + +namespace __llvm_libc { + +LLVM_LIBC_FUNCTION(int, feenableexcept, (int e)) { + return fputil::enableExcept(e); +} + +} // namespace __llvm_libc diff --git a/libc/src/fenv/fegetexcept.h b/libc/src/fenv/fegetexcept.h new file mode 100644 --- /dev/null +++ b/libc/src/fenv/fegetexcept.h @@ -0,0 +1,18 @@ +//===-- Implementation header for fegetexcept -------------------*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC_FENV_FEGETEXCEPT_H +#define LLVM_LIBC_SRC_FENV_FEGETEXCEPT_H + +namespace __llvm_libc { + +int fegetexcept(); + +} // namespace __llvm_libc + +#endif // LLVM_LIBC_SRC_FENV_FEGETEXCEPT_H diff --git a/libc/src/fenv/fegetexcept.cpp b/libc/src/fenv/fegetexcept.cpp new file mode 100644 --- /dev/null +++ b/libc/src/fenv/fegetexcept.cpp @@ -0,0 +1,17 @@ +//===-- Implementation of fegetexcept function ----------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "src/fenv/fegetexcept.h" +#include "src/__support/FPUtil/FEnvUtils.h" +#include "src/__support/common.h" + +namespace __llvm_libc { + +LLVM_LIBC_FUNCTION(int, fegetexcept, ()) { return fputil::getExcept(); } + +} // namespace __llvm_libc diff --git a/libc/test/src/fenv/CMakeLists.txt b/libc/test/src/fenv/CMakeLists.txt --- a/libc/test/src/fenv/CMakeLists.txt +++ b/libc/test/src/fenv/CMakeLists.txt @@ -71,6 +71,18 @@ libc.src.__support.FPUtil.fputil ) +add_libc_unittest( + feenableexcept_test + SUITE + libc_fenv_unittests + SRCS + feenableexcept_test.cpp + DEPENDS + libc.src.fenv.fedisableexcept + libc.src.fenv.feenableexcept + libc.src.fenv.fegetexcept +) + if (NOT (LLVM_USE_SANITIZER OR (${LIBC_TARGET_OS} STREQUAL "windows"))) # Sanitizers don't like SIGFPE. So, we will run the # tests which raise SIGFPE only in non-sanitizer builds. diff --git a/libc/test/src/fenv/feenableexcept_test.cpp b/libc/test/src/fenv/feenableexcept_test.cpp new file mode 100644 --- /dev/null +++ b/libc/test/src/fenv/feenableexcept_test.cpp @@ -0,0 +1,86 @@ +//===-- Unittests for feenableexcept -------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "src/fenv/fedisableexcept.h" +#include "src/fenv/feenableexcept.h" +#include "src/fenv/fegetexcept.h" + +#include "utils/UnitTest/Test.h" + +#include + +TEST(LlvmLibcFEnvTest, EnableTest) { +#ifdef __aarch64__ + // Few aarch64 HW implementations do not trap exceptions. We skip this test + // completely on such HW. + // + // Whether HW supports trapping exceptions or not is deduced by enabling an + // exception and reading back to see if the exception got enabled. If the + // exception did not get enabled, then it means that the HW does not support + // trapping exceptions. + __llvm_libc::fedisableexcept(FE_ALL_EXCEPT); + __llvm_libc::feenableexcept(FE_DIVBYZERO); + if (__llvm_libc::fegetexcept() == 0) + return; +#endif + + int excepts[] = {FE_DIVBYZERO, FE_INVALID, FE_INEXACT, FE_OVERFLOW, + FE_UNDERFLOW}; + __llvm_libc::fedisableexcept(FE_ALL_EXCEPT); + ASSERT_EQ(0, __llvm_libc::fegetexcept()); + + for (int e : excepts) { + __llvm_libc::feenableexcept(e); + ASSERT_EQ(e, __llvm_libc::fegetexcept()); + __llvm_libc::fedisableexcept(e); + } + + for (int e1 : excepts) { + for (int e2 : excepts) { + __llvm_libc::feenableexcept(e1 | e2); + ASSERT_EQ(e1 | e2, __llvm_libc::fegetexcept()); + __llvm_libc::fedisableexcept(e1 | e2); + } + } + + for (int e1 : excepts) { + for (int e2 : excepts) { + for (int e3 : excepts) { + __llvm_libc::feenableexcept(e1 | e2 | e3); + ASSERT_EQ(e1 | e2 | e3, __llvm_libc::fegetexcept()); + __llvm_libc::fedisableexcept(e1 | e2 | e3); + } + } + } + + for (int e1 : excepts) { + for (int e2 : excepts) { + for (int e3 : excepts) { + for (int e4 : excepts) { + __llvm_libc::feenableexcept(e1 | e2 | e3 | e4); + ASSERT_EQ(e1 | e2 | e3 | e4, __llvm_libc::fegetexcept()); + __llvm_libc::fedisableexcept(e1 | e2 | e3 | e4); + } + } + } + } + + for (int e1 : excepts) { + for (int e2 : excepts) { + for (int e3 : excepts) { + for (int e4 : excepts) { + for (int e5 : excepts) { + __llvm_libc::feenableexcept(e1 | e2 | e3 | e4 | e5); + ASSERT_EQ(e1 | e2 | e3 | e4 | e5, __llvm_libc::fegetexcept()); + __llvm_libc::fedisableexcept(e1 | e2 | e3 | e4 | e5); + } + } + } + } + } +}