mirror of
https://github.com/intel/llvm.git
synced 2026-01-16 05:32:28 +08:00
[libc] Add simple x86_64 floating point exception and rounding mode support.
Reviewed By: lntue Differential Revision: https://reviews.llvm.org/D92546
This commit is contained in:
@@ -179,6 +179,22 @@ def MathAPI : PublicAPI<"math.h"> {
|
||||
];
|
||||
}
|
||||
|
||||
def FenvAPI: PublicAPI<"fenv.h"> {
|
||||
let Macros = [
|
||||
SimpleMacroDef<"FE_DIVBYZERO", "1">,
|
||||
SimpleMacroDef<"FE_INEXACT", "2">,
|
||||
SimpleMacroDef<"FE_INVALID", "4">,
|
||||
SimpleMacroDef<"FE_OVERFLOW", "8">,
|
||||
SimpleMacroDef<"FE_UNDERFLOW", "16">,
|
||||
SimpleMacroDef<"FE_ALL_EXCEPT", "(FE_DIVBYZERO|FE_INEXACT|FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW)">,
|
||||
|
||||
SimpleMacroDef<"FE_DOWNWARD", "1">,
|
||||
SimpleMacroDef<"FE_TONEAREST", "2">,
|
||||
SimpleMacroDef<"FE_TOWARDZERO", "4">,
|
||||
SimpleMacroDef<"FE_UPWARD", "8">,
|
||||
];
|
||||
}
|
||||
|
||||
def StringAPI : PublicAPI<"string.h"> {
|
||||
let TypeDeclarations = [
|
||||
SizeT,
|
||||
|
||||
@@ -21,6 +21,13 @@ set(TARGET_LIBC_ENTRYPOINTS
|
||||
# errno.h entrypoints
|
||||
libc.src.errno.__errno_location
|
||||
|
||||
# fenv.h entrypoints
|
||||
libc.src.fenv.feclearexcept
|
||||
libc.src.fenv.fegetround
|
||||
libc.src.fenv.fesetround
|
||||
libc.src.fenv.feraiseexcept
|
||||
libc.src.fenv.fetestexcept
|
||||
|
||||
# signal.h entrypoints
|
||||
libc.src.signal.raise
|
||||
libc.src.signal.sigaction
|
||||
|
||||
@@ -25,6 +25,14 @@ add_gen_header(
|
||||
.llvm_libc_common_h
|
||||
)
|
||||
|
||||
add_gen_header(
|
||||
fenv
|
||||
DEF_FILE fenv.h.def
|
||||
GEN_HDR fenv.h
|
||||
DEPENDS
|
||||
.llvm_libc_common_h
|
||||
)
|
||||
|
||||
add_gen_header(
|
||||
math
|
||||
DEF_FILE math.h.def
|
||||
|
||||
16
libc/include/fenv.h.def
Normal file
16
libc/include/fenv.h.def
Normal file
@@ -0,0 +1,16 @@
|
||||
//===-- C standard library header fenv.h ----------------------------------===//
|
||||
//
|
||||
// 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_FENV_H
|
||||
#define LLVM_LIBC_FENV_H
|
||||
|
||||
#include <__llvm-libc-common.h>
|
||||
|
||||
%%public_api()
|
||||
|
||||
#endif // LLVM_LIBC_FENV_H
|
||||
@@ -95,7 +95,53 @@ def StdC : StandardSpec<"stdc"> {
|
||||
>,
|
||||
]
|
||||
>;
|
||||
|
||||
|
||||
HeaderSpec Fenv = HeaderSpec<
|
||||
"fenv.h",
|
||||
[
|
||||
Macro<"FE_DIVBYZERO">,
|
||||
Macro<"FE_INEXACT">,
|
||||
Macro<"FE_INVALID">,
|
||||
Macro<"FE_OVERFLOW">,
|
||||
Macro<"FE_UNDERFLOW">,
|
||||
Macro<"FE_ALL_EXCEPT">,
|
||||
|
||||
Macro<"FE_DOWNWARD">,
|
||||
Macro<"FE_TONEAREST">,
|
||||
Macro<"FE_TOWARDZERO">,
|
||||
Macro<"FE_UPWARD">
|
||||
],
|
||||
[], // Types
|
||||
[], // Enumerations
|
||||
[
|
||||
FunctionSpec<
|
||||
"feclearexcept",
|
||||
RetValSpec<IntType>,
|
||||
[ArgSpec<IntType>]
|
||||
>,
|
||||
FunctionSpec<
|
||||
"fetestexcept",
|
||||
RetValSpec<IntType>,
|
||||
[ArgSpec<IntType>]
|
||||
>,
|
||||
FunctionSpec<
|
||||
"feraiseexcept",
|
||||
RetValSpec<IntType>,
|
||||
[ArgSpec<IntType>]
|
||||
>,
|
||||
FunctionSpec<
|
||||
"fesetround",
|
||||
RetValSpec<IntType>,
|
||||
[ArgSpec<IntType>]
|
||||
>,
|
||||
FunctionSpec<
|
||||
"fegetround",
|
||||
RetValSpec<IntType>,
|
||||
[]
|
||||
>,
|
||||
]
|
||||
>;
|
||||
|
||||
HeaderSpec String = HeaderSpec<
|
||||
"string.h",
|
||||
[
|
||||
@@ -491,6 +537,7 @@ def StdC : StandardSpec<"stdc"> {
|
||||
Assert,
|
||||
CType,
|
||||
Errno,
|
||||
Fenv,
|
||||
Math,
|
||||
String,
|
||||
StdIO,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
add_subdirectory(assert)
|
||||
add_subdirectory(ctype)
|
||||
add_subdirectory(errno)
|
||||
add_subdirectory(fenv)
|
||||
add_subdirectory(math)
|
||||
add_subdirectory(signal)
|
||||
add_subdirectory(stdio)
|
||||
|
||||
64
libc/src/fenv/CMakeLists.txt
Normal file
64
libc/src/fenv/CMakeLists.txt
Normal file
@@ -0,0 +1,64 @@
|
||||
add_entrypoint_object(
|
||||
fegetround
|
||||
SRCS
|
||||
fegetround.cpp
|
||||
HDRS
|
||||
fegetround.h
|
||||
DEPENDS
|
||||
libc.include.fenv
|
||||
libc.utils.FPUtil.fputil
|
||||
COMPILE_OPTIONS
|
||||
-O2
|
||||
)
|
||||
|
||||
add_entrypoint_object(
|
||||
fesetround
|
||||
SRCS
|
||||
fesetround.cpp
|
||||
HDRS
|
||||
fesetround.h
|
||||
DEPENDS
|
||||
libc.include.fenv
|
||||
libc.utils.FPUtil.fputil
|
||||
COMPILE_OPTIONS
|
||||
-O2
|
||||
)
|
||||
|
||||
add_entrypoint_object(
|
||||
feclearexcept
|
||||
SRCS
|
||||
feclearexcept.cpp
|
||||
HDRS
|
||||
feclearexcept.h
|
||||
DEPENDS
|
||||
libc.include.fenv
|
||||
libc.utils.FPUtil.fputil
|
||||
COMPILE_OPTIONS
|
||||
-O2
|
||||
)
|
||||
|
||||
add_entrypoint_object(
|
||||
feraiseexcept
|
||||
SRCS
|
||||
feraiseexcept.cpp
|
||||
HDRS
|
||||
feraiseexcept.h
|
||||
DEPENDS
|
||||
libc.include.fenv
|
||||
libc.utils.FPUtil.fputil
|
||||
COMPILE_OPTIONS
|
||||
-O2
|
||||
)
|
||||
|
||||
add_entrypoint_object(
|
||||
fetestexcept
|
||||
SRCS
|
||||
fetestexcept.cpp
|
||||
HDRS
|
||||
fetestexcept.h
|
||||
DEPENDS
|
||||
libc.include.fenv
|
||||
libc.utils.FPUtil.fputil
|
||||
COMPILE_OPTIONS
|
||||
-O2
|
||||
)
|
||||
18
libc/src/fenv/feclearexcept.cpp
Normal file
18
libc/src/fenv/feclearexcept.cpp
Normal file
@@ -0,0 +1,18 @@
|
||||
//===-- Implementation of feclearexcept 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/__support/common.h"
|
||||
#include "utils/FPUtil/FEnv.h"
|
||||
|
||||
namespace __llvm_libc {
|
||||
|
||||
int LLVM_LIBC_ENTRYPOINT(feclearexcept)(int e) {
|
||||
return fputil::clearExcept(e);
|
||||
}
|
||||
|
||||
} // namespace __llvm_libc
|
||||
18
libc/src/fenv/feclearexcept.h
Normal file
18
libc/src/fenv/feclearexcept.h
Normal file
@@ -0,0 +1,18 @@
|
||||
//===-- Implementation header for feclearexcept -----------------*- 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_FECLEAREXCEPT_H
|
||||
#define LLVM_LIBC_SRC_FENV_FECLEAREXCEPT_H
|
||||
|
||||
namespace __llvm_libc {
|
||||
|
||||
int feclearexcept(int);
|
||||
|
||||
} // namespace __llvm_libc
|
||||
|
||||
#endif // LLVM_LIBC_SRC_FENV_FECLEAREXCEPT_H
|
||||
16
libc/src/fenv/fegetround.cpp
Normal file
16
libc/src/fenv/fegetround.cpp
Normal file
@@ -0,0 +1,16 @@
|
||||
//===-- Implementation of fegetround 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/__support/common.h"
|
||||
#include "utils/FPUtil/FEnv.h"
|
||||
|
||||
namespace __llvm_libc {
|
||||
|
||||
int LLVM_LIBC_ENTRYPOINT(fegetround)() { return fputil::getRound(); }
|
||||
|
||||
} // namespace __llvm_libc
|
||||
18
libc/src/fenv/fegetround.h
Normal file
18
libc/src/fenv/fegetround.h
Normal file
@@ -0,0 +1,18 @@
|
||||
//===-- Implementation header for fegetround --------------------*- 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_FEGETROUND_H
|
||||
#define LLVM_LIBC_SRC_FENV_FEGETROUND_H
|
||||
|
||||
namespace __llvm_libc {
|
||||
|
||||
int fegetround();
|
||||
|
||||
} // namespace __llvm_libc
|
||||
|
||||
#endif // LLVM_LIBC_SRC_FENV_FEGETROUND_H
|
||||
18
libc/src/fenv/feraiseexcept.cpp
Normal file
18
libc/src/fenv/feraiseexcept.cpp
Normal file
@@ -0,0 +1,18 @@
|
||||
//===-- Implementation of feraiseexcept 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/__support/common.h"
|
||||
#include "utils/FPUtil/FEnv.h"
|
||||
|
||||
namespace __llvm_libc {
|
||||
|
||||
int LLVM_LIBC_ENTRYPOINT(feraiseexcept)(int e) {
|
||||
return fputil::raiseExcept(e);
|
||||
}
|
||||
|
||||
} // namespace __llvm_libc
|
||||
18
libc/src/fenv/feraiseexcept.h
Normal file
18
libc/src/fenv/feraiseexcept.h
Normal file
@@ -0,0 +1,18 @@
|
||||
//===-- Implementation header for feraiseexcept -----------------*- 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_FERAISEEXCEPT_H
|
||||
#define LLVM_LIBC_SRC_FENV_FERAISEEXCEPT_H
|
||||
|
||||
namespace __llvm_libc {
|
||||
|
||||
int feraiseexcept(int);
|
||||
|
||||
} // namespace __llvm_libc
|
||||
|
||||
#endif // LLVM_LIBC_SRC_FENV_FERAISEEXCEPT_H
|
||||
16
libc/src/fenv/fesetround.cpp
Normal file
16
libc/src/fenv/fesetround.cpp
Normal file
@@ -0,0 +1,16 @@
|
||||
//===-- Implementation of fesetround 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/__support/common.h"
|
||||
#include "utils/FPUtil/FEnv.h"
|
||||
|
||||
namespace __llvm_libc {
|
||||
|
||||
int LLVM_LIBC_ENTRYPOINT(fesetround)(int m) { return fputil::setRound(m); }
|
||||
|
||||
} // namespace __llvm_libc
|
||||
18
libc/src/fenv/fesetround.h
Normal file
18
libc/src/fenv/fesetround.h
Normal file
@@ -0,0 +1,18 @@
|
||||
//===-- Implementation header for fesetround --------------------*- 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_FESETROUND_H
|
||||
#define LLVM_LIBC_SRC_FENV_FESETROUND_H
|
||||
|
||||
namespace __llvm_libc {
|
||||
|
||||
int fesetround(int);
|
||||
|
||||
} // namespace __llvm_libc
|
||||
|
||||
#endif // LLVM_LIBC_SRC_FENV_FESETROUND_H
|
||||
16
libc/src/fenv/fetestexcept.cpp
Normal file
16
libc/src/fenv/fetestexcept.cpp
Normal file
@@ -0,0 +1,16 @@
|
||||
//===-- Implementation of fetestexcept 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/__support/common.h"
|
||||
#include "utils/FPUtil/FEnv.h"
|
||||
|
||||
namespace __llvm_libc {
|
||||
|
||||
int LLVM_LIBC_ENTRYPOINT(fetestexcept)(int e) { return fputil::testExcept(e); }
|
||||
|
||||
} // namespace __llvm_libc
|
||||
18
libc/src/fenv/fetestexcept.h
Normal file
18
libc/src/fenv/fetestexcept.h
Normal file
@@ -0,0 +1,18 @@
|
||||
//===-- Implementation header for fetestexpect ------------------*- 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_FETESTEXCEPT_H
|
||||
#define LLVM_LIBC_SRC_FENV_FETESTEXCEPT_H
|
||||
|
||||
namespace __llvm_libc {
|
||||
|
||||
int fetestexcept(int);
|
||||
|
||||
} // namespace __llvm_libc
|
||||
|
||||
#endif // LLVM_LIBC_SRC_FENV_FETESTEXCEPT_H
|
||||
@@ -1,6 +1,7 @@
|
||||
add_subdirectory(assert)
|
||||
add_subdirectory(ctype)
|
||||
add_subdirectory(errno)
|
||||
add_subdirectory(fenv)
|
||||
add_subdirectory(math)
|
||||
add_subdirectory(signal)
|
||||
add_subdirectory(stdio)
|
||||
|
||||
24
libc/test/src/fenv/CMakeLists.txt
Normal file
24
libc/test/src/fenv/CMakeLists.txt
Normal file
@@ -0,0 +1,24 @@
|
||||
add_libc_testsuite(libc_fenv_unittests)
|
||||
|
||||
add_libc_unittest(
|
||||
rounding_mode_test
|
||||
SUITE
|
||||
libc_fenv_unittests
|
||||
SRCS
|
||||
rounding_mode_test.cpp
|
||||
DEPENDS
|
||||
libc.src.fenv.fegetround
|
||||
libc.src.fenv.fesetround
|
||||
)
|
||||
|
||||
add_libc_unittest(
|
||||
exception_status_test
|
||||
SUITE
|
||||
libc_fenv_unittests
|
||||
SRCS
|
||||
exception_status_test.cpp
|
||||
DEPENDS
|
||||
libc.src.fenv.feclearexcept
|
||||
libc.src.fenv.feraiseexcept
|
||||
libc.src.fenv.fetestexcept
|
||||
)
|
||||
108
libc/test/src/fenv/exception_status_test.cpp
Normal file
108
libc/test/src/fenv/exception_status_test.cpp
Normal file
@@ -0,0 +1,108 @@
|
||||
//===-- Unittests for feclearexcept, feraiseexcept and fetestexpect -------===//
|
||||
//
|
||||
// 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/feclearexcept.h"
|
||||
#include "src/fenv/feraiseexcept.h"
|
||||
#include "src/fenv/fetestexcept.h"
|
||||
|
||||
#include "utils/UnitTest/Test.h"
|
||||
|
||||
#include <fenv.h>
|
||||
|
||||
TEST(ExceptionStatusTest, RaiseAndTest) {
|
||||
int excepts[] = {FE_DIVBYZERO, FE_INVALID, FE_INEXACT, FE_OVERFLOW,
|
||||
FE_UNDERFLOW};
|
||||
for (int e : excepts) {
|
||||
int r = __llvm_libc::feraiseexcept(e);
|
||||
EXPECT_EQ(r, 0);
|
||||
int s = __llvm_libc::fetestexcept(e);
|
||||
EXPECT_EQ(s, e);
|
||||
|
||||
r = __llvm_libc::feclearexcept(e);
|
||||
EXPECT_EQ(r, 0);
|
||||
s = __llvm_libc::fetestexcept(e);
|
||||
EXPECT_EQ(s, 0);
|
||||
}
|
||||
|
||||
for (int e1 : excepts) {
|
||||
for (int e2 : excepts) {
|
||||
int e = e1 | e2;
|
||||
int r = __llvm_libc::feraiseexcept(e);
|
||||
EXPECT_EQ(r, 0);
|
||||
int s = __llvm_libc::fetestexcept(e);
|
||||
EXPECT_EQ(s, e);
|
||||
|
||||
r = __llvm_libc::feclearexcept(e);
|
||||
EXPECT_EQ(r, 0);
|
||||
s = __llvm_libc::fetestexcept(e);
|
||||
EXPECT_EQ(s, 0);
|
||||
}
|
||||
}
|
||||
|
||||
for (int e1 : excepts) {
|
||||
for (int e2 : excepts) {
|
||||
for (int e3 : excepts) {
|
||||
int e = e1 | e2 | e3;
|
||||
int r = __llvm_libc::feraiseexcept(e);
|
||||
EXPECT_EQ(r, 0);
|
||||
int s = __llvm_libc::fetestexcept(e);
|
||||
EXPECT_EQ(s, e);
|
||||
|
||||
r = __llvm_libc::feclearexcept(e);
|
||||
EXPECT_EQ(r, 0);
|
||||
s = __llvm_libc::fetestexcept(e);
|
||||
EXPECT_EQ(s, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int e1 : excepts) {
|
||||
for (int e2 : excepts) {
|
||||
for (int e3 : excepts) {
|
||||
for (int e4 : excepts) {
|
||||
int e = e1 | e2 | e3 | e4;
|
||||
int r = __llvm_libc::feraiseexcept(e);
|
||||
EXPECT_EQ(r, 0);
|
||||
int s = __llvm_libc::fetestexcept(e);
|
||||
EXPECT_EQ(s, e);
|
||||
|
||||
r = __llvm_libc::feclearexcept(e);
|
||||
EXPECT_EQ(r, 0);
|
||||
s = __llvm_libc::fetestexcept(e);
|
||||
EXPECT_EQ(s, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int e1 : excepts) {
|
||||
for (int e2 : excepts) {
|
||||
for (int e3 : excepts) {
|
||||
for (int e4 : excepts) {
|
||||
for (int e5 : excepts) {
|
||||
int e = e1 | e2 | e3 | e4 | e5;
|
||||
int r = __llvm_libc::feraiseexcept(e);
|
||||
EXPECT_EQ(r, 0);
|
||||
int s = __llvm_libc::fetestexcept(e);
|
||||
EXPECT_EQ(s, e);
|
||||
|
||||
r = __llvm_libc::feclearexcept(e);
|
||||
EXPECT_EQ(r, 0);
|
||||
s = __llvm_libc::fetestexcept(e);
|
||||
EXPECT_EQ(s, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int r = __llvm_libc::feraiseexcept(FE_ALL_EXCEPT);
|
||||
EXPECT_EQ(r, 0);
|
||||
int s = __llvm_libc::fetestexcept(FE_ALL_EXCEPT);
|
||||
EXPECT_EQ(s, FE_ALL_EXCEPT);
|
||||
}
|
||||
36
libc/test/src/fenv/rounding_mode_test.cpp
Normal file
36
libc/test/src/fenv/rounding_mode_test.cpp
Normal file
@@ -0,0 +1,36 @@
|
||||
//===-- Unittests for fegetround and fesetround ---------------------------===//
|
||||
//
|
||||
// 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/fegetround.h"
|
||||
#include "src/fenv/fesetround.h"
|
||||
|
||||
#include "utils/UnitTest/Test.h"
|
||||
|
||||
#include <fenv.h>
|
||||
|
||||
TEST(RoundingModeTest, SetAndGet) {
|
||||
int s = __llvm_libc::fesetround(FE_TONEAREST);
|
||||
EXPECT_EQ(s, 0);
|
||||
int rm = __llvm_libc::fegetround();
|
||||
EXPECT_EQ(rm, FE_TONEAREST);
|
||||
|
||||
s = __llvm_libc::fesetround(FE_UPWARD);
|
||||
EXPECT_EQ(s, 0);
|
||||
rm = __llvm_libc::fegetround();
|
||||
EXPECT_EQ(rm, FE_UPWARD);
|
||||
|
||||
s = __llvm_libc::fesetround(FE_DOWNWARD);
|
||||
EXPECT_EQ(s, 0);
|
||||
rm = __llvm_libc::fegetround();
|
||||
EXPECT_EQ(rm, FE_DOWNWARD);
|
||||
|
||||
s = __llvm_libc::fesetround(FE_TOWARDZERO);
|
||||
EXPECT_EQ(s, 0);
|
||||
rm = __llvm_libc::fegetround();
|
||||
EXPECT_EQ(rm, FE_TOWARDZERO);
|
||||
}
|
||||
@@ -4,14 +4,22 @@ else()
|
||||
set(LONG_DOUBLE_HDR)
|
||||
endif()
|
||||
|
||||
if(EXISTS ${LIBC_TARGET_MACHINE})
|
||||
set(FENV_IMPL ${LIBC_TARGET_MACHINE}/FEnv.h)
|
||||
else()
|
||||
set(FENV_IMPL DummyFEnv.h)
|
||||
endif()
|
||||
|
||||
add_header_library(
|
||||
fputil
|
||||
HDRS
|
||||
${LONG_DOUBLE_HDR}
|
||||
${FENV_IMPL}
|
||||
BasicOperations.h
|
||||
BitPatterns.h
|
||||
ClassificationFunctions.h
|
||||
DivisionAndRemainderOperations.h
|
||||
FEnv.h
|
||||
FloatOperations.h
|
||||
FloatProperties.h
|
||||
FPBits.h
|
||||
|
||||
32
libc/utils/FPUtil/DummyFEnv.h
Normal file
32
libc/utils/FPUtil/DummyFEnv.h
Normal file
@@ -0,0 +1,32 @@
|
||||
//===-- Dummy floating point environment manipulation functins --*- 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_UTILS_FPUTIL_DUMMY_FENV_H
|
||||
#define LLVM_LIBC_UTILS_FPUTIL_DUMMY_FENV_H
|
||||
|
||||
#include <math.h>
|
||||
|
||||
namespace __llvm_libc {
|
||||
namespace fputil {
|
||||
|
||||
// All dummy functions silently succeed.
|
||||
|
||||
int clearExcept(int) { return 0; }
|
||||
|
||||
int testExcept(int) { return 0; }
|
||||
|
||||
int raiseExcept(int) { return 0; }
|
||||
|
||||
int getRound() { return FE_TONEAREST; }
|
||||
|
||||
int setRound(int) { return 0; }
|
||||
|
||||
} // namespace fputil
|
||||
} // namespace __llvm_libc
|
||||
|
||||
#endif // LLVM_LIBC_UTILS_FPUTIL_DUMMY_FENV_H
|
||||
18
libc/utils/FPUtil/FEnv.h
Normal file
18
libc/utils/FPUtil/FEnv.h
Normal file
@@ -0,0 +1,18 @@
|
||||
//===-- Utilities for manipulating floating point environment ---*- 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_UTILS_FPUTIL_FENV_H
|
||||
#define LLVM_LIBC_UTILS_FPUTIL_FENV_H
|
||||
|
||||
#ifdef __x86_64__
|
||||
#include "x86_64/FEnv.h"
|
||||
#else
|
||||
#include "DummyFEnv.h"
|
||||
#endif
|
||||
|
||||
#endif // LLVM_LIBC_UTILS_FPUTIL_FP_BITS_H
|
||||
184
libc/utils/FPUtil/x86_64/FEnv.h
Normal file
184
libc/utils/FPUtil/x86_64/FEnv.h
Normal file
@@ -0,0 +1,184 @@
|
||||
//===-- x86_64 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_UTILS_FPUTIL_X86_64_FENV_H
|
||||
#define LLVM_LIBC_UTILS_FPUTIL_X86_64_FENV_H
|
||||
|
||||
#include <fenv.h>
|
||||
#include <stdint.h>
|
||||
#include <xmmintrin.h>
|
||||
|
||||
namespace __llvm_libc {
|
||||
namespace fputil {
|
||||
|
||||
namespace internal {
|
||||
|
||||
// Normally, one should be able to define FE_* macros to the exact rounding mode
|
||||
// encodings. However, since we want LLVM libc to be compiled against headers
|
||||
// from other libcs, we cannot assume that FE_* macros are always defined in
|
||||
// such a manner. So, we will define enums corresponding to the x86_64 bit
|
||||
// encodings. The implementations can map from FE_* to the corresponding enum
|
||||
// values.
|
||||
|
||||
// The rounding control values in the x87 control register and the MXCSR
|
||||
// register have the same 2-bit enoding but have different bit positions.
|
||||
// See below for the bit positions.
|
||||
struct RoundingControlValue {
|
||||
static constexpr uint16_t ToNearest = 0x0;
|
||||
static constexpr uint16_t Downward = 0x1;
|
||||
static constexpr uint16_t Upward = 0x2;
|
||||
static constexpr uint16_t TowardZero = 0x3;
|
||||
};
|
||||
|
||||
static constexpr uint16_t X87RoundingControlBitPosition = 10;
|
||||
static constexpr uint16_t MXCSRRoundingControlBitPosition = 13;
|
||||
|
||||
// The exception flags in the x87 status register and the MXCSR have the same
|
||||
// encoding as well as the same bit positions.
|
||||
struct ExceptionFlags {
|
||||
static constexpr uint16_t Invalid = 0x1;
|
||||
static constexpr uint16_t Denormal = 0x2; // This flag is not used
|
||||
static constexpr uint16_t DivByZero = 0x4;
|
||||
static constexpr uint16_t Overflow = 0x8;
|
||||
static constexpr uint16_t Underflow = 0x10;
|
||||
static constexpr uint16_t Inexact = 0x20;
|
||||
};
|
||||
|
||||
// Exception flags are individual bits in the corresponding registers.
|
||||
// So, we just OR the bit values to get the full set of exceptions.
|
||||
static inline uint16_t getStatusValueForExcept(int excepts) {
|
||||
// We will make use of the fact that exception control bits are single
|
||||
// bit flags in the control registers.
|
||||
return (excepts & FE_INVALID ? ExceptionFlags::Invalid : 0) |
|
||||
(excepts & FE_DIVBYZERO ? ExceptionFlags::DivByZero : 0) |
|
||||
(excepts & FE_OVERFLOW ? ExceptionFlags::Overflow : 0) |
|
||||
(excepts & FE_UNDERFLOW ? ExceptionFlags::Underflow : 0) |
|
||||
(excepts & FE_INEXACT ? ExceptionFlags::Inexact : 0);
|
||||
}
|
||||
|
||||
static inline int exceptionStatusToMacro(uint16_t status) {
|
||||
return (status & ExceptionFlags::Invalid ? FE_INVALID : 0) |
|
||||
(status & ExceptionFlags::DivByZero ? FE_DIVBYZERO : 0) |
|
||||
(status & ExceptionFlags::Overflow ? FE_OVERFLOW : 0) |
|
||||
(status & ExceptionFlags::Underflow ? FE_UNDERFLOW : 0) |
|
||||
(status & ExceptionFlags::Inexact ? FE_INEXACT : 0);
|
||||
}
|
||||
|
||||
static inline uint16_t getX87ControlWord() {
|
||||
uint16_t w;
|
||||
__asm__ __volatile__("fnstcw %0" : "=m"(w)::);
|
||||
return w;
|
||||
}
|
||||
|
||||
static inline void writeX87ControlWord(uint16_t w) {
|
||||
__asm__ __volatile__("fldcw %0" : : "m"(w) :);
|
||||
}
|
||||
|
||||
static inline uint16_t getX87StatusWord() {
|
||||
uint16_t w;
|
||||
__asm__ __volatile__("fnstsw %0" : "=m"(w)::);
|
||||
return w;
|
||||
}
|
||||
|
||||
static inline void clearX87Exceptions() {
|
||||
__asm__ __volatile__("fnclex" : : :);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
static inline int clearExcept(int excepts) {
|
||||
// An instruction to write to x87 status word ins't available. So, we
|
||||
// just clear all of the x87 exceptions.
|
||||
// TODO: One can potentially use fegetenv/fesetenv to clear only the
|
||||
// listed exceptions in the x87 status word. We can do this if it is
|
||||
// really required.
|
||||
internal::clearX87Exceptions();
|
||||
|
||||
uint32_t mxcsr = _mm_getcsr();
|
||||
mxcsr &= ~internal::getStatusValueForExcept(excepts);
|
||||
_mm_setcsr(mxcsr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int testExcept(int excepts) {
|
||||
uint16_t statusValue = internal::getStatusValueForExcept(excepts);
|
||||
// Check both x87 status word and MXCSR.
|
||||
return internal::exceptionStatusToMacro(
|
||||
(statusValue & internal::getX87StatusWord()) |
|
||||
(statusValue & _mm_getcsr()));
|
||||
}
|
||||
|
||||
static inline int raiseExcept(int excepts) {
|
||||
// It is enough to set the exception flags in MXCSR.
|
||||
// TODO: Investigate if each exception has to be raised one at a time
|
||||
// followed with an fwait instruction before writing the flag for the
|
||||
// next exception.
|
||||
uint16_t statusValue = internal::getStatusValueForExcept(excepts);
|
||||
uint32_t sse = _mm_getcsr();
|
||||
sse = sse | statusValue;
|
||||
_mm_setcsr(sse);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int getRound() {
|
||||
uint16_t bitValue =
|
||||
(_mm_getcsr() >> internal::MXCSRRoundingControlBitPosition) & 0x3;
|
||||
switch (bitValue) {
|
||||
case internal::RoundingControlValue::ToNearest:
|
||||
return FE_TONEAREST;
|
||||
case internal::RoundingControlValue::Downward:
|
||||
return FE_DOWNWARD;
|
||||
case internal::RoundingControlValue::Upward:
|
||||
return FE_UPWARD;
|
||||
case internal::RoundingControlValue::TowardZero:
|
||||
return FE_TOWARDZERO;
|
||||
default:
|
||||
return -1; // Error value.
|
||||
}
|
||||
}
|
||||
|
||||
static inline int setRound(int mode) {
|
||||
uint16_t bitValue;
|
||||
switch (mode) {
|
||||
case FE_TONEAREST:
|
||||
bitValue = internal::RoundingControlValue::ToNearest;
|
||||
break;
|
||||
case FE_DOWNWARD:
|
||||
bitValue = internal::RoundingControlValue::Downward;
|
||||
break;
|
||||
case FE_UPWARD:
|
||||
bitValue = internal::RoundingControlValue::Upward;
|
||||
break;
|
||||
case FE_TOWARDZERO:
|
||||
bitValue = internal::RoundingControlValue::TowardZero;
|
||||
break;
|
||||
default:
|
||||
return 1; // To indicate failure
|
||||
}
|
||||
|
||||
uint16_t x87Value = bitValue << internal::X87RoundingControlBitPosition;
|
||||
uint16_t x87Control = internal::getX87ControlWord();
|
||||
x87Control =
|
||||
(x87Control & ~(0x3 << internal::X87RoundingControlBitPosition)) |
|
||||
x87Value;
|
||||
internal::writeX87ControlWord(x87Control);
|
||||
|
||||
uint32_t mxcsrValue = bitValue << internal::MXCSRRoundingControlBitPosition;
|
||||
uint32_t mxcsrControl = _mm_getcsr();
|
||||
mxcsrControl =
|
||||
(mxcsrControl & ~(0x3 << internal::MXCSRRoundingControlBitPosition)) |
|
||||
mxcsrValue;
|
||||
_mm_setcsr(mxcsrControl);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace fputil
|
||||
} // namespace __llvm_libc
|
||||
|
||||
#endif // LLVM_LIBC_UTILS_FPUTIL_X86_64_FENV_H
|
||||
Reference in New Issue
Block a user