forked from OSchip/llvm-project
[libc] Add implementations of rounding functions which depend rounding mode.
Namely, implementations for rint, rintf, rintl, lrint, lrintf, lrintl, llrint, llrintf and llrintl have been added. Reviewed By: lntue Differential Revision: https://reviews.llvm.org/D93889
This commit is contained in:
parent
981a0bd858
commit
ff6fd38552
|
@ -123,12 +123,18 @@ set(TARGET_LIBM_ENTRYPOINTS
|
|||
libc.src.math.ldexp
|
||||
libc.src.math.ldexpf
|
||||
libc.src.math.ldexpl
|
||||
libc.src.math.llrint
|
||||
libc.src.math.llrintf
|
||||
libc.src.math.llrintl
|
||||
libc.src.math.llround
|
||||
libc.src.math.llroundf
|
||||
libc.src.math.llroundl
|
||||
libc.src.math.logb
|
||||
libc.src.math.logbf
|
||||
libc.src.math.logbl
|
||||
libc.src.math.lrint
|
||||
libc.src.math.lrintf
|
||||
libc.src.math.lrintl
|
||||
libc.src.math.lround
|
||||
libc.src.math.lroundf
|
||||
libc.src.math.lroundl
|
||||
|
@ -141,6 +147,9 @@ set(TARGET_LIBM_ENTRYPOINTS
|
|||
libc.src.math.remquof
|
||||
libc.src.math.remquo
|
||||
libc.src.math.remquol
|
||||
libc.src.math.rint
|
||||
libc.src.math.rintf
|
||||
libc.src.math.rintl
|
||||
libc.src.math.round
|
||||
libc.src.math.roundf
|
||||
libc.src.math.roundl
|
||||
|
|
|
@ -371,6 +371,18 @@ def StdC : StandardSpec<"stdc"> {
|
|||
FunctionSpec<"llroundf", RetValSpec<LongLongType>, [ArgSpec<FloatType>]>,
|
||||
FunctionSpec<"llroundl", RetValSpec<LongLongType>, [ArgSpec<LongDoubleType>]>,
|
||||
|
||||
FunctionSpec<"rint", RetValSpec<DoubleType>, [ArgSpec<DoubleType>]>,
|
||||
FunctionSpec<"rintf", RetValSpec<FloatType>, [ArgSpec<FloatType>]>,
|
||||
FunctionSpec<"rintl", RetValSpec<LongDoubleType>, [ArgSpec<LongDoubleType>]>,
|
||||
|
||||
FunctionSpec<"lrint", RetValSpec<LongType>, [ArgSpec<DoubleType>]>,
|
||||
FunctionSpec<"lrintf", RetValSpec<LongType>, [ArgSpec<FloatType>]>,
|
||||
FunctionSpec<"lrintl", RetValSpec<LongType>, [ArgSpec<LongDoubleType>]>,
|
||||
|
||||
FunctionSpec<"llrint", RetValSpec<LongLongType>, [ArgSpec<DoubleType>]>,
|
||||
FunctionSpec<"llrintf", RetValSpec<LongLongType>, [ArgSpec<FloatType>]>,
|
||||
FunctionSpec<"llrintl", RetValSpec<LongLongType>, [ArgSpec<LongDoubleType>]>,
|
||||
|
||||
FunctionSpec<"sqrt", RetValSpec<DoubleType>, [ArgSpec<DoubleType>]>,
|
||||
FunctionSpec<"sqrtf", RetValSpec<FloatType>, [ArgSpec<FloatType>]>,
|
||||
FunctionSpec<"sqrtl", RetValSpec<LongDoubleType>, [ArgSpec<LongDoubleType>]>,
|
||||
|
|
|
@ -308,6 +308,114 @@ add_entrypoint_object(
|
|||
-O2
|
||||
)
|
||||
|
||||
add_entrypoint_object(
|
||||
rint
|
||||
SRCS
|
||||
rint.cpp
|
||||
HDRS
|
||||
rint.h
|
||||
DEPENDS
|
||||
libc.utils.FPUtil.fputil
|
||||
COMPILE_OPTIONS
|
||||
-O2
|
||||
)
|
||||
|
||||
add_entrypoint_object(
|
||||
rintf
|
||||
SRCS
|
||||
rintf.cpp
|
||||
HDRS
|
||||
rintf.h
|
||||
DEPENDS
|
||||
libc.utils.FPUtil.fputil
|
||||
COMPILE_OPTIONS
|
||||
-O2
|
||||
)
|
||||
|
||||
add_entrypoint_object(
|
||||
rintl
|
||||
SRCS
|
||||
rintl.cpp
|
||||
HDRS
|
||||
rintl.h
|
||||
DEPENDS
|
||||
libc.utils.FPUtil.fputil
|
||||
COMPILE_OPTIONS
|
||||
-O2
|
||||
)
|
||||
|
||||
add_entrypoint_object(
|
||||
lrint
|
||||
SRCS
|
||||
lrint.cpp
|
||||
HDRS
|
||||
lrint.h
|
||||
DEPENDS
|
||||
libc.utils.FPUtil.fputil
|
||||
COMPILE_OPTIONS
|
||||
-O2
|
||||
)
|
||||
|
||||
add_entrypoint_object(
|
||||
lrintf
|
||||
SRCS
|
||||
lrintf.cpp
|
||||
HDRS
|
||||
lrintf.h
|
||||
DEPENDS
|
||||
libc.utils.FPUtil.fputil
|
||||
COMPILE_OPTIONS
|
||||
-O2
|
||||
)
|
||||
|
||||
add_entrypoint_object(
|
||||
lrintl
|
||||
SRCS
|
||||
lrintl.cpp
|
||||
HDRS
|
||||
lrintl.h
|
||||
DEPENDS
|
||||
libc.utils.FPUtil.fputil
|
||||
COMPILE_OPTIONS
|
||||
-O2
|
||||
)
|
||||
|
||||
add_entrypoint_object(
|
||||
llrint
|
||||
SRCS
|
||||
llrint.cpp
|
||||
HDRS
|
||||
llrint.h
|
||||
DEPENDS
|
||||
libc.utils.FPUtil.fputil
|
||||
COMPILE_OPTIONS
|
||||
-O2
|
||||
)
|
||||
|
||||
add_entrypoint_object(
|
||||
llrintf
|
||||
SRCS
|
||||
llrintf.cpp
|
||||
HDRS
|
||||
llrintf.h
|
||||
DEPENDS
|
||||
libc.utils.FPUtil.fputil
|
||||
COMPILE_OPTIONS
|
||||
-O2
|
||||
)
|
||||
|
||||
add_entrypoint_object(
|
||||
llrintl
|
||||
SRCS
|
||||
llrintl.cpp
|
||||
HDRS
|
||||
llrintl.h
|
||||
DEPENDS
|
||||
libc.utils.FPUtil.fputil
|
||||
COMPILE_OPTIONS
|
||||
-O2
|
||||
)
|
||||
|
||||
add_object_library(
|
||||
exp_utils
|
||||
HDRS
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
//===-- Implementation of llrint 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/NearestIntegerOperations.h"
|
||||
|
||||
namespace __llvm_libc {
|
||||
|
||||
long long LLVM_LIBC_ENTRYPOINT(llrint)(double x) {
|
||||
return fputil::roundToSignedIntegerUsingCurrentRoundingMode<double,
|
||||
long long>(x);
|
||||
}
|
||||
|
||||
} // namespace __llvm_libc
|
|
@ -0,0 +1,18 @@
|
|||
//===-- Implementation header for llrint ------------------------*- 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_LLRINT_H
|
||||
#define LLVM_LIBC_SRC_MATH_LLRINT_H
|
||||
|
||||
namespace __llvm_libc {
|
||||
|
||||
long long llrint(double x);
|
||||
|
||||
} // namespace __llvm_libc
|
||||
|
||||
#endif // LLVM_LIBC_SRC_MATH_LLRINT_H
|
|
@ -0,0 +1,19 @@
|
|||
//===-- Implementation of llrintf 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/NearestIntegerOperations.h"
|
||||
|
||||
namespace __llvm_libc {
|
||||
|
||||
long long LLVM_LIBC_ENTRYPOINT(llrintf)(float x) {
|
||||
return fputil::roundToSignedIntegerUsingCurrentRoundingMode<float, long long>(
|
||||
x);
|
||||
}
|
||||
|
||||
} // namespace __llvm_libc
|
|
@ -0,0 +1,18 @@
|
|||
//===-- Implementation header for llrintf -----------------------*- 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_LLRINTF_H
|
||||
#define LLVM_LIBC_SRC_MATH_LLRINTF_H
|
||||
|
||||
namespace __llvm_libc {
|
||||
|
||||
long long llrintf(float x);
|
||||
|
||||
} // namespace __llvm_libc
|
||||
|
||||
#endif // LLVM_LIBC_SRC_MATH_LLRINTF_H
|
|
@ -0,0 +1,19 @@
|
|||
//===-- Implementation of llrintl 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/NearestIntegerOperations.h"
|
||||
|
||||
namespace __llvm_libc {
|
||||
|
||||
long long LLVM_LIBC_ENTRYPOINT(llrintl)(long double x) {
|
||||
return fputil::roundToSignedIntegerUsingCurrentRoundingMode<long double,
|
||||
long long>(x);
|
||||
}
|
||||
|
||||
} // namespace __llvm_libc
|
|
@ -0,0 +1,18 @@
|
|||
//===-- Implementation header for llrintl -----------------------*- 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_LLRINTL_H
|
||||
#define LLVM_LIBC_SRC_MATH_LLRINTL_H
|
||||
|
||||
namespace __llvm_libc {
|
||||
|
||||
long long llrintl(long double x);
|
||||
|
||||
} // namespace __llvm_libc
|
||||
|
||||
#endif // LLVM_LIBC_SRC_MATH_LLRINTL_H
|
|
@ -0,0 +1,18 @@
|
|||
//===-- Implementation of lrint 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/NearestIntegerOperations.h"
|
||||
|
||||
namespace __llvm_libc {
|
||||
|
||||
long LLVM_LIBC_ENTRYPOINT(lrint)(double x) {
|
||||
return fputil::roundToSignedIntegerUsingCurrentRoundingMode<double, long>(x);
|
||||
}
|
||||
|
||||
} // namespace __llvm_libc
|
|
@ -0,0 +1,18 @@
|
|||
//===-- Implementation header for lrint -------------------------*- 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_LRINT_H
|
||||
#define LLVM_LIBC_SRC_MATH_LRINT_H
|
||||
|
||||
namespace __llvm_libc {
|
||||
|
||||
long lrint(double x);
|
||||
|
||||
} // namespace __llvm_libc
|
||||
|
||||
#endif // LLVM_LIBC_SRC_MATH_LRINT_H
|
|
@ -0,0 +1,18 @@
|
|||
//===-- Implementation of lrintf 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/NearestIntegerOperations.h"
|
||||
|
||||
namespace __llvm_libc {
|
||||
|
||||
long LLVM_LIBC_ENTRYPOINT(lrintf)(float x) {
|
||||
return fputil::roundToSignedIntegerUsingCurrentRoundingMode<float, long>(x);
|
||||
}
|
||||
|
||||
} // namespace __llvm_libc
|
|
@ -0,0 +1,18 @@
|
|||
//===-- Implementation header for lrintf ------------------------*- 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_LRINTF_H
|
||||
#define LLVM_LIBC_SRC_MATH_LRINTF_H
|
||||
|
||||
namespace __llvm_libc {
|
||||
|
||||
long lrintf(float x);
|
||||
|
||||
} // namespace __llvm_libc
|
||||
|
||||
#endif // LLVM_LIBC_SRC_MATH_LRINTF_H
|
|
@ -0,0 +1,19 @@
|
|||
//===-- Implementation of lrintl 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/NearestIntegerOperations.h"
|
||||
|
||||
namespace __llvm_libc {
|
||||
|
||||
long LLVM_LIBC_ENTRYPOINT(lrintl)(long double x) {
|
||||
return fputil::roundToSignedIntegerUsingCurrentRoundingMode<long double,
|
||||
long>(x);
|
||||
}
|
||||
|
||||
} // namespace __llvm_libc
|
|
@ -0,0 +1,18 @@
|
|||
//===-- Implementation header for lrintl ------------------------*- 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_LRINTL_H
|
||||
#define LLVM_LIBC_SRC_MATH_LRINTL_H
|
||||
|
||||
namespace __llvm_libc {
|
||||
|
||||
long lrintl(long double x);
|
||||
|
||||
} // namespace __llvm_libc
|
||||
|
||||
#endif // LLVM_LIBC_SRC_MATH_LRINTL_H
|
|
@ -0,0 +1,18 @@
|
|||
//===-- Implementation of rint 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/NearestIntegerOperations.h"
|
||||
|
||||
namespace __llvm_libc {
|
||||
|
||||
double LLVM_LIBC_ENTRYPOINT(rint)(double x) {
|
||||
return fputil::roundUsingCurrentRoundingMode(x);
|
||||
}
|
||||
|
||||
} // namespace __llvm_libc
|
|
@ -0,0 +1,18 @@
|
|||
//===-- Implementation header for rint --------------------------*- 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_RINT_H
|
||||
#define LLVM_LIBC_SRC_MATH_RINT_H
|
||||
|
||||
namespace __llvm_libc {
|
||||
|
||||
double rint(double x);
|
||||
|
||||
} // namespace __llvm_libc
|
||||
|
||||
#endif // LLVM_LIBC_SRC_MATH_RINT_H
|
|
@ -0,0 +1,18 @@
|
|||
//===-- Implementation of rintf 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/NearestIntegerOperations.h"
|
||||
|
||||
namespace __llvm_libc {
|
||||
|
||||
float LLVM_LIBC_ENTRYPOINT(rintf)(float x) {
|
||||
return fputil::roundUsingCurrentRoundingMode(x);
|
||||
}
|
||||
|
||||
} // namespace __llvm_libc
|
|
@ -0,0 +1,18 @@
|
|||
//===-- Implementation header for rintf -------------------------*- 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_RINTF_H
|
||||
#define LLVM_LIBC_SRC_MATH_RINTF_H
|
||||
|
||||
namespace __llvm_libc {
|
||||
|
||||
float rintf(float x);
|
||||
|
||||
} // namespace __llvm_libc
|
||||
|
||||
#endif // LLVM_LIBC_SRC_MATH_RINTF_H
|
|
@ -0,0 +1,18 @@
|
|||
//===-- Implementation of rintl 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/NearestIntegerOperations.h"
|
||||
|
||||
namespace __llvm_libc {
|
||||
|
||||
long double LLVM_LIBC_ENTRYPOINT(rintl)(long double x) {
|
||||
return fputil::roundUsingCurrentRoundingMode(x);
|
||||
}
|
||||
|
||||
} // namespace __llvm_libc
|
|
@ -0,0 +1,18 @@
|
|||
//===-- Implementation header for rintl -------------------------*- 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_RINTL_H
|
||||
#define LLVM_LIBC_SRC_MATH_RINTL_H
|
||||
|
||||
namespace __llvm_libc {
|
||||
|
||||
long double rintl(long double x);
|
||||
|
||||
} // namespace __llvm_libc
|
||||
|
||||
#endif // LLVM_LIBC_SRC_MATH_RINTL_H
|
|
@ -390,6 +390,141 @@ add_fp_unittest(
|
|||
libc.utils.FPUtil.fputil
|
||||
)
|
||||
|
||||
add_fp_unittest(
|
||||
rint_test
|
||||
NEED_MPFR
|
||||
SUITE
|
||||
libc_math_unittests
|
||||
SRCS
|
||||
rint_test.cpp
|
||||
HDRS
|
||||
RIntTest.h
|
||||
DEPENDS
|
||||
libc.include.math
|
||||
libc.src.math.rint
|
||||
libc.utils.FPUtil.fputil
|
||||
)
|
||||
|
||||
add_fp_unittest(
|
||||
rintf_test
|
||||
NEED_MPFR
|
||||
SUITE
|
||||
libc_math_unittests
|
||||
SRCS
|
||||
rintf_test.cpp
|
||||
HDRS
|
||||
RIntTest.h
|
||||
DEPENDS
|
||||
libc.include.math
|
||||
libc.src.math.rintf
|
||||
libc.utils.FPUtil.fputil
|
||||
)
|
||||
|
||||
add_fp_unittest(
|
||||
rintl_test
|
||||
NEED_MPFR
|
||||
SUITE
|
||||
libc_math_unittests
|
||||
SRCS
|
||||
rintl_test.cpp
|
||||
HDRS
|
||||
RIntTest.h
|
||||
DEPENDS
|
||||
libc.include.math
|
||||
libc.src.math.rintl
|
||||
libc.utils.FPUtil.fputil
|
||||
)
|
||||
|
||||
add_fp_unittest(
|
||||
lrint_test
|
||||
NEED_MPFR
|
||||
SUITE
|
||||
libc_math_unittests
|
||||
SRCS
|
||||
lrint_test.cpp
|
||||
HDRS
|
||||
RoundToIntegerTest.h
|
||||
DEPENDS
|
||||
libc.include.math
|
||||
libc.src.math.lrint
|
||||
libc.utils.FPUtil.fputil
|
||||
)
|
||||
|
||||
add_fp_unittest(
|
||||
lrintf_test
|
||||
NEED_MPFR
|
||||
SUITE
|
||||
libc_math_unittests
|
||||
SRCS
|
||||
lrintf_test.cpp
|
||||
HDRS
|
||||
RoundToIntegerTest.h
|
||||
DEPENDS
|
||||
libc.include.math
|
||||
libc.src.math.lrintf
|
||||
libc.utils.FPUtil.fputil
|
||||
)
|
||||
|
||||
add_fp_unittest(
|
||||
lrintl_test
|
||||
NEED_MPFR
|
||||
SUITE
|
||||
libc_math_unittests
|
||||
SRCS
|
||||
lrintl_test.cpp
|
||||
HDRS
|
||||
RoundToIntegerTest.h
|
||||
DEPENDS
|
||||
libc.include.math
|
||||
libc.src.math.lrintl
|
||||
libc.utils.FPUtil.fputil
|
||||
)
|
||||
|
||||
add_fp_unittest(
|
||||
llrint_test
|
||||
NEED_MPFR
|
||||
SUITE
|
||||
libc_math_unittests
|
||||
SRCS
|
||||
llrint_test.cpp
|
||||
HDRS
|
||||
RoundToIntegerTest.h
|
||||
DEPENDS
|
||||
libc.include.math
|
||||
libc.src.math.llrint
|
||||
libc.utils.FPUtil.fputil
|
||||
)
|
||||
|
||||
add_fp_unittest(
|
||||
llrintf_test
|
||||
NEED_MPFR
|
||||
SUITE
|
||||
libc_math_unittests
|
||||
SRCS
|
||||
llrintf_test.cpp
|
||||
HDRS
|
||||
RoundToIntegerTest.h
|
||||
DEPENDS
|
||||
libc.include.math
|
||||
libc.src.math.llrintf
|
||||
libc.utils.FPUtil.fputil
|
||||
)
|
||||
|
||||
add_fp_unittest(
|
||||
llrintl_test
|
||||
NEED_MPFR
|
||||
SUITE
|
||||
libc_math_unittests
|
||||
SRCS
|
||||
llrintl_test.cpp
|
||||
HDRS
|
||||
RoundToIntegerTest.h
|
||||
DEPENDS
|
||||
libc.include.math
|
||||
libc.src.math.llrintl
|
||||
libc.utils.FPUtil.fputil
|
||||
)
|
||||
|
||||
add_fp_unittest(
|
||||
expf_test
|
||||
NEED_MPFR
|
||||
|
|
|
@ -0,0 +1,138 @@
|
|||
//===-- Utility class to test different flavors of rint ---------*- 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_TEST_SRC_MATH_RINTTEST_H
|
||||
#define LLVM_LIBC_TEST_SRC_MATH_RINTTEST_H
|
||||
|
||||
#include "utils/FPUtil/FEnv.h"
|
||||
#include "utils/FPUtil/FPBits.h"
|
||||
#include "utils/FPUtil/TestHelpers.h"
|
||||
#include "utils/MPFRWrapper/MPFRUtils.h"
|
||||
#include "utils/UnitTest/Test.h"
|
||||
|
||||
#include <fenv.h>
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
|
||||
namespace mpfr = __llvm_libc::testing::mpfr;
|
||||
|
||||
static constexpr int roundingModes[4] = {FE_UPWARD, FE_DOWNWARD, FE_TOWARDZERO,
|
||||
FE_TONEAREST};
|
||||
|
||||
template <typename T>
|
||||
class RIntTestTemplate : public __llvm_libc::testing::Test {
|
||||
public:
|
||||
typedef T (*RIntFunc)(T);
|
||||
|
||||
private:
|
||||
using FPBits = __llvm_libc::fputil::FPBits<T>;
|
||||
using UIntType = typename FPBits::UIntType;
|
||||
|
||||
const T zero = FPBits::zero();
|
||||
const T negZero = FPBits::negZero();
|
||||
const T inf = FPBits::inf();
|
||||
const T negInf = FPBits::negInf();
|
||||
const T nan = FPBits::buildNaN(1);
|
||||
|
||||
static inline mpfr::RoundingMode toMPFRRoundingMode(int mode) {
|
||||
switch (mode) {
|
||||
case FE_UPWARD:
|
||||
return mpfr::RoundingMode::Upward;
|
||||
case FE_DOWNWARD:
|
||||
return mpfr::RoundingMode::Downward;
|
||||
case FE_TOWARDZERO:
|
||||
return mpfr::RoundingMode::TowardZero;
|
||||
case FE_TONEAREST:
|
||||
return mpfr::RoundingMode::Nearest;
|
||||
default:
|
||||
__builtin_unreachable();
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
void testSpecialNumbers(RIntFunc func) {
|
||||
for (int mode : roundingModes) {
|
||||
__llvm_libc::fputil::setRound(mode);
|
||||
ASSERT_FP_EQ(inf, func(inf));
|
||||
ASSERT_FP_EQ(negInf, func(negInf));
|
||||
ASSERT_FP_EQ(nan, func(nan));
|
||||
ASSERT_FP_EQ(zero, func(zero));
|
||||
ASSERT_FP_EQ(negZero, func(negZero));
|
||||
}
|
||||
}
|
||||
|
||||
void testRoundNumbers(RIntFunc func) {
|
||||
for (int mode : roundingModes) {
|
||||
__llvm_libc::fputil::setRound(mode);
|
||||
mpfr::RoundingMode mpfrMode = toMPFRRoundingMode(mode);
|
||||
ASSERT_FP_EQ(func(T(1.0)), mpfr::Round(T(1.0), mpfrMode));
|
||||
ASSERT_FP_EQ(func(T(-1.0)), mpfr::Round(T(-1.0), mpfrMode));
|
||||
ASSERT_FP_EQ(func(T(10.0)), mpfr::Round(T(10.0), mpfrMode));
|
||||
ASSERT_FP_EQ(func(T(-10.0)), mpfr::Round(T(-10.0), mpfrMode));
|
||||
ASSERT_FP_EQ(func(T(1234.0)), mpfr::Round(T(1234.0), mpfrMode));
|
||||
ASSERT_FP_EQ(func(T(-1234.0)), mpfr::Round(T(-1234.0), mpfrMode));
|
||||
}
|
||||
}
|
||||
|
||||
void testFractions(RIntFunc func) {
|
||||
for (int mode : roundingModes) {
|
||||
__llvm_libc::fputil::setRound(mode);
|
||||
mpfr::RoundingMode mpfrMode = toMPFRRoundingMode(mode);
|
||||
ASSERT_FP_EQ(func(T(0.5)), mpfr::Round(T(0.5), mpfrMode));
|
||||
ASSERT_FP_EQ(func(T(-0.5)), mpfr::Round(T(-0.5), mpfrMode));
|
||||
ASSERT_FP_EQ(func(T(0.115)), mpfr::Round(T(0.115), mpfrMode));
|
||||
ASSERT_FP_EQ(func(T(-0.115)), mpfr::Round(T(-0.115), mpfrMode));
|
||||
ASSERT_FP_EQ(func(T(0.715)), mpfr::Round(T(0.715), mpfrMode));
|
||||
ASSERT_FP_EQ(func(T(-0.715)), mpfr::Round(T(-0.715), mpfrMode));
|
||||
}
|
||||
}
|
||||
|
||||
void testSubnormalRange(RIntFunc func) {
|
||||
constexpr UIntType count = 1000001;
|
||||
constexpr UIntType step =
|
||||
(FPBits::maxSubnormal - FPBits::minSubnormal) / count;
|
||||
for (UIntType i = FPBits::minSubnormal; i <= FPBits::maxSubnormal;
|
||||
i += step) {
|
||||
T x = FPBits(i);
|
||||
for (int mode : roundingModes) {
|
||||
__llvm_libc::fputil::setRound(mode);
|
||||
mpfr::RoundingMode mpfrMode = toMPFRRoundingMode(mode);
|
||||
ASSERT_FP_EQ(func(x), mpfr::Round(x, mpfrMode));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void testNormalRange(RIntFunc func) {
|
||||
constexpr UIntType count = 1000001;
|
||||
constexpr UIntType step = (FPBits::maxNormal - FPBits::minNormal) / count;
|
||||
for (UIntType i = FPBits::minNormal; i <= FPBits::maxNormal; i += step) {
|
||||
T x = FPBits(i);
|
||||
// In normal range on x86 platforms, the long double implicit 1 bit can be
|
||||
// zero making the numbers NaN. We will skip them.
|
||||
if (isnan(x)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int mode : roundingModes) {
|
||||
__llvm_libc::fputil::setRound(mode);
|
||||
mpfr::RoundingMode mpfrMode = toMPFRRoundingMode(mode);
|
||||
ASSERT_FP_EQ(func(x), mpfr::Round(x, mpfrMode));
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#define LIST_RINT_TESTS(F, func) \
|
||||
using RIntTest = RIntTestTemplate<F>; \
|
||||
TEST_F(RIntTest, specialNumbers) { testSpecialNumbers(&func); } \
|
||||
TEST_F(RIntTest, RoundNumbers) { testRoundNumbers(&func); } \
|
||||
TEST_F(RIntTest, Fractions) { testFractions(&func); } \
|
||||
TEST_F(RIntTest, SubnormalRange) { testSubnormalRange(&func); } \
|
||||
TEST_F(RIntTest, NormalRange) { testNormalRange(&func); }
|
||||
|
||||
#endif // LLVM_LIBC_TEST_SRC_MATH_RINTTEST_H
|
|
@ -10,9 +10,6 @@
|
|||
#define LLVM_LIBC_TEST_SRC_MATH_ROUNDTOINTEGERTEST_H
|
||||
|
||||
#include "src/errno/llvmlibc_errno.h"
|
||||
#include "src/fenv/feclearexcept.h"
|
||||
#include "src/fenv/feraiseexcept.h"
|
||||
#include "src/fenv/fetestexcept.h"
|
||||
#include "utils/FPUtil/FPBits.h"
|
||||
#include "utils/MPFRWrapper/MPFRUtils.h"
|
||||
#include "utils/UnitTest/Test.h"
|
||||
|
@ -27,7 +24,10 @@
|
|||
|
||||
namespace mpfr = __llvm_libc::testing::mpfr;
|
||||
|
||||
template <typename F, typename I>
|
||||
static constexpr int roundingModes[4] = {FE_UPWARD, FE_DOWNWARD, FE_TOWARDZERO,
|
||||
FE_TONEAREST};
|
||||
|
||||
template <typename F, typename I, bool TestModes = false>
|
||||
class RoundToIntegerTestTemplate : public __llvm_libc::testing::Test {
|
||||
public:
|
||||
typedef I (*RoundToIntegerFunc)(F);
|
||||
|
@ -50,21 +50,21 @@ private:
|
|||
llvmlibc_errno = 0;
|
||||
#endif
|
||||
#if math_errhandling & MATH_ERREXCEPT
|
||||
__llvm_libc::feclearexcept(FE_ALL_EXCEPT);
|
||||
__llvm_libc::fputil::clearExcept(FE_ALL_EXCEPT);
|
||||
#endif
|
||||
|
||||
ASSERT_EQ(func(input), expected);
|
||||
|
||||
if (expectError) {
|
||||
#if math_errhandling & MATH_ERREXCEPT
|
||||
ASSERT_EQ(__llvm_libc::fetestexcept(FE_ALL_EXCEPT), FE_INVALID);
|
||||
ASSERT_EQ(__llvm_libc::fputil::testExcept(FE_ALL_EXCEPT), FE_INVALID);
|
||||
#endif
|
||||
#if math_errhandling & MATH_ERRNO
|
||||
ASSERT_EQ(llvmlibc_errno, EDOM);
|
||||
#endif
|
||||
} else {
|
||||
#if math_errhandling & MATH_ERREXCEPT
|
||||
ASSERT_EQ(__llvm_libc::fetestexcept(FE_ALL_EXCEPT), 0);
|
||||
ASSERT_EQ(__llvm_libc::fputil::testExcept(FE_ALL_EXCEPT), 0);
|
||||
#endif
|
||||
#if math_errhandling & MATH_ERRNO
|
||||
ASSERT_EQ(llvmlibc_errno, 0);
|
||||
|
@ -72,6 +72,21 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
static inline mpfr::RoundingMode toMPFRRoundingMode(int mode) {
|
||||
switch (mode) {
|
||||
case FE_UPWARD:
|
||||
return mpfr::RoundingMode::Upward;
|
||||
case FE_DOWNWARD:
|
||||
return mpfr::RoundingMode::Downward;
|
||||
case FE_TOWARDZERO:
|
||||
return mpfr::RoundingMode::TowardZero;
|
||||
case FE_TONEAREST:
|
||||
return mpfr::RoundingMode::Nearest;
|
||||
default:
|
||||
__builtin_unreachable();
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
void SetUp() override {
|
||||
#if math_errhandling & MATH_ERREXCEPT
|
||||
|
@ -82,13 +97,24 @@ public:
|
|||
#endif
|
||||
}
|
||||
|
||||
void testInfinityAndNaN(RoundToIntegerFunc func) {
|
||||
void doInfinityAndNaNTest(RoundToIntegerFunc func) {
|
||||
testOneInput(func, inf, IntegerMax, true);
|
||||
testOneInput(func, negInf, IntegerMin, true);
|
||||
testOneInput(func, nan, IntegerMax, true);
|
||||
}
|
||||
|
||||
void testRoundNumbers(RoundToIntegerFunc func) {
|
||||
void testInfinityAndNaN(RoundToIntegerFunc func) {
|
||||
if (TestModes) {
|
||||
for (int mode : roundingModes) {
|
||||
__llvm_libc::fputil::setRound(mode);
|
||||
doInfinityAndNaNTest(func);
|
||||
}
|
||||
} else {
|
||||
doInfinityAndNaNTest(func);
|
||||
}
|
||||
}
|
||||
|
||||
void doRoundNumbersTest(RoundToIntegerFunc func) {
|
||||
testOneInput(func, zero, I(0), false);
|
||||
testOneInput(func, negZero, I(0), false);
|
||||
testOneInput(func, F(1.0), I(1), false);
|
||||
|
@ -121,13 +147,44 @@ public:
|
|||
testOneInput(func, x, mpfrResult, false);
|
||||
}
|
||||
|
||||
void testRoundNumbers(RoundToIntegerFunc func) {
|
||||
if (TestModes) {
|
||||
for (int mode : roundingModes) {
|
||||
__llvm_libc::fputil::setRound(mode);
|
||||
doRoundNumbersTest(func);
|
||||
}
|
||||
} else {
|
||||
doRoundNumbersTest(func);
|
||||
}
|
||||
}
|
||||
|
||||
void doFractionsTest(RoundToIntegerFunc func, int mode) {
|
||||
constexpr F fractions[] = {0.5, -0.5, 0.115, -0.115, 0.715, -0.715};
|
||||
for (F x : fractions) {
|
||||
long mpfrLongResult;
|
||||
bool erangeflag;
|
||||
if (TestModes)
|
||||
erangeflag =
|
||||
mpfr::RoundToLong(x, toMPFRRoundingMode(mode), mpfrLongResult);
|
||||
else
|
||||
erangeflag = mpfr::RoundToLong(x, mpfrLongResult);
|
||||
ASSERT_FALSE(erangeflag);
|
||||
I mpfrResult = mpfrLongResult;
|
||||
testOneInput(func, x, mpfrResult, false);
|
||||
}
|
||||
}
|
||||
|
||||
void testFractions(RoundToIntegerFunc func) {
|
||||
testOneInput(func, F(0.5), I(1), false);
|
||||
testOneInput(func, F(-0.5), I(-1), false);
|
||||
testOneInput(func, F(0.115), I(0), false);
|
||||
testOneInput(func, F(-0.115), I(0), false);
|
||||
testOneInput(func, F(0.715), I(1), false);
|
||||
testOneInput(func, F(-0.715), I(-1), false);
|
||||
if (TestModes) {
|
||||
for (int mode : roundingModes) {
|
||||
__llvm_libc::fputil::setRound(mode);
|
||||
doFractionsTest(func, mode);
|
||||
}
|
||||
} else {
|
||||
// Passing 0 for mode has no effect as it is not used in doFractionsTest
|
||||
// when `TestModes` is false;
|
||||
doFractionsTest(func, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void testIntegerOverflow(RoundToIntegerFunc func) {
|
||||
|
@ -149,29 +206,56 @@ public:
|
|||
<< (__llvm_libc::fputil::MantissaWidth<F>::value - 1);
|
||||
|
||||
F x = bits;
|
||||
long mpfrResult;
|
||||
bool erangeflag = mpfr::RoundToLong(x, mpfrResult);
|
||||
ASSERT_TRUE(erangeflag);
|
||||
testOneInput(func, x, IntegerMin, true);
|
||||
if (TestModes) {
|
||||
for (int m : roundingModes) {
|
||||
__llvm_libc::fputil::setRound(m);
|
||||
long mpfrLongResult;
|
||||
bool erangeflag =
|
||||
mpfr::RoundToLong(x, toMPFRRoundingMode(m), mpfrLongResult);
|
||||
ASSERT_TRUE(erangeflag);
|
||||
testOneInput(func, x, IntegerMin, true);
|
||||
}
|
||||
} else {
|
||||
long mpfrLongResult;
|
||||
bool erangeflag = mpfr::RoundToLong(x, mpfrLongResult);
|
||||
ASSERT_TRUE(erangeflag);
|
||||
testOneInput(func, x, IntegerMin, true);
|
||||
}
|
||||
}
|
||||
|
||||
void testSubnormalRange(RoundToIntegerFunc func) {
|
||||
// This function compares with an equivalent MPFR function which rounds
|
||||
// floating point numbers to long values. There is no MPFR function to
|
||||
// round to long long or wider integer values. So, we will peform the
|
||||
// comparisons in this function only if the width of I less than equal to
|
||||
// that of long.
|
||||
if (sizeof(I) > sizeof(long))
|
||||
return;
|
||||
|
||||
constexpr UIntType count = 1000001;
|
||||
constexpr UIntType step =
|
||||
(FPBits::maxSubnormal - FPBits::minSubnormal) / count;
|
||||
for (UIntType i = FPBits::minSubnormal; i <= FPBits::maxSubnormal;
|
||||
i += step) {
|
||||
F x = FPBits(i);
|
||||
if (x == F(0.0))
|
||||
continue;
|
||||
// All subnormal numbers should round to zero.
|
||||
testOneInput(func, x, 0L, false);
|
||||
if (TestModes) {
|
||||
if (x > 0) {
|
||||
__llvm_libc::fputil::setRound(FE_UPWARD);
|
||||
testOneInput(func, x, I(1), false);
|
||||
__llvm_libc::fputil::setRound(FE_DOWNWARD);
|
||||
testOneInput(func, x, I(0), false);
|
||||
__llvm_libc::fputil::setRound(FE_TOWARDZERO);
|
||||
testOneInput(func, x, I(0), false);
|
||||
__llvm_libc::fputil::setRound(FE_TONEAREST);
|
||||
testOneInput(func, x, I(0), false);
|
||||
} else {
|
||||
__llvm_libc::fputil::setRound(FE_UPWARD);
|
||||
testOneInput(func, x, I(0), false);
|
||||
__llvm_libc::fputil::setRound(FE_DOWNWARD);
|
||||
testOneInput(func, x, I(-1), false);
|
||||
__llvm_libc::fputil::setRound(FE_TOWARDZERO);
|
||||
testOneInput(func, x, I(0), false);
|
||||
__llvm_libc::fputil::setRound(FE_TONEAREST);
|
||||
testOneInput(func, x, I(0), false);
|
||||
}
|
||||
} else {
|
||||
testOneInput(func, x, 0L, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -194,18 +278,33 @@ public:
|
|||
continue;
|
||||
}
|
||||
|
||||
long mpfrResult;
|
||||
bool erangeflag = mpfr::RoundToLong(x, mpfrResult);
|
||||
if (erangeflag)
|
||||
testOneInput(func, x, x > 0 ? IntegerMax : IntegerMin, true);
|
||||
else
|
||||
testOneInput(func, x, mpfrResult, false);
|
||||
if (TestModes) {
|
||||
for (int m : roundingModes) {
|
||||
long mpfrLongResult;
|
||||
bool erangeflag =
|
||||
mpfr::RoundToLong(x, toMPFRRoundingMode(m), mpfrLongResult);
|
||||
I mpfrResult = mpfrLongResult;
|
||||
__llvm_libc::fputil::setRound(m);
|
||||
if (erangeflag)
|
||||
testOneInput(func, x, x > 0 ? IntegerMax : IntegerMin, true);
|
||||
else
|
||||
testOneInput(func, x, mpfrResult, false);
|
||||
}
|
||||
} else {
|
||||
long mpfrLongResult;
|
||||
bool erangeflag = mpfr::RoundToLong(x, mpfrLongResult);
|
||||
I mpfrResult = mpfrLongResult;
|
||||
if (erangeflag)
|
||||
testOneInput(func, x, x > 0 ? IntegerMax : IntegerMin, true);
|
||||
else
|
||||
testOneInput(func, x, mpfrResult, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#define LIST_ROUND_TO_INTEGER_TESTS(F, I, func) \
|
||||
using RoundToIntegerTest = RoundToIntegerTestTemplate<F, I>; \
|
||||
#define LIST_ROUND_TO_INTEGER_TESTS_HELPER(F, I, func, TestModes) \
|
||||
using RoundToIntegerTest = RoundToIntegerTestTemplate<F, I, TestModes>; \
|
||||
TEST_F(RoundToIntegerTest, InfinityAndNaN) { testInfinityAndNaN(&func); } \
|
||||
TEST_F(RoundToIntegerTest, RoundNumbers) { testRoundNumbers(&func); } \
|
||||
TEST_F(RoundToIntegerTest, Fractions) { testFractions(&func); } \
|
||||
|
@ -213,4 +312,10 @@ public:
|
|||
TEST_F(RoundToIntegerTest, SubnormalRange) { testSubnormalRange(&func); } \
|
||||
TEST_F(RoundToIntegerTest, NormalRange) { testNormalRange(&func); }
|
||||
|
||||
#define LIST_ROUND_TO_INTEGER_TESTS(F, I, func) \
|
||||
LIST_ROUND_TO_INTEGER_TESTS_HELPER(F, I, func, false)
|
||||
|
||||
#define LIST_ROUND_TO_INTEGER_TESTS_WITH_MODES(F, I, func) \
|
||||
LIST_ROUND_TO_INTEGER_TESTS_HELPER(F, I, func, true)
|
||||
|
||||
#endif // LLVM_LIBC_TEST_SRC_MATH_ROUNDTOINTEGERTEST_H
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
//===-- Unittests for llrint ----------------------------------------------===//
|
||||
//
|
||||
// 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 "RoundToIntegerTest.h"
|
||||
|
||||
#include "src/math/llrint.h"
|
||||
|
||||
LIST_ROUND_TO_INTEGER_TESTS_WITH_MODES(double, long long, __llvm_libc::llrint)
|
|
@ -0,0 +1,13 @@
|
|||
//===-- Unittests for llrintf ---------------------------------------------===//
|
||||
//
|
||||
// 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 "RoundToIntegerTest.h"
|
||||
|
||||
#include "src/math/llrintf.h"
|
||||
|
||||
LIST_ROUND_TO_INTEGER_TESTS_WITH_MODES(float, long long, __llvm_libc::llrintf)
|
|
@ -0,0 +1,14 @@
|
|||
//===-- Unittests for llrintl ---------------------------------------------===//
|
||||
//
|
||||
// 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 "RoundToIntegerTest.h"
|
||||
|
||||
#include "src/math/llrintl.h"
|
||||
|
||||
LIST_ROUND_TO_INTEGER_TESTS_WITH_MODES(long double, long long,
|
||||
__llvm_libc::llrintl)
|
|
@ -0,0 +1,13 @@
|
|||
//===-- Unittests for lrint -----------------------------------------------===//
|
||||
//
|
||||
// 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 "RoundToIntegerTest.h"
|
||||
|
||||
#include "src/math/lrint.h"
|
||||
|
||||
LIST_ROUND_TO_INTEGER_TESTS_WITH_MODES(double, long, __llvm_libc::lrint)
|
|
@ -0,0 +1,13 @@
|
|||
//===-- Unittests for lrintf ----------------------------------------------===//
|
||||
//
|
||||
// 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 "RoundToIntegerTest.h"
|
||||
|
||||
#include "src/math/lrintf.h"
|
||||
|
||||
LIST_ROUND_TO_INTEGER_TESTS_WITH_MODES(float, long, __llvm_libc::lrintf)
|
|
@ -0,0 +1,13 @@
|
|||
//===-- Unittests for lrintl ----------------------------------------------===//
|
||||
//
|
||||
// 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 "RoundToIntegerTest.h"
|
||||
|
||||
#include "src/math/lrintl.h"
|
||||
|
||||
LIST_ROUND_TO_INTEGER_TESTS_WITH_MODES(long double, long, __llvm_libc::lrintl)
|
|
@ -0,0 +1,13 @@
|
|||
//===-- Unittests for rint ------------------------------------------------===//
|
||||
//
|
||||
// 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 "RIntTest.h"
|
||||
|
||||
#include "src/math/rint.h"
|
||||
|
||||
LIST_RINT_TESTS(double, __llvm_libc::rint)
|
|
@ -0,0 +1,13 @@
|
|||
//===-- Unittests for rintf -----------------------------------------------===//
|
||||
//
|
||||
// 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 "RIntTest.h"
|
||||
|
||||
#include "src/math/rintf.h"
|
||||
|
||||
LIST_RINT_TESTS(float, __llvm_libc::rintf)
|
|
@ -0,0 +1,13 @@
|
|||
//===-- Unittests for rintl -----------------------------------------------===//
|
||||
//
|
||||
// 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 "RIntTest.h"
|
||||
|
||||
#include "src/math/rintl.h"
|
||||
|
||||
LIST_RINT_TESTS(long double, __llvm_libc::rintl)
|
|
@ -9,14 +9,12 @@
|
|||
#ifndef LLVM_LIBC_UTILS_FPUTIL_NEAREST_INTEGER_OPERATIONS_H
|
||||
#define LLVM_LIBC_UTILS_FPUTIL_NEAREST_INTEGER_OPERATIONS_H
|
||||
|
||||
#include "FEnv.h"
|
||||
#include "FPBits.h"
|
||||
|
||||
#include "utils/CPP/TypeTraits.h"
|
||||
|
||||
#include <math.h>
|
||||
#if math_errhandling & MATH_ERREXCEPT
|
||||
#include "FEnv.h"
|
||||
#endif
|
||||
#if math_errhandling & MATH_ERRNO
|
||||
#include "src/errno/llvmlibc_errno.h"
|
||||
#include <errno.h>
|
||||
|
@ -159,17 +157,94 @@ static inline T round(T x) {
|
|||
}
|
||||
}
|
||||
|
||||
template <typename T,
|
||||
cpp::EnableIfType<cpp::IsFloatingPointType<T>::Value, int> = 0>
|
||||
static inline T roundUsingCurrentRoundingMode(T x) {
|
||||
using UIntType = typename FPBits<T>::UIntType;
|
||||
FPBits<T> bits(x);
|
||||
|
||||
// If x is infinity NaN or zero, return it.
|
||||
if (bits.isInfOrNaN() || bits.isZero())
|
||||
return x;
|
||||
|
||||
bool isNeg = bits.sign;
|
||||
int exponent = bits.getExponent();
|
||||
int roundingMode = getRound();
|
||||
|
||||
// If the exponent is greater than the most negative mantissa
|
||||
// exponent, then x is already an integer.
|
||||
if (exponent >= static_cast<int>(MantissaWidth<T>::value))
|
||||
return x;
|
||||
|
||||
if (exponent <= -1) {
|
||||
switch (roundingMode) {
|
||||
case FE_DOWNWARD:
|
||||
return isNeg ? T(-1.0) : T(0.0);
|
||||
case FE_UPWARD:
|
||||
return isNeg ? T(-0.0) : T(1.0);
|
||||
case FE_TOWARDZERO:
|
||||
return isNeg ? T(-0.0) : T(0.0);
|
||||
case FE_TONEAREST:
|
||||
if (exponent <= -2 || bits.mantissa == 0)
|
||||
return isNeg ? T(-0.0) : T(0.0); // abs(x) <= 0.5
|
||||
else
|
||||
return isNeg ? T(-1.0) : T(1.0); // abs(x) > 0.5
|
||||
default:
|
||||
__builtin_unreachable();
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t trimSize = MantissaWidth<T>::value - exponent;
|
||||
FPBits<T> newBits = bits;
|
||||
newBits.mantissa = (bits.mantissa >> trimSize) << trimSize;
|
||||
T truncValue = T(newBits);
|
||||
|
||||
// If x is already an integer, return it.
|
||||
if (truncValue == x)
|
||||
return x;
|
||||
|
||||
UIntType trimValue = bits.mantissa & ((UIntType(1) << trimSize) - 1);
|
||||
UIntType halfValue = (UIntType(1) << (trimSize - 1));
|
||||
// If exponent is 0, trimSize will be equal to the mantissa width, and
|
||||
// truncIsOdd` will not be correct. So, we handle it as a special case
|
||||
// below.
|
||||
UIntType truncIsOdd = newBits.mantissa & (UIntType(1) << trimSize);
|
||||
|
||||
switch (roundingMode) {
|
||||
case FE_DOWNWARD:
|
||||
return isNeg ? truncValue - T(1.0) : truncValue;
|
||||
case FE_UPWARD:
|
||||
return isNeg ? truncValue : truncValue + T(1.0);
|
||||
case FE_TOWARDZERO:
|
||||
return truncValue;
|
||||
case FE_TONEAREST:
|
||||
if (trimValue > halfValue) {
|
||||
return isNeg ? truncValue - T(1.0) : truncValue + T(1.0);
|
||||
} else if (trimValue == halfValue) {
|
||||
if (exponent == 0)
|
||||
return isNeg ? T(-2.0) : T(2.0);
|
||||
if (truncIsOdd)
|
||||
return isNeg ? truncValue - T(1.0) : truncValue + T(1.0);
|
||||
else
|
||||
return truncValue;
|
||||
} else {
|
||||
return truncValue;
|
||||
}
|
||||
default:
|
||||
__builtin_unreachable();
|
||||
}
|
||||
}
|
||||
|
||||
namespace internal {
|
||||
|
||||
template <typename F, typename I,
|
||||
cpp::EnableIfType<cpp::IsFloatingPointType<F>::Value &&
|
||||
cpp::IsIntegral<I>::Value,
|
||||
int> = 0>
|
||||
static inline I roundToSignedInteger(F x) {
|
||||
static inline I roundedFloatToSignedInteger(F x) {
|
||||
constexpr I IntegerMin = (I(1) << (sizeof(I) * 8 - 1));
|
||||
constexpr I IntegerMax = -(IntegerMin + 1);
|
||||
|
||||
using FPBits = FPBits<F>;
|
||||
F roundedValue = round(x);
|
||||
FPBits bits(roundedValue);
|
||||
FPBits<F> bits(x);
|
||||
auto setDomainErrorAndRaiseInvalid = []() {
|
||||
#if math_errhandling & MATH_ERRNO
|
||||
llvmlibc_errno = EDOM;
|
||||
|
@ -180,8 +255,6 @@ static inline I roundToSignedInteger(F x) {
|
|||
};
|
||||
|
||||
if (bits.isInfOrNaN()) {
|
||||
// Result of round is infinity or NaN only if x is infinity
|
||||
// or NaN.
|
||||
setDomainErrorAndRaiseInvalid();
|
||||
return bits.sign ? IntegerMin : IntegerMax;
|
||||
}
|
||||
|
@ -200,10 +273,29 @@ static inline I roundToSignedInteger(F x) {
|
|||
// value is the most negative number for the signed integer type I.
|
||||
}
|
||||
|
||||
// For all other cases, if |roundedValue| can fit in the integer type |I|,
|
||||
// we just return the roundedValue. Implicit conversion will convert the
|
||||
// For all other cases, if `x` can fit in the integer type `I`,
|
||||
// we just return `x`. Implicit conversion will convert the
|
||||
// floating point value to the exact integer value.
|
||||
return roundedValue;
|
||||
return x;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
template <typename F, typename I,
|
||||
cpp::EnableIfType<cpp::IsFloatingPointType<F>::Value &&
|
||||
cpp::IsIntegral<I>::Value,
|
||||
int> = 0>
|
||||
static inline I roundToSignedInteger(F x) {
|
||||
return internal::roundedFloatToSignedInteger<F, I>(round(x));
|
||||
}
|
||||
|
||||
template <typename F, typename I,
|
||||
cpp::EnableIfType<cpp::IsFloatingPointType<F>::Value &&
|
||||
cpp::IsIntegral<I>::Value,
|
||||
int> = 0>
|
||||
static inline I roundToSignedIntegerUsingCurrentRoundingMode(F x) {
|
||||
return internal::roundedFloatToSignedInteger<F, I>(
|
||||
roundUsingCurrentRoundingMode(x));
|
||||
}
|
||||
|
||||
} // namespace fputil
|
||||
|
|
|
@ -163,6 +163,18 @@ public:
|
|||
return mpfr_erangeflag_p();
|
||||
}
|
||||
|
||||
bool roundToLong(mpfr_rnd_t rnd, long &result) const {
|
||||
MPFRNumber rint_result;
|
||||
mpfr_rint(rint_result.value, value, rnd);
|
||||
return rint_result.roundToLong(result);
|
||||
}
|
||||
|
||||
MPFRNumber rint(mpfr_rnd_t rnd) const {
|
||||
MPFRNumber result;
|
||||
mpfr_rint(result.value, value, rnd);
|
||||
return result;
|
||||
}
|
||||
|
||||
MPFRNumber sin() const {
|
||||
MPFRNumber result;
|
||||
mpfr_sin(result.value, value, MPFR_RNDN);
|
||||
|
@ -563,6 +575,23 @@ compareBinaryOperationOneOutput<double>(Operation, const BinaryInput<double> &,
|
|||
template bool compareBinaryOperationOneOutput<long double>(
|
||||
Operation, const BinaryInput<long double> &, long double, double);
|
||||
|
||||
static mpfr_rnd_t getMPFRRoundingMode(RoundingMode mode) {
|
||||
switch (mode) {
|
||||
case RoundingMode::Upward:
|
||||
return MPFR_RNDU;
|
||||
break;
|
||||
case RoundingMode::Downward:
|
||||
return MPFR_RNDD;
|
||||
break;
|
||||
case RoundingMode::TowardZero:
|
||||
return MPFR_RNDZ;
|
||||
break;
|
||||
case RoundingMode::Nearest:
|
||||
return MPFR_RNDN;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
template <typename T> bool RoundToLong(T x, long &result) {
|
||||
|
@ -574,6 +603,25 @@ template bool RoundToLong<float>(float, long &);
|
|||
template bool RoundToLong<double>(double, long &);
|
||||
template bool RoundToLong<long double>(long double, long &);
|
||||
|
||||
template <typename T> bool RoundToLong(T x, RoundingMode mode, long &result) {
|
||||
MPFRNumber mpfr(x);
|
||||
return mpfr.roundToLong(internal::getMPFRRoundingMode(mode), result);
|
||||
}
|
||||
|
||||
template bool RoundToLong<float>(float, RoundingMode, long &);
|
||||
template bool RoundToLong<double>(double, RoundingMode, long &);
|
||||
template bool RoundToLong<long double>(long double, RoundingMode, long &);
|
||||
|
||||
template <typename T> T Round(T x, RoundingMode mode) {
|
||||
MPFRNumber mpfr(x);
|
||||
MPFRNumber result = mpfr.rint(internal::getMPFRRoundingMode(mode));
|
||||
return result.as<T>();
|
||||
}
|
||||
|
||||
template float Round<float>(float, RoundingMode);
|
||||
template double Round<double>(double, RoundingMode);
|
||||
template long double Round<long double>(long double, RoundingMode);
|
||||
|
||||
} // namespace mpfr
|
||||
} // namespace testing
|
||||
} // namespace __llvm_libc
|
||||
|
|
|
@ -237,7 +237,12 @@ getMPFRMatcher(InputType input, OutputType outputUnused, double t) {
|
|||
return internal::MPFRMatcher<op, InputType, OutputType>(input, t);
|
||||
}
|
||||
|
||||
enum class RoundingMode : uint8_t { Upward, Downward, TowardZero, Nearest };
|
||||
|
||||
template <typename T> T Round(T x, RoundingMode mode);
|
||||
|
||||
template <typename T> bool RoundToLong(T x, long &result);
|
||||
template <typename T> bool RoundToLong(T x, RoundingMode mode, long &result);
|
||||
|
||||
} // namespace mpfr
|
||||
} // namespace testing
|
||||
|
|
Loading…
Reference in New Issue