[libc-commits] [libc] 5c3c716 - [libc] Add FE_DFL_ENV and handle it in fesetenv.
Siva Chandra Reddy via libc-commits
libc-commits at lists.llvm.org
Tue Sep 28 11:10:16 PDT 2021
Author: Siva Chandra Reddy
Date: 2021-09-28T18:09:52Z
New Revision: 5c3c716bb1f5b209b42973790fc85ad241e7f86a
URL: https://github.com/llvm/llvm-project/commit/5c3c716bb1f5b209b42973790fc85ad241e7f86a
DIFF: https://github.com/llvm/llvm-project/commit/5c3c716bb1f5b209b42973790fc85ad241e7f86a.diff
LOG: [libc] Add FE_DFL_ENV and handle it in fesetenv.
Reviewed By: michaelrj
Differential Revision: https://reviews.llvm.org/D110611
Added:
Modified:
libc/config/linux/api.td
libc/spec/stdc.td
libc/src/__support/FPUtil/aarch64/FEnvImpl.h
libc/src/__support/FPUtil/x86_64/FEnvImpl.h
libc/test/src/fenv/CMakeLists.txt
libc/test/src/fenv/getenv_and_setenv_test.cpp
Removed:
################################################################################
diff --git a/libc/config/linux/api.td b/libc/config/linux/api.td
index d4fec7a52f234..d60d17b6d4039 100644
--- a/libc/config/linux/api.td
+++ b/libc/config/linux/api.td
@@ -230,6 +230,8 @@ def FenvAPI: PublicAPI<"fenv.h"> {
SimpleMacroDef<"FE_TONEAREST", "2">,
SimpleMacroDef<"FE_TOWARDZERO", "4">,
SimpleMacroDef<"FE_UPWARD", "8">,
+
+ SimpleMacroDef<"FE_DFL_ENV", "((fenv_t *)-1)">,
];
let TypeDeclarations = [
FEnvT,
diff --git a/libc/spec/stdc.td b/libc/spec/stdc.td
index 2b6488142206c..dd5ac0a357f90 100644
--- a/libc/spec/stdc.td
+++ b/libc/spec/stdc.td
@@ -120,7 +120,9 @@ def StdC : StandardSpec<"stdc"> {
Macro<"FE_DOWNWARD">,
Macro<"FE_TONEAREST">,
Macro<"FE_TOWARDZERO">,
- Macro<"FE_UPWARD">
+ Macro<"FE_UPWARD">,
+
+ Macro<"FE_DFL_ENV">
],
[
NamedType<"fenv_t">,
diff --git a/libc/src/__support/FPUtil/aarch64/FEnvImpl.h b/libc/src/__support/FPUtil/aarch64/FEnvImpl.h
index 36d6caaab5ba9..d59e8f097a922 100644
--- a/libc/src/__support/FPUtil/aarch64/FEnvImpl.h
+++ b/libc/src/__support/FPUtil/aarch64/FEnvImpl.h
@@ -230,6 +230,13 @@ static inline int getEnv(fenv_t *envp) {
}
static inline int setEnv(const fenv_t *envp) {
+ if (envp == FE_DFL_ENV) {
+ // Default status and control words bits are all zeros so we just
+ // write zeros.
+ FEnv::writeStatusWord(0);
+ FEnv::writeControlWord(0);
+ return 0;
+ }
const FEnv::FPState *state = reinterpret_cast<const FEnv::FPState *>(envp);
FEnv::writeControlWord(state->ControlWord);
FEnv::writeStatusWord(state->StatusWord);
diff --git a/libc/src/__support/FPUtil/x86_64/FEnvImpl.h b/libc/src/__support/FPUtil/x86_64/FEnvImpl.h
index d5bb703cebafa..0a220a268c9c1 100644
--- a/libc/src/__support/FPUtil/x86_64/FEnvImpl.h
+++ b/libc/src/__support/FPUtil/x86_64/FEnvImpl.h
@@ -381,10 +381,58 @@ static inline int getEnv(fenv_t *envp) {
}
static inline int setEnv(const fenv_t *envp) {
- const internal::FPState *state =
+ // envp contains everything including pieces like the current
+ // top of FPU stack. We cannot arbitrarily change them. So, we first
+ // read the current status and update only those pieces which are
+ // not disruptive.
+ internal::X87StateDescriptor x87Status;
+ internal::getX87StateDescriptor(x87Status);
+
+ if (envp == FE_DFL_ENV) {
+ // Reset the exception flags in the status word.
+ x87Status.StatusWord &= ~uint16_t(0x3F);
+ // Reset other non-sensitive parts of the status word.
+ for (int i = 0; i < 5; i++)
+ x87Status._[i] = 0;
+ // In the control word, we do the following:
+ // 1. Mask all exceptions
+ // 2. Set rounding mode to round-to-nearest
+ // 3. Set the internal precision to double extended precision.
+ x87Status.ControlWord |= uint16_t(0x3F); // Mask all exceptions.
+ x87Status.ControlWord &= ~(uint16_t(0x3) << 10); // Round to nearest.
+ x87Status.ControlWord |= (uint16_t(0x3) << 8); // Extended precision.
+ internal::writeX87StateDescriptor(x87Status);
+
+ // We take the exact same approach MXCSR register as well.
+ // MXCSR has two additional fields, "flush-to-zero" and
+ // "denormals-are-zero". We reset those bits. Also, MXCSR does not
+ // have a field which controls the precision of internal operations.
+ uint32_t mxcsr = internal::getMXCSR();
+ mxcsr &= ~uint16_t(0x3F); // Clear exception flags.
+ mxcsr &= ~(uint16_t(0x1) << 6); // Reset denormals-are-zero
+ mxcsr |= (uint16_t(0x3F) << 7); // Mask exceptions
+ mxcsr &= ~(uint16_t(0x3) << 13); // Round to nearest.
+ mxcsr &= ~(uint16_t(0x1) << 15); // Reset flush-to-zero
+ internal::writeMXCSR(mxcsr);
+
+ return 0;
+ }
+
+ const internal::FPState *fpstate =
reinterpret_cast<const internal::FPState *>(envp);
- internal::writeX87StateDescriptor(state->X87Status);
- internal::writeMXCSR(state->MXCSR);
+
+ // Copy the exception status flags from envp.
+ x87Status.StatusWord &= ~uint16_t(0x3F);
+ x87Status.StatusWord |= (fpstate->X87Status.StatusWord & 0x3F);
+ // Copy other non-sensitive parts of the status word.
+ for (int i = 0; i < 5; i++)
+ x87Status._[i] = fpstate->X87Status._[i];
+ // We can set the x87 control word as is as there no sensitive bits.
+ x87Status.ControlWord = fpstate->X87Status.ControlWord;
+ internal::writeX87StateDescriptor(x87Status);
+
+ // We can write the MXCSR state as is as there are no sensitive bits.
+ internal::writeMXCSR(fpstate->MXCSR);
return 0;
}
#endif
diff --git a/libc/test/src/fenv/CMakeLists.txt b/libc/test/src/fenv/CMakeLists.txt
index bab83c1138e4c..89b60e5a4d400 100644
--- a/libc/test/src/fenv/CMakeLists.txt
+++ b/libc/test/src/fenv/CMakeLists.txt
@@ -32,7 +32,9 @@ add_libc_unittest(
getenv_and_setenv_test.cpp
DEPENDS
libc.src.fenv.fegetenv
+ libc.src.fenv.fegetround
libc.src.fenv.fesetenv
+ libc.src.fenv.fesetround
libc.src.__support.FPUtil.fputil
)
diff --git a/libc/test/src/fenv/getenv_and_setenv_test.cpp b/libc/test/src/fenv/getenv_and_setenv_test.cpp
index 4a5fbba7e44e3..aa1b53d932d15 100644
--- a/libc/test/src/fenv/getenv_and_setenv_test.cpp
+++ b/libc/test/src/fenv/getenv_and_setenv_test.cpp
@@ -7,7 +7,9 @@
//===----------------------------------------------------------------------===//
#include "src/fenv/fegetenv.h"
+#include "src/fenv/fegetround.h"
#include "src/fenv/fesetenv.h"
+#include "src/fenv/fesetround.h"
#include "src/__support/FPUtil/FEnvUtils.h"
#include "utils/UnitTest/Test.h"
@@ -37,3 +39,34 @@ TEST(LlvmLibcFenvTest, GetEnvAndSetEnv) {
ASSERT_EQ(__llvm_libc::fputil::testExcept(FE_ALL_EXCEPT) & e, 0);
}
}
+
+TEST(LlvmLibcFenvTest, Set_FE_DFL_ENV) {
+ // We will disable all exceptions to prevent invocation of the exception
+ // handler.
+ __llvm_libc::fputil::disableExcept(FE_ALL_EXCEPT);
+
+ int excepts[] = {FE_DIVBYZERO, FE_INVALID, FE_INEXACT, FE_OVERFLOW,
+ FE_UNDERFLOW};
+
+ for (int e : excepts) {
+ __llvm_libc::fputil::clearExcept(FE_ALL_EXCEPT);
+
+ // Save the cleared environment.
+ fenv_t env;
+ ASSERT_EQ(__llvm_libc::fegetenv(&env), 0);
+
+ __llvm_libc::fputil::raiseExcept(e);
+ // Make sure that the exception is raised.
+ ASSERT_NE(__llvm_libc::fputil::testExcept(FE_ALL_EXCEPT) & e, 0);
+
+ ASSERT_EQ(__llvm_libc::fesetenv(FE_DFL_ENV), 0);
+ // Setting the default env should clear all exceptions.
+ ASSERT_EQ(__llvm_libc::fputil::testExcept(FE_ALL_EXCEPT) & e, 0);
+ }
+
+ ASSERT_EQ(__llvm_libc::fesetround(FE_DOWNWARD), 0);
+ ASSERT_EQ(__llvm_libc::fesetenv(FE_DFL_ENV), 0);
+ // Setting the default env should set rounding mode to FE_TONEAREST.
+ int rm = __llvm_libc::fegetround();
+ EXPECT_EQ(rm, FE_TONEAREST);
+}
More information about the libc-commits
mailing list