Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions libcxx/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -749,6 +749,7 @@ config_define(${LIBCXX_ENABLE_UNICODE} _LIBCPP_HAS_UNICODE)
config_define(${LIBCXX_ENABLE_WIDE_CHARACTERS} _LIBCPP_HAS_WIDE_CHARACTERS)
config_define(${LIBCXX_ENABLE_TIME_ZONE_DATABASE} _LIBCPP_HAS_TIME_ZONE_DATABASE)
config_define(${LIBCXX_ENABLE_VENDOR_AVAILABILITY_ANNOTATIONS} _LIBCPP_HAS_VENDOR_AVAILABILITY_ANNOTATIONS)
config_define_if(C_SUPPORTS_C99_COMPLEX _LIBCPP_HAS_C99_COMPLEX)

# TODO: Remove in LLVM 21. We're leaving an error to make this fail explicitly.
if (LIBCXX_ENABLE_ASSERTIONS)
Expand Down
25 changes: 25 additions & 0 deletions libcxx/cmake/config-ix.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,31 @@ endif()

check_symbol_exists(__PICOLIBC__ "string.h" PICOLIBC)

# Check for the existence of <complex.h> complex math functions.
# This is necessary even though libcxx uses the builtin versions
# of these functions, because if the builtin cannot be used, a reference
# to the library function is emitted. Using compiler builtins for these
# functions requires corresponding C99 library functions to be present.

cmake_push_check_state()
list(APPEND CMAKE_REQUIRED_LIBRARIES m)
check_c_source_compiles("
#include <complex.h>
typedef __complex__ float float_type;
typedef __complex__ double double_type;
typedef __complex__ long double ld_type;
volatile float_type tmpf;
volatile double_type tmpd;
volatile ld_type tmpld;
int main(void) {
tmpf = cexpf(tmpf);
tmpd = cexp(tmpd);
tmpld = cexpl(tmpld);
return 0;
}
" C_SUPPORTS_C99_COMPLEX)
cmake_pop_check_state()

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We generally try to avoid these kinds of shenanigans. Why is this required?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is required when libm is missing these functions. If they are missing, we can fall back to the old implementation, which is not using builtin_cexp functions. At least one build configuration encounters this issue: Android 5.0 x86.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have removed these shenanigans. After that, there are following fails in CI:

  1. Linking errors for Android 5.0, x86 NDK, because underlying libc doesn't provide cexp.
  2. Errors in std\numerics\complex.number\complex.transcendentals\exp.pass.cpp for some windows and macos jobs.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should guard calling the libc version behind !defined(__ANDROID__) || __ANDROID_API__ >= 23. It's quite unfortunate, but I expect support for older android version will be dropped somewhat soon, so it's likely just temporary (CC @pirama-arumuga-nainar @Sharjeel-Khan maybe you know more?). The errors inside the test will have to be looked at. My guess is that the test is simply wrong, but I don't know for certain.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We will raise the minimum supported version to API 23 next year in NDK r31 as seen in android/ndk#2188. The Android 5 builder is based on API 21 so it should get dropped . We were using it mostly for 32-bit checks I believe so I might have to find another image to replace it.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(cc: @DanAlbert )

# Check libraries
if(WIN32 AND NOT MINGW)
# TODO(compnerd) do we want to support an emulation layer that allows for the
Expand Down
1 change: 1 addition & 0 deletions libcxx/include/__config_site.in
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#cmakedefine01 _LIBCPP_HAS_WIDE_CHARACTERS
#cmakedefine01 _LIBCPP_HAS_TIME_ZONE_DATABASE
#cmakedefine01 _LIBCPP_INSTRUMENTED_WITH_ASAN
#cmakedefine01 _LIBCPP_HAS_C99_COMPLEX

// PSTL backends
#cmakedefine _LIBCPP_PSTL_BACKEND_SERIAL
Expand Down
15 changes: 15 additions & 0 deletions libcxx/include/complex
Original file line number Diff line number Diff line change
Expand Up @@ -1074,6 +1074,16 @@ _LIBCPP_HIDE_FROM_ABI complex<_Tp> sqrt(const complex<_Tp>& __x) {

// exp

#if _LIBCPP_HAS_C99_COMPLEX
_LIBCPP_HIDE_FROM_ABI inline _Complex float __cexp(_Complex float __v) { return __builtin_cexpf(__v); }
_LIBCPP_HIDE_FROM_ABI inline _Complex double __cexp(_Complex double __v) { return __builtin_cexp(__v); }
_LIBCPP_HIDE_FROM_ABI inline _Complex long double __cexp(_Complex long double __v) { return __builtin_cexpl(__v); }

template <class _Tp>
_LIBCPP_HIDE_FROM_ABI complex<_Tp> exp(const complex<_Tp>& __x) {
return complex<_Tp>(__from_builtin_tag(), std::__cexp(__x.__builtin()));
}
#else
template <class _Tp>
_LIBCPP_HIDE_FROM_ABI complex<_Tp> exp(const complex<_Tp>& __x) {
_Tp __i = __x.imag();
Expand All @@ -1090,9 +1100,14 @@ _LIBCPP_HIDE_FROM_ABI complex<_Tp> exp(const complex<_Tp>& __x) {
return complex<_Tp>(__x.real(), __i);
}
}
if (std::isinf(__e)) {
_Tp __e2 = std::exp(__x.real() * _Tp(0.5));
return complex<_Tp>(__e2 * std::cos(__i) * __e2, __e2 * std::sin(__i) * __e2);
}
_Tp __e = std::exp(__x.real());
return complex<_Tp>(__e * std::cos(__i), __e * std::sin(__i));
}
#endif

// pow

Expand Down
40 changes: 40 additions & 0 deletions libcxx/test/libcxx/numerics/complex.number/exp.pass.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//

// <complex>

// template<class T>
// complex<T>
// exp(const complex<T>& x);

#include <complex>
#include <cassert>
#include <cmath>

#include "test_macros.h"

template <class T>
void test_overflow_case() {
typedef std::complex<T> C;

// In this case, the overflow of exp(real_part) is compensated when
// sin(imag_part) is close to zero, resulting in a finite imaginary part.
C z(T(90.0238094), T(5.900613e-39));
C result = std::exp(z);

assert(std::isinf(result.real()));
assert(result.real() > 0);

assert(std::isfinite(result.imag()));
assert(std::abs(result.imag() - T(7.3746)) < T(1.0));
}

int main(int, char**) {
test_overflow_case<float>();
return 0;
}
Loading