[libc] Add implementation of fabs and fabsf.

Reviewers: phosek

Differential Revision: https://reviews.llvm.org/D79725
This commit is contained in:
Siva Chandra Reddy 2020-05-08 23:19:17 -07:00
parent ddacd370c5
commit 4a39a33d44
14 changed files with 262 additions and 0 deletions

View File

@ -150,6 +150,8 @@ def MathAPI : PublicAPI<"math.h"> {
];
let Functions = [
"cosf",
"fabs",
"fabsf",
"round",
"sincosf",
"sinf",

View File

@ -48,6 +48,8 @@ add_entrypoint_library(
DEPENDS
# math.h entrypoints
libc.src.math.cosf
libc.src.math.fabs
libc.src.math.fabsf
libc.src.math.round
libc.src.math.sincosf
libc.src.math.sinf

View File

@ -182,6 +182,9 @@ def StdC : StandardSpec<"stdc"> {
],
[], // Enumerations
[
FunctionSpec<"fabs", RetValSpec<DoubleType>, [ArgSpec<DoubleType>]>,
FunctionSpec<"fabsf", RetValSpec<FloatType>, [ArgSpec<FloatType>]>,
FunctionSpec<"cosf", RetValSpec<FloatType>, [ArgSpec<FloatType>]>,
FunctionSpec<"sinf", RetValSpec<FloatType>, [ArgSpec<FloatType>]>,

View File

@ -68,3 +68,23 @@ add_entrypoint_object(
libc.include.math
libc.src.errno.__errno_location
)
add_entrypoint_object(
fabs
SRCS
fabs.cpp
HDRS
fabs.h
DEPENDS
libc.utils.FPUtil.fputil
)
add_entrypoint_object(
fabsf
SRCS
fabsf.cpp
HDRS
fabsf.h
DEPENDS
libc.utils.FPUtil.fputil
)

16
libc/src/math/fabs.cpp Normal file
View File

@ -0,0 +1,16 @@
//===-- Implementation of fabs 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/FloatOperations.h"
namespace __llvm_libc {
double LLVM_LIBC_ENTRYPOINT(fabs)(double x) { return fputil::abs(x); }
} // namespace __llvm_libc

18
libc/src/math/fabs.h Normal file
View File

@ -0,0 +1,18 @@
//===-- Implementation header for fabs --------------------------*- 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_MATH_FABS_H
#define LLVM_LIBC_SRC_MATH_FABS_H
namespace __llvm_libc {
double fabs(double x);
} // namespace __llvm_libc
#endif // LLVM_LIBC_SRC_MATH_FABS_H

16
libc/src/math/fabsf.cpp Normal file
View File

@ -0,0 +1,16 @@
//===-- Implementation of fabsf 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/FloatOperations.h"
namespace __llvm_libc {
float LLVM_LIBC_ENTRYPOINT(fabsf)(float x) { return fputil::abs(x); }
} // namespace __llvm_libc

18
libc/src/math/fabsf.h Normal file
View File

@ -0,0 +1,18 @@
//===-- Implementation header for fabsf -------------------------*- 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_MATH_FABSF_H
#define LLVM_LIBC_SRC_MATH_FABSF_H
namespace __llvm_libc {
float fabsf(float x);
} // namespace __llvm_libc
#endif // LLVM_LIBC_SRC_MATH_FABSF_H

View File

@ -70,3 +70,29 @@ add_math_unittest(
libc.utils.CPP.standalone_cpp
libc.utils.FPUtil.fputil
)
add_math_unittest(
fabs_test
NEED_MPFR
SUITE
libc_math_unittests
SRCS
fabs_test.cpp
DEPENDS
libc.include.math
libc.src.math.fabs
libc.utils.FPUtil.fputil
)
add_math_unittest(
fabsf_test
NEED_MPFR
SUITE
libc_math_unittests
SRCS
fabsf_test.cpp
DEPENDS
libc.include.math
libc.src.math.fabsf
libc.utils.FPUtil.fputil
)

View File

@ -0,0 +1,64 @@
//===-- Unittests for fabs ------------------------------------------------===//
//
// 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 "include/math.h"
#include "src/math/fabs.h"
#include "utils/FPUtil/BitPatterns.h"
#include "utils/FPUtil/FloatOperations.h"
#include "utils/FPUtil/FloatProperties.h"
#include "utils/MPFRWrapper/MPFRUtils.h"
#include "utils/UnitTest/Test.h"
using __llvm_libc::fputil::valueAsBits;
using __llvm_libc::fputil::valueFromBits;
using BitPatterns = __llvm_libc::fputil::BitPatterns<double>;
using Properties = __llvm_libc::fputil::FloatProperties<double>;
namespace mpfr = __llvm_libc::testing::mpfr;
// Zero tolerance; As in, exact match with MPFR result.
static constexpr mpfr::Tolerance tolerance{mpfr::Tolerance::doublePrecision, 0,
0};
TEST(FabsTest, SpecialNumbers) {
EXPECT_EQ(
BitPatterns::aQuietNaN,
valueAsBits(__llvm_libc::fabs(valueFromBits(BitPatterns::aQuietNaN))));
EXPECT_EQ(BitPatterns::aQuietNaN, valueAsBits(__llvm_libc::fabs(valueFromBits(
BitPatterns::aNegativeQuietNaN))));
EXPECT_EQ(BitPatterns::aSignallingNaN,
valueAsBits(
__llvm_libc::fabs(valueFromBits(BitPatterns::aSignallingNaN))));
EXPECT_EQ(BitPatterns::aSignallingNaN,
valueAsBits(__llvm_libc::fabs(
valueFromBits(BitPatterns::aNegativeSignallingNaN))));
EXPECT_EQ(BitPatterns::inf,
valueAsBits(__llvm_libc::fabs(valueFromBits(BitPatterns::inf))));
EXPECT_EQ(BitPatterns::inf,
valueAsBits(__llvm_libc::fabs(valueFromBits(BitPatterns::negInf))));
EXPECT_EQ(BitPatterns::zero,
valueAsBits(__llvm_libc::fabs(valueFromBits(BitPatterns::zero))));
EXPECT_EQ(BitPatterns::zero, valueAsBits(__llvm_libc::fabs(
valueFromBits(BitPatterns::negZero))));
}
TEST(FabsTest, InDoubleRange) {
using BitsType = Properties::BitsType;
constexpr BitsType count = 1000000;
constexpr BitsType step = UINT64_MAX / count;
for (BitsType i = 0, v = 0; i <= count; ++i, v += step) {
double x = valueFromBits(v);
if (isnan(x) || isinf(x))
continue;
ASSERT_MPFR_MATCH(mpfr::OP_Abs, x, __llvm_libc::fabs(x), tolerance);
}
}

View File

@ -0,0 +1,66 @@
//===-- Unittests for fabsf -----------------------------------------------===//
//
// 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 "include/math.h"
#include "src/math/fabsf.h"
#include "utils/FPUtil/BitPatterns.h"
#include "utils/FPUtil/FloatOperations.h"
#include "utils/FPUtil/FloatProperties.h"
#include "utils/MPFRWrapper/MPFRUtils.h"
#include "utils/UnitTest/Test.h"
using __llvm_libc::fputil::valueAsBits;
using __llvm_libc::fputil::valueFromBits;
using BitPatterns = __llvm_libc::fputil::BitPatterns<float>;
using Properties = __llvm_libc::fputil::FloatProperties<float>;
namespace mpfr = __llvm_libc::testing::mpfr;
// Zero tolerance; As in, exact match with MPFR result.
static constexpr mpfr::Tolerance tolerance{mpfr::Tolerance::floatPrecision, 0,
0};
namespace mpfr = __llvm_libc::testing::mpfr;
TEST(FabsfTest, SpecialNumbers) {
EXPECT_EQ(
BitPatterns::aQuietNaN,
valueAsBits(__llvm_libc::fabsf(valueFromBits(BitPatterns::aQuietNaN))));
EXPECT_EQ(BitPatterns::aQuietNaN,
valueAsBits(__llvm_libc::fabsf(
valueFromBits(BitPatterns::aNegativeQuietNaN))));
EXPECT_EQ(BitPatterns::aSignallingNaN,
valueAsBits(__llvm_libc::fabsf(
valueFromBits(BitPatterns::aSignallingNaN))));
EXPECT_EQ(BitPatterns::aSignallingNaN,
valueAsBits(__llvm_libc::fabsf(
valueFromBits(BitPatterns::aNegativeSignallingNaN))));
EXPECT_EQ(BitPatterns::inf,
valueAsBits(__llvm_libc::fabsf(valueFromBits(BitPatterns::inf))));
EXPECT_EQ(BitPatterns::inf, valueAsBits(__llvm_libc::fabsf(
valueFromBits(BitPatterns::negInf))));
EXPECT_EQ(BitPatterns::zero,
valueAsBits(__llvm_libc::fabsf(valueFromBits(BitPatterns::zero))));
EXPECT_EQ(BitPatterns::zero, valueAsBits(__llvm_libc::fabsf(
valueFromBits(BitPatterns::negZero))));
}
TEST(FabsfTest, InFloatRange) {
using BitsType = Properties::BitsType;
constexpr BitsType count = 1000000;
constexpr BitsType step = UINT32_MAX / count;
for (BitsType i = 0, v = 0; i <= count; ++i, v += step) {
double x = valueFromBits(v);
if (isnan(x) || isinf(x))
continue;
ASSERT_MPFR_MATCH(mpfr::OP_Abs, x, __llvm_libc::fabsf(x), tolerance);
}
}

View File

@ -96,6 +96,13 @@ static inline bool isNegativeQuietNaN(T x) {
((bits & Properties::quietNaNMask) != 0);
}
// Return the absolute value of x.
template <typename T,
cpp::EnableIfType<cpp::IsFloatingPointType<T>::Value, int> = 0>
static inline T abs(T x) {
return valueFromBits(absBits(x));
}
} // namespace fputil
} // namespace __llvm_libc

View File

@ -86,6 +86,9 @@ public:
mpfr_init2(value, mpfrPrecision);
MPFRNumber mpfrInput(rawValue);
switch (op) {
case OP_Abs:
mpfr_abs(value, mpfrInput.value, MPFR_RNDN);
break;
case OP_Cos:
mpfr_cos(value, mpfrInput.value, MPFR_RNDN);
break;

View File

@ -40,6 +40,7 @@ struct Tolerance {
};
enum Operation {
OP_Abs,
OP_Cos,
OP_Sin,
};