diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt --- a/libc/config/linux/x86_64/entrypoints.txt +++ b/libc/config/linux/x86_64/entrypoints.txt @@ -65,6 +65,7 @@ libc.src.math.ceil libc.src.math.ceilf libc.src.math.ceill + libc.src.math.cos libc.src.math.cosf libc.src.math.expf libc.src.math.exp2f @@ -136,11 +137,13 @@ libc.src.math.round libc.src.math.roundf libc.src.math.roundl + libc.src.math.sin libc.src.math.sincosf libc.src.math.sinf libc.src.math.sqrt libc.src.math.sqrtf libc.src.math.sqrtl + libc.src.math.tan libc.src.math.trunc libc.src.math.truncf libc.src.math.truncl diff --git a/libc/spec/stdc.td b/libc/spec/stdc.td --- a/libc/spec/stdc.td +++ b/libc/spec/stdc.td @@ -388,8 +388,11 @@ FunctionSpec<"modff", RetValSpec, [ArgSpec, ArgSpec]>, FunctionSpec<"modfl", RetValSpec, [ArgSpec, ArgSpec]>, + FunctionSpec<"cos", RetValSpec, [ArgSpec]>, FunctionSpec<"cosf", RetValSpec, [ArgSpec]>, + FunctionSpec<"sin", RetValSpec, [ArgSpec]>, FunctionSpec<"sinf", RetValSpec, [ArgSpec]>, + FunctionSpec<"tan", RetValSpec, [ArgSpec]>, FunctionSpec<"expf", RetValSpec, [ArgSpec]>, FunctionSpec<"exp2f", RetValSpec, [ArgSpec]>, diff --git a/libc/src/math/CMakeLists.txt b/libc/src/math/CMakeLists.txt --- a/libc/src/math/CMakeLists.txt +++ b/libc/src/math/CMakeLists.txt @@ -64,6 +64,7 @@ add_math_entrypoint_object(copysignf) add_math_entrypoint_object(copysignl) +add_math_entrypoint_object(cos) add_math_entrypoint_object(cosf) add_math_entrypoint_object(expf) @@ -155,12 +156,15 @@ add_math_entrypoint_object(sincosf) +add_math_entrypoint_object(sin) add_math_entrypoint_object(sinf) add_math_entrypoint_object(sqrt) add_math_entrypoint_object(sqrtf) add_math_entrypoint_object(sqrtl) +add_math_entrypoint_object(tan) + add_math_entrypoint_object(trunc) add_math_entrypoint_object(truncf) add_math_entrypoint_object(truncl) diff --git a/libc/src/math/cos.h b/libc/src/math/cos.h new file mode 100644 --- /dev/null +++ b/libc/src/math/cos.h @@ -0,0 +1,18 @@ +//===-- Implementation header for cos ---------------------------*- 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_COS_H +#define LLVM_LIBC_SRC_MATH_COS_H + +namespace __llvm_libc { + +double cos(double x); + +} // namespace __llvm_libc + +#endif // LLVM_LIBC_SRC_MATH_COS_H diff --git a/libc/src/math/sin.h b/libc/src/math/sin.h new file mode 100644 --- /dev/null +++ b/libc/src/math/sin.h @@ -0,0 +1,18 @@ +//===-- Implementation header for sin ---------------------------*- 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_SIN_H +#define LLVM_LIBC_SRC_MATH_SIN_H + +namespace __llvm_libc { + +double sin(double x); + +} // namespace __llvm_libc + +#endif // LLVM_LIBC_SRC_MATH_SIN_H diff --git a/libc/src/math/tan.h b/libc/src/math/tan.h new file mode 100644 --- /dev/null +++ b/libc/src/math/tan.h @@ -0,0 +1,18 @@ +//===-- Implementation header for tan ---------------------------*- 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_TAN_H +#define LLVM_LIBC_SRC_MATH_TAN_H + +namespace __llvm_libc { + +double tan(double x); + +} // namespace __llvm_libc + +#endif // LLVM_LIBC_SRC_MATH_TAN_H diff --git a/libc/src/math/x86_64/CMakeLists.txt b/libc/src/math/x86_64/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/libc/src/math/x86_64/CMakeLists.txt @@ -0,0 +1,29 @@ +add_entrypoint_object( + cos + SRCS + cos.cpp + HDRS + ../cos.h + COMPILE_OPTIONS + -O2 +) + +add_entrypoint_object( + sin + SRCS + sin.cpp + HDRS + ../sin.h + COMPILE_OPTIONS + -O2 +) + +add_entrypoint_object( + tan + SRCS + tan.cpp + HDRS + ../tan.h + COMPILE_OPTIONS + -O2 +) diff --git a/libc/src/math/x86_64/cos.cpp b/libc/src/math/x86_64/cos.cpp new file mode 100644 --- /dev/null +++ b/libc/src/math/x86_64/cos.cpp @@ -0,0 +1,20 @@ +//===-- Implementation of the cos function for x86_64 ---------------------===// +// +// 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/math/cos.h" +#include "src/__support/common.h" + +namespace __llvm_libc { + +LLVM_LIBC_FUNCTION(double, cos, (double x)) { + double result; + __asm__ __volatile__("fcos" : "=t"(result) : "f"(x)); + return result; +} + +} // namespace __llvm_libc diff --git a/libc/src/math/x86_64/sin.cpp b/libc/src/math/x86_64/sin.cpp new file mode 100644 --- /dev/null +++ b/libc/src/math/x86_64/sin.cpp @@ -0,0 +1,20 @@ +//===-- Implementation of the sin function for x86_64 ---------------------===// +// +// 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/math/sin.h" +#include "src/__support/common.h" + +namespace __llvm_libc { + +LLVM_LIBC_FUNCTION(double, sin, (double x)) { + double result; + __asm__ __volatile__("fsin" : "=t"(result) : "f"(x)); + return result; +} + +} // namespace __llvm_libc diff --git a/libc/src/math/x86_64/tan.cpp b/libc/src/math/x86_64/tan.cpp new file mode 100644 --- /dev/null +++ b/libc/src/math/x86_64/tan.cpp @@ -0,0 +1,24 @@ +//===-- Implementation of the tan function for x86_64 ---------------------===// +// +// 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/math/tan.h" +#include "src/__support/common.h" + +namespace __llvm_libc { + +LLVM_LIBC_FUNCTION(double, tan, (double x)) { + double result; + double one; + // The fptan instruction pushes the number 1 on to the FP stack after + // computing tan. So, we read out the one before popping the actual result. + __asm__ __volatile__("fptan" : "=t"(one) : "f"(x)); + __asm__ __volatile__("fstpl %0" : "=m"(result)); + return result; +} + +} // namespace __llvm_libc diff --git a/libc/test/src/math/CMakeLists.txt b/libc/test/src/math/CMakeLists.txt --- a/libc/test/src/math/CMakeLists.txt +++ b/libc/test/src/math/CMakeLists.txt @@ -43,6 +43,18 @@ libc.utils.FPUtil.fputil ) +add_fp_unittest( + cos_test + NEED_MPFR + SUITE + libc_math_unittests + SRCS + cos_test.cpp + DEPENDS + libc.src.math.cos + libc.utils.FPUtil.fputil +) + add_fp_unittest( sinf_test NEED_MPFR @@ -59,6 +71,18 @@ libc.utils.FPUtil.fputil ) +add_fp_unittest( + sin_test + NEED_MPFR + SUITE + libc_math_unittests + SRCS + sin_test.cpp + DEPENDS + libc.src.math.sin + libc.utils.FPUtil.fputil +) + add_fp_unittest( sincosf_test NEED_MPFR @@ -1132,6 +1156,18 @@ libc.utils.FPUtil.fputil ) +add_fp_unittest( + tan_test + NEED_MPFR + SUITE + libc_math_unittests + SRCS + tan_test.cpp + DEPENDS + libc.src.math.tan + libc.utils.FPUtil.fputil +) + add_subdirectory(generic) add_subdirectory(exhaustive) add_subdirectory(differential_testing) diff --git a/libc/test/src/math/cos_test.cpp b/libc/test/src/math/cos_test.cpp new file mode 100644 --- /dev/null +++ b/libc/test/src/math/cos_test.cpp @@ -0,0 +1,32 @@ +//===-- Unittests for cos -------------------------------------------------===// +// +// 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/math/cos.h" +#include "utils/FPUtil/TestHelpers.h" +#include "utils/MPFRWrapper/MPFRUtils.h" +#include "utils/UnitTest/Test.h" + +#include + +namespace mpfr = __llvm_libc::testing::mpfr; + +DECLARE_SPECIAL_CONSTANTS(double) + +TEST(LlvmLibccosTest, Range) { + static constexpr double _2pi = 6.283185307179586; + constexpr UIntType count = 10000000; + constexpr UIntType step = UIntType(-1) / count; + for (UIntType i = 0, v = 0; i <= count; ++i, v += step) { + double x = double(FPBits(v)); + // TODO: Expand the range of testing after range reduction is implemented. + if (isnan(x) || isinf(x) || x > _2pi || x < -_2pi) + continue; + + ASSERT_MPFR_MATCH(mpfr::Operation::Cos, x, __llvm_libc::cos(x), 1.0); + } +} diff --git a/libc/test/src/math/sin_test.cpp b/libc/test/src/math/sin_test.cpp new file mode 100644 --- /dev/null +++ b/libc/test/src/math/sin_test.cpp @@ -0,0 +1,32 @@ +//===-- Unittests for sin -------------------------------------------------===// +// +// 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/math/sin.h" +#include "utils/FPUtil/TestHelpers.h" +#include "utils/MPFRWrapper/MPFRUtils.h" +#include "utils/UnitTest/Test.h" + +#include + +namespace mpfr = __llvm_libc::testing::mpfr; + +DECLARE_SPECIAL_CONSTANTS(double) + +TEST(LlvmLibcSinTest, Range) { + static constexpr double _2pi = 6.283185307179586; + constexpr UIntType count = 10000000; + constexpr UIntType step = UIntType(-1) / count; + for (UIntType i = 0, v = 0; i <= count; ++i, v += step) { + double x = double(FPBits(v)); + // TODO: Expand the range of testing after range reduction is implemented. + if (isnan(x) || isinf(x) || x > _2pi || x < -_2pi) + continue; + + ASSERT_MPFR_MATCH(mpfr::Operation::Sin, x, __llvm_libc::sin(x), 1.0); + } +} diff --git a/libc/test/src/math/tan_test.cpp b/libc/test/src/math/tan_test.cpp new file mode 100644 --- /dev/null +++ b/libc/test/src/math/tan_test.cpp @@ -0,0 +1,32 @@ +//===-- Unittests for tan -------------------------------------------------===// +// +// 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/math/tan.h" +#include "utils/FPUtil/TestHelpers.h" +#include "utils/MPFRWrapper/MPFRUtils.h" +#include "utils/UnitTest/Test.h" + +#include + +namespace mpfr = __llvm_libc::testing::mpfr; + +DECLARE_SPECIAL_CONSTANTS(double) + +TEST(LlvmLibctanTest, Range) { + static constexpr double _2pi = 6.283185307179586; + constexpr UIntType count = 10000000; + constexpr UIntType step = UIntType(-1) / count; + for (UIntType i = 0, v = 0; i <= count; ++i, v += step) { + double x = double(FPBits(v)); + // TODO: Expand the range of testing after range reduction is implemented. + if (isnan(x) || isinf(x) || x > _2pi || x < -_2pi) + continue; + + ASSERT_MPFR_MATCH(mpfr::Operation::Tan, x, __llvm_libc::tan(x), 1.0); + } +} diff --git a/libc/utils/MPFRWrapper/MPFRUtils.h b/libc/utils/MPFRWrapper/MPFRUtils.h --- a/libc/utils/MPFRWrapper/MPFRUtils.h +++ b/libc/utils/MPFRWrapper/MPFRUtils.h @@ -32,6 +32,7 @@ Round, Sin, Sqrt, + Tan, Trunc, EndUnaryOperationsSingleOutput, diff --git a/libc/utils/MPFRWrapper/MPFRUtils.cpp b/libc/utils/MPFRWrapper/MPFRUtils.cpp --- a/libc/utils/MPFRWrapper/MPFRUtils.cpp +++ b/libc/utils/MPFRWrapper/MPFRUtils.cpp @@ -207,6 +207,12 @@ return result; } + MPFRNumber tan() const { + MPFRNumber result; + mpfr_tan(result.value, value, MPFR_RNDN); + return result; + } + MPFRNumber trunc() const { MPFRNumber result; mpfr_trunc(result.value, value); @@ -311,6 +317,8 @@ return mpfrInput.sin(); case Operation::Sqrt: return mpfrInput.sqrt(); + case Operation::Tan: + return mpfrInput.tan(); case Operation::Trunc: return mpfrInput.trunc(); default: