diff --git a/libc/cmake/modules/LLVMLibCCompileOptionRules.cmake b/libc/cmake/modules/LLVMLibCCompileOptionRules.cmake index 8643c9bb48ad4..7af67e629471c 100644 --- a/libc/cmake/modules/LLVMLibCCompileOptionRules.cmake +++ b/libc/cmake/modules/LLVMLibCCompileOptionRules.cmake @@ -152,6 +152,8 @@ function(_get_common_compile_options output_var flags) endif() list(APPEND compile_options "-Wconversion") list(APPEND compile_options "-Wno-sign-conversion") + # Silence this warning because _Complex is a part of C99. + list(APPEND compile_options "-Wno-c99-extensions") list(APPEND compile_options "-Wimplicit-fallthrough") list(APPEND compile_options "-Wwrite-strings") list(APPEND compile_options "-Wextra-semi") @@ -227,6 +229,8 @@ function(_get_common_test_compile_options output_var c_test flags) # list(APPEND compile_options "-Wimplicit-fallthrough") # list(APPEND compile_options "-Wwrite-strings") # list(APPEND compile_options "-Wextra-semi") + # Silence this warning because _Complex is a part of C99. + list(APPEND compile_options "-Wno-c99-extensions") # if(NOT CMAKE_COMPILER_IS_GNUCXX) # list(APPEND compile_options "-Wnewline-eof") # list(APPEND compile_options "-Wnonportable-system-include-path") diff --git a/libc/docs/complex.rst b/libc/docs/complex.rst new file mode 100644 index 0000000000000..09fbdd7c6179e --- /dev/null +++ b/libc/docs/complex.rst @@ -0,0 +1,65 @@ +.. include:: check.rst + +========= +complex.h +========= + +Macros +====== + ++-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+ +| | (float) | (double) | (long double) | (float16) | (float128) | C23 Definition Section | C23 Error Handling Section | ++===========+==================+=================+========================+======================+========================+========================+============================+ +| CMPLX | | | | | | 7.3.9.3 | N/A | ++-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+ + +Functions +========= + ++-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+ +| | (float) | (double) | (long double) | (float16) | (float128) | C23 Definition Section | C23 Error Handling Section | ++===========+==================+=================+========================+======================+========================+========================+============================+ +| cacos | | | | | | 7.3.5.1 | G.6.2.1 | ++-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+ +| casin | | | | | | 7.3.5.2 | N/A | ++-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+ +| catan | | | | | | 7.3.5.3 | N/A | ++-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+ +| ccos | | | | | | 7.3.5.4 | N/A | ++-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+ +| csin | | | | | | 7.3.5.5 | N/A | ++-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+ +| ctan | | | | | | 7.3.5.6 | N/A | ++-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+ +| cacosh | | | | | | 7.3.6.1 | G.6.3.1 | ++-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+ +| casinh | | | | | | 7.3.6.2 | G.6.3.2 | ++-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+ +| catanh | | | | | | 7.3.6.3 | G.6.3.3 | ++-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+ +| ccosh | | | | | | 7.3.6.4 | G.6.3.4 | ++-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+ +| csinh | | | | | | 7.3.6.5 | G.6.3.5 | ++-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+ +| ctanh | | | | | | 7.3.6.6 | G.6.3.6 | ++-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+ +| cexp | | | | | | 7.3.7.1 | G.6.4.1 | ++-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+ +| clog | | | | | | 7.3.7.2 | G.6.4.2 | ++-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+ +| cabs | | | | | | 7.3.8.1 | N/A | ++-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+ +| cpow | | | | | | 7.3.8.2 | G.6.5.1 | ++-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+ +| csqrt | | | | | | 7.3.8.3 | G.6.5.2 | ++-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+ +| carg | | | | | | 7.3.9.1 | N/A | ++-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+ +| cimag | | | | | | 7.3.9.2 | N/A | ++-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+ +| conj | | | | | | 7.3.9.4 | N/A | ++-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+ +| cproj | | | | | | 7.3.9.5 | N/A | ++-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+ +| creal | | | | | | 7.3.9.6 | N/A | ++-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+ diff --git a/libc/docs/index.rst b/libc/docs/index.rst index d089a800ab90a..6f759aa215b62 100644 --- a/libc/docs/index.rst +++ b/libc/docs/index.rst @@ -73,6 +73,7 @@ stages there is no ABI stability in any form. libc_search c23 ctype + complex signal threads setjmp diff --git a/libc/include/CMakeLists.txt b/libc/include/CMakeLists.txt index 1f3cb59f69e96..5deb5258d532f 100644 --- a/libc/include/CMakeLists.txt +++ b/libc/include/CMakeLists.txt @@ -202,6 +202,16 @@ add_header_macro( .llvm-libc-macros.assert_macros ) +add_header_macro( + complex + ../libc/newhdrgen/yaml/complex.yaml + complex.h.def + complex.h + DEPENDS + .llvm_libc_common_h + .llvm-libc-macros.complex_macros +) + add_header_macro( setjmp ../libc/newhdrgen/yaml/setjmp.yaml diff --git a/libc/include/complex.h.def b/libc/include/complex.h.def new file mode 100644 index 0000000000000..65f5765573e84 --- /dev/null +++ b/libc/include/complex.h.def @@ -0,0 +1,17 @@ +//===-- C standard library header complex.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_COMPLEX_H +#define LLVM_LIBC_COMPLEX_H + +#include "__llvm-libc-common.h" +#include "llvm-libc-macros/complex-macros.h" + +%%public_api() + +#endif // LLVM_LIBC_COMPLEX_H diff --git a/libc/include/llvm-libc-macros/CMakeLists.txt b/libc/include/llvm-libc-macros/CMakeLists.txt index 2ba437c8437f2..75194923a452f 100644 --- a/libc/include/llvm-libc-macros/CMakeLists.txt +++ b/libc/include/llvm-libc-macros/CMakeLists.txt @@ -61,6 +61,12 @@ add_macro_header( fcntl-macros.h ) +add_macro_header( + complex_macros + HDR + complex-macros.h +) + add_macro_header( features_macros HDR diff --git a/libc/include/llvm-libc-macros/complex-macros.h b/libc/include/llvm-libc-macros/complex-macros.h new file mode 100644 index 0000000000000..427c68d289e0b --- /dev/null +++ b/libc/include/llvm-libc-macros/complex-macros.h @@ -0,0 +1,24 @@ +//===-- Definition of macros to be used with complex functions ------------===// +// +// 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_MACROS_COMPLEX_MACROS_H +#define __LLVM_LIBC_MACROS_COMPLEX_MACROS_H + +#ifndef __STDC_NO_COMPLEX__ + +#define __STDC_VERSION_COMPLEX_H__ 202311L + +#define complex _Complex +#define _Complex_I ((_Complex float)1.0fi) +#define I _Complex_I + +// TODO: Add imaginary macros once GCC or Clang support _Imaginary builtin-type. + +#endif + +#endif // __LLVM_LIBC_MACROS_COMPLEX_MACROS_H diff --git a/libc/src/__support/CPP/type_traits.h b/libc/src/__support/CPP/type_traits.h index d50b6612656db..cef4e5d1f0b13 100644 --- a/libc/src/__support/CPP/type_traits.h +++ b/libc/src/__support/CPP/type_traits.h @@ -25,6 +25,7 @@ #include "src/__support/CPP/type_traits/is_array.h" #include "src/__support/CPP/type_traits/is_base_of.h" #include "src/__support/CPP/type_traits/is_class.h" +#include "src/__support/CPP/type_traits/is_complex.h" #include "src/__support/CPP/type_traits/is_const.h" #include "src/__support/CPP/type_traits/is_constant_evaluated.h" #include "src/__support/CPP/type_traits/is_convertible.h" diff --git a/libc/src/__support/CPP/type_traits/is_complex.h b/libc/src/__support/CPP/type_traits/is_complex.h new file mode 100644 index 0000000000000..4f5ee9abdb33a --- /dev/null +++ b/libc/src/__support/CPP/type_traits/is_complex.h @@ -0,0 +1,40 @@ +//===-- is_complex type_traits ----------------------------------*- 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___SUPPORT_CPP_TYPE_TRAITS_IS_COMPLEX_H +#define LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_COMPLEX_H + +#include "src/__support/CPP/type_traits/is_same.h" +#include "src/__support/CPP/type_traits/remove_cv.h" + +namespace LIBC_NAMESPACE_DECL { +namespace cpp { + +// is_complex +template struct is_complex { +private: + template + LIBC_INLINE_VAR static constexpr bool __is_unqualified_any_of() { + return (... || is_same_v, Args>); + } + +public: + LIBC_INLINE_VAR static constexpr bool value = + __is_unqualified_any_of(); +}; +template +LIBC_INLINE_VAR constexpr bool is_complex_v = is_complex::value; +template +LIBC_INLINE_VAR constexpr bool is_complex_type_same() { + return is_same_v, T2>; +} + +} // namespace cpp +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_COMPLEX_H diff --git a/libc/test/UnitTest/FPMatcher.h b/libc/test/UnitTest/FPMatcher.h index 3cf0b04952ec0..5220b1245bf3a 100644 --- a/libc/test/UnitTest/FPMatcher.h +++ b/libc/test/UnitTest/FPMatcher.h @@ -60,10 +60,95 @@ template class FPMatcher : public Matcher { } }; +template class CFPMatcher : public Matcher { + static_assert( + cpp::is_complex_v, + "CFPMatcher can only be used with complex floating point values."); + static_assert(Condition == TestCond::EQ || Condition == TestCond::NE, + "Unsupported CFPMatcher test condition."); + + T expected; + T actual; + +public: + CFPMatcher(T expectedValue) : expected(expectedValue) {} + + template bool matchComplex() { + CFT *actualCmplxPtr = reinterpret_cast(&actual); + CFT *expectedCmplxPtr = reinterpret_cast(&expected); + CFT actualReal = actualCmplxPtr[0]; + CFT actualImag = actualCmplxPtr[1]; + CFT expectedReal = expectedCmplxPtr[0]; + CFT expectedImag = expectedCmplxPtr[1]; + fputil::FPBits actualRealBits(actualReal), + expectedRealBits(expectedReal); + fputil::FPBits actualImagBits(actualImag), + expectedImagBits(expectedImag); + if (Condition == TestCond::EQ) + return ((actualRealBits.is_nan() && expectedRealBits.is_nan()) || + (actualRealBits.uintval() == expectedRealBits.uintval())) && + ((actualImagBits.is_nan() && expectedImagBits.is_nan()) || + (actualImagBits.uintval() == expectedImagBits.uintval())); + + // If condition == TestCond::NE. + if (actualRealBits.is_nan() && expectedRealBits.is_nan()) + return !expectedRealBits.is_nan() && !expectedImagBits.is_nan(); + if (actualRealBits.is_nan()) + return !expectedRealBits.is_nan(); + if (actualImagBits.is_nan()) + return !expectedImagBits.is_nan(); + return (expectedRealBits.is_nan() || + actualRealBits.uintval() != expectedRealBits.uintval()) && + (expectedImagBits.is_nan() || + actualImagBits.uintval() != expectedImagBits.uintval()); + } + + template void explainErrorComplex() { + CFT *actualCmplxPtr = reinterpret_cast(&actual); + CFT *expectedCmplxPtr = reinterpret_cast(&expected); + CFT actualReal = actualCmplxPtr[0]; + CFT actualImag = actualCmplxPtr[1]; + CFT expectedReal = expectedCmplxPtr[0]; + CFT expectedImag = expectedCmplxPtr[1]; + tlog << "Expected complex floating point value: " + << str(fputil::FPBits(expectedReal)) + " + " + + str(fputil::FPBits(expectedImag)) + "i" + << '\n'; + tlog << "Actual complex floating point value: " + << str(fputil::FPBits(actualReal)) + " + " + + str(fputil::FPBits(actualImag)) + "i" + << '\n'; + } + + bool match(T actualValue) { + actual = actualValue; + if (cpp::is_complex_type_same()) + return matchComplex(); + else if (cpp::is_complex_type_same()) + return matchComplex(); + else if (cpp::is_complex_type_same()) + return matchComplex(); + } + + void explainError() override { + if (cpp::is_complex_type_same()) + return explainErrorComplex(); + else if (cpp::is_complex_type_same()) + return explainErrorComplex(); + else if (cpp::is_complex_type_same()) + return explainErrorComplex(); + } +}; + template FPMatcher getMatcher(T expectedValue) { return FPMatcher(expectedValue); } +template +CFPMatcher getMatcherComplex(T expectedValue) { + return CFPMatcher(expectedValue); +} + template struct FPTest : public Test { using FPBits = LIBC_NAMESPACE::fputil::FPBits; using StorageType = typename FPBits::StorageType; @@ -125,6 +210,10 @@ template struct FPTest : public Test { EXPECT_THAT(actual, LIBC_NAMESPACE::testing::getMatcher< \ LIBC_NAMESPACE::testing::TestCond::EQ>(expected)) +#define EXPECT_CFP_EQ(expected, actual) \ + EXPECT_THAT(actual, LIBC_NAMESPACE::testing::getMatcherComplex< \ + LIBC_NAMESPACE::testing::TestCond::EQ>(expected)) + #define TEST_FP_EQ(expected, actual) \ LIBC_NAMESPACE::testing::getMatcher( \ expected) \ diff --git a/libc/test/include/CMakeLists.txt b/libc/test/include/CMakeLists.txt index 9218516062879..0d882eb49a738 100644 --- a/libc/test/include/CMakeLists.txt +++ b/libc/test/include/CMakeLists.txt @@ -11,6 +11,16 @@ add_libc_test( libc.include.llvm-libc-macros.assert_macros ) +add_libc_test( + complex_test + SUITE + libc_include_tests + SRCS + complex_test.cpp + DEPENDS + libc.include.llvm-libc-macros.complex_macros +) + add_libc_test( sys_queue_test SUITE diff --git a/libc/test/include/complex_test.cpp b/libc/test/include/complex_test.cpp new file mode 100644 index 0000000000000..f6bfe997d98dd --- /dev/null +++ b/libc/test/include/complex_test.cpp @@ -0,0 +1,19 @@ +//===-- Unittests for complex ---------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDSList-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "include/llvm-libc-macros/complex-macros.h" +#include "test/UnitTest/FPMatcher.h" +#include "test/UnitTest/Test.h" + +TEST(LlvmLibcComplexTest, VersionMacro) { + EXPECT_EQ(__STDC_VERSION_COMPLEX_H__, 202311L); +} + +TEST(LlvmLibcComplexTest, IMacro) { EXPECT_CFP_EQ(1.0fi, I); } + +TEST(LlvmLibcComplexTest, _Complex_IMacro) { EXPECT_CFP_EQ(1.0fi, _Complex_I); }