[libc-commits] [libc] 6f8dfee - [libc] Add riscv64 fenv implementation and enable the fenv.h functions.
Mikhail R. Gadelha via libc-commits
libc-commits at lists.llvm.org
Wed Mar 8 05:49:59 PST 2023
Author: Siva Chandra
Date: 2023-03-08T10:49:24-03:00
New Revision: 6f8dfeee06cf97d253bd278357ef26c0a2c9c1e2
URL: https://github.com/llvm/llvm-project/commit/6f8dfeee06cf97d253bd278357ef26c0a2c9c1e2
DIFF: https://github.com/llvm/llvm-project/commit/6f8dfeee06cf97d253bd278357ef26c0a2c9c1e2.diff
LOG: [libc] Add riscv64 fenv implementation and enable the fenv.h functions.
Reviewed By: mikhail.ramalho
Differential Revision: https://reviews.llvm.org/D145560
Added:
libc/src/__support/FPUtil/riscv64/FEnvImpl.h
Modified:
libc/config/linux/riscv64/entrypoints.txt
libc/src/__support/FPUtil/FEnvImpl.h
libc/test/src/fenv/enabled_exceptions_test.cpp
libc/test/src/fenv/feenableexcept_test.cpp
libc/test/src/fenv/feholdexcept_test.cpp
Removed:
################################################################################
diff --git a/libc/config/linux/riscv64/entrypoints.txt b/libc/config/linux/riscv64/entrypoints.txt
index de901a7a95500..cc052f9b41d2f 100644
--- a/libc/config/linux/riscv64/entrypoints.txt
+++ b/libc/config/linux/riscv64/entrypoints.txt
@@ -189,6 +189,22 @@ set(TARGET_LIBC_ENTRYPOINTS
)
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
+ libc.src.fenv.fesetenv
+ libc.src.fenv.fesetexceptflag
+ libc.src.fenv.fesetround
+ libc.src.fenv.feraiseexcept
+ libc.src.fenv.fetestexcept
+ libc.src.fenv.feupdateenv
+
# math.h entrypoints
libc.src.math.fabs
libc.src.math.fabsf
diff --git a/libc/src/__support/FPUtil/FEnvImpl.h b/libc/src/__support/FPUtil/FEnvImpl.h
index ec21555071c86..43980a87afc64 100644
--- a/libc/src/__support/FPUtil/FEnvImpl.h
+++ b/libc/src/__support/FPUtil/FEnvImpl.h
@@ -30,6 +30,8 @@
#include "x86_64/FEnvImpl.h"
#elif defined(LIBC_TARGET_ARCH_IS_ARM)
#include "arm/FEnvImpl.h"
+#elif defined(LIBC_TARGET_ARCH_IS_RISCV64)
+#include "riscv64/FEnvImpl.h"
#else
namespace __llvm_libc::fputil {
diff --git a/libc/src/__support/FPUtil/riscv64/FEnvImpl.h b/libc/src/__support/FPUtil/riscv64/FEnvImpl.h
new file mode 100644
index 0000000000000..b4c11443b798a
--- /dev/null
+++ b/libc/src/__support/FPUtil/riscv64/FEnvImpl.h
@@ -0,0 +1,180 @@
+//===-- riscv64 floating point env manipulation functions -------*- 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_SUPPORT_FPUTIL_RISCV64_FENVIMPL_H
+#define LLVM_LIBC_SRC_SUPPORT_FPUTIL_RISCV64_FENVIMPL_H
+
+#include "src/__support/FPUtil/FPBits.h"
+#include "src/__support/macros/attributes.h" // For LIBC_INLINE_ASM
+#include "src/__support/macros/config.h" // For LIBC_INLINE
+
+#include <fenv.h>
+#include <stdint.h>
+
+namespace __llvm_libc {
+namespace fputil {
+
+struct FEnv {
+ // We will ignore RMM and DYN rounding modes.
+ static constexpr uint32_t TONEAREST = 0x0;
+ static constexpr uint32_t TOWARDZERO = 0x1;
+ static constexpr uint32_t DOWNWARD = 0x2;
+ static constexpr uint32_t UPWARD = 0x3;
+
+ // These are the bit locations of the corresponding exceptions in fcsr.
+ static constexpr uint32_t INEXACT = 0x1;
+ static constexpr uint32_t UNDERFLOW = 0x2;
+ static constexpr uint32_t OVERFLOW = 0x4;
+ static constexpr uint32_t DIVBYZERO = 0x8;
+ static constexpr uint32_t INVALID = 0x10;
+
+ LIBC_INLINE static uint32_t get_frm() {
+ unsigned int rm;
+ LIBC_INLINE_ASM("frrm %0\n\t" : "=r"(rm));
+ return rm;
+ }
+
+ LIBC_INLINE static void set_frm(uint32_t rm) {
+ LIBC_INLINE_ASM("fsrm %0, %0\n\t" : "+r"(rm));
+ }
+
+ LIBC_INLINE static uint32_t get_fflags() {
+ unsigned int flags;
+ LIBC_INLINE_ASM("frflags %0\n\t" : "=r"(flags));
+ return flags;
+ }
+
+ LIBC_INLINE static void set_fflags(uint32_t flags) {
+ LIBC_INLINE_ASM("fsflags %0, %0\n\t" : "+r"(flags));
+ }
+
+ LIBC_INLINE static uint32_t get_fcsr() {
+ unsigned int fcsr;
+ LIBC_INLINE_ASM("frcsr %0\n\t" : "=r"(fcsr));
+ return fcsr;
+ }
+
+ LIBC_INLINE static void set_fcsr(uint32_t fcsr) {
+ LIBC_INLINE_ASM("fscsr %0, %0\n\t" : "+r"(fcsr));
+ }
+
+ LIBC_INLINE static int exception_bits_to_macro(uint32_t status) {
+ return (status & INVALID ? FE_INVALID : 0) |
+ (status & DIVBYZERO ? FE_DIVBYZERO : 0) |
+ (status & OVERFLOW ? FE_OVERFLOW : 0) |
+ (status & UNDERFLOW ? FE_UNDERFLOW : 0) |
+ (status & INEXACT ? FE_INEXACT : 0);
+ }
+
+ LIBC_INLINE static uint32_t exception_macro_to_bits(int except) {
+ return (except & FE_INVALID ? INVALID : 0) |
+ (except & FE_DIVBYZERO ? DIVBYZERO : 0) |
+ (except & FE_OVERFLOW ? OVERFLOW : 0) |
+ (except & FE_UNDERFLOW ? UNDERFLOW : 0) |
+ (except & FE_INEXACT ? INEXACT : 0);
+ }
+};
+
+// Since RISCV does not have exception enable bits, we will just return
+// the failure indicator.
+LIBC_INLINE int enable_except(int) { return -1; }
+
+// Always succeed.
+LIBC_INLINE int disable_except(int) { return 0; }
+
+// Always return "no exceptions enabled".
+LIBC_INLINE int get_except() { return 0; }
+
+LIBC_INLINE int clear_except(int excepts) {
+ uint32_t flags = FEnv::get_fflags();
+ uint32_t to_clear = FEnv::exception_macro_to_bits(excepts);
+ flags &= ~to_clear;
+ FEnv::set_fflags(flags);
+ return 0;
+}
+
+LIBC_INLINE int test_except(int excepts) {
+ uint32_t to_test = FEnv::exception_macro_to_bits(excepts);
+ uint32_t flags = FEnv::get_fflags();
+ return FEnv::exception_bits_to_macro(flags & to_test);
+}
+
+LIBC_INLINE int set_except(int excepts) {
+ uint32_t flags = FEnv::get_fflags();
+ FEnv::set_fflags(flags | FEnv::exception_macro_to_bits(excepts));
+ return 0;
+}
+
+LIBC_INLINE int raise_except(int excepts) {
+ // Since there are no traps, we just set the exception flags.
+ uint32_t flags = FEnv::get_fflags();
+ FEnv::set_fflags(flags | FEnv::exception_macro_to_bits(excepts));
+ return 0;
+}
+
+LIBC_INLINE int get_round() {
+ uint32_t rm = FEnv::get_frm();
+ switch (rm) {
+ case FEnv::TONEAREST:
+ return FE_TONEAREST;
+ case FEnv::DOWNWARD:
+ return FE_DOWNWARD;
+ case FEnv::UPWARD:
+ return FE_UPWARD;
+ case FEnv::TOWARDZERO:
+ return FE_TOWARDZERO;
+ default:
+ return -1; // Error value.
+ }
+ return 0;
+}
+
+LIBC_INLINE int set_round(int mode) {
+ uint32_t rm;
+ switch (mode) {
+ case FE_TONEAREST:
+ rm = FEnv::TONEAREST;
+ break;
+ case FE_DOWNWARD:
+ rm = FEnv::DOWNWARD;
+ break;
+ case FE_UPWARD:
+ rm = FEnv::UPWARD;
+ break;
+ case FE_TOWARDZERO:
+ rm = FEnv::TOWARDZERO;
+ break;
+ default:
+ return -1; // To indicate failure
+ }
+ FEnv::set_frm(rm);
+ return 0;
+}
+
+LIBC_INLINE int get_env(fenv_t *envp) {
+ uint32_t *state = reinterpret_cast<uint32_t *>(envp);
+ *state = FEnv::get_fcsr();
+ return 0;
+}
+
+LIBC_INLINE int set_env(const fenv_t *envp) {
+ if (envp == FE_DFL_ENV) {
+ FEnv::set_frm(FEnv::TONEAREST);
+ FEnv::set_fflags(0);
+ return 0;
+ }
+ uint32_t status = *reinterpret_cast<const uint32_t *>(envp);
+ // We have to do the masking to preserve the reserved bits.
+ FEnv::set_fcsr((status & 0xFF) | (FEnv::get_fcsr() & 0xFFFFFF00));
+ return 0;
+}
+
+} // namespace fputil
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_SUPPORT_FPUTIL_RISCV64_FENVIMPL_H
diff --git a/libc/test/src/fenv/enabled_exceptions_test.cpp b/libc/test/src/fenv/enabled_exceptions_test.cpp
index fb389d0db62c2..bb0c572da7541 100644
--- a/libc/test/src/fenv/enabled_exceptions_test.cpp
+++ b/libc/test/src/fenv/enabled_exceptions_test.cpp
@@ -21,7 +21,7 @@
// This test enables an exception and verifies that raising that exception
// triggers SIGFPE.
TEST(LlvmLibcExceptionStatusTest, RaiseAndCrash) {
-#if defined(LIBC_TARGET_ARCH_IS_ANY_ARM)
+#if defined(LIBC_TARGET_ARCH_IS_ANY_ARM) || defined(LIBC_TARGET_ARCH_IS_RISCV64)
// Few Arm HW implementations do not trap exceptions. We skip this test
// completely on such HW.
//
@@ -33,7 +33,7 @@ TEST(LlvmLibcExceptionStatusTest, RaiseAndCrash) {
__llvm_libc::fputil::enable_except(FE_DIVBYZERO);
if (__llvm_libc::fputil::get_except() == 0)
return;
-#endif // defined(LIBC_TARGET_ARCH_IS_ANY_ARM)
+#endif // Architectures where exception trapping is not supported
// TODO: Install a floating point exception handler and verify that the
// the expected exception was raised. One will have to longjmp back from
diff --git a/libc/test/src/fenv/feenableexcept_test.cpp b/libc/test/src/fenv/feenableexcept_test.cpp
index d4a2c6e216af5..c27a2bff6a038 100644
--- a/libc/test/src/fenv/feenableexcept_test.cpp
+++ b/libc/test/src/fenv/feenableexcept_test.cpp
@@ -16,7 +16,7 @@
#include <fenv.h>
TEST(LlvmLibcFEnvTest, EnableTest) {
-#if defined(LIBC_TARGET_ARCH_IS_ANY_ARM)
+#if defined(LIBC_TARGET_ARCH_IS_ANY_ARM) || defined(LIBC_TARGET_ARCH_IS_RISCV64)
// Few Arm HW implementations do not trap exceptions. We skip this test
// completely on such HW.
//
@@ -28,7 +28,7 @@ TEST(LlvmLibcFEnvTest, EnableTest) {
__llvm_libc::feenableexcept(FE_DIVBYZERO);
if (__llvm_libc::fegetexcept() == 0)
return;
-#endif // defined(LIBC_TARGET_ARCH_IS_ANY_ARM)
+#endif // Architectures where exception trapping is not supported
int excepts[] = {FE_DIVBYZERO, FE_INVALID, FE_INEXACT, FE_OVERFLOW,
FE_UNDERFLOW};
diff --git a/libc/test/src/fenv/feholdexcept_test.cpp b/libc/test/src/fenv/feholdexcept_test.cpp
index db7573d833e9e..40e336ef41af3 100644
--- a/libc/test/src/fenv/feholdexcept_test.cpp
+++ b/libc/test/src/fenv/feholdexcept_test.cpp
@@ -16,7 +16,7 @@
#include <fenv.h>
TEST(LlvmLibcFEnvTest, RaiseAndCrash) {
-#if defined(LIBC_TARGET_ARCH_IS_ANY_ARM)
+#if defined(LIBC_TARGET_ARCH_IS_ANY_ARM) || defined(LIBC_TARGET_ARCH_IS_RISCV64)
// Few Arm HW implementations do not trap exceptions. We skip this test
// completely on such HW.
//
@@ -28,7 +28,7 @@ TEST(LlvmLibcFEnvTest, RaiseAndCrash) {
__llvm_libc::fputil::enable_except(FE_DIVBYZERO);
if (__llvm_libc::fputil::get_except() == 0)
return;
-#endif // defined(LIBC_TARGET_ARCH_IS_ANY_ARM)
+#endif // Architectures where exception trapping is not supported
int excepts[] = {FE_DIVBYZERO, FE_INVALID, FE_INEXACT, FE_OVERFLOW,
FE_UNDERFLOW};
More information about the libc-commits
mailing list