[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