[libcxx-commits] [libcxx] [libc++] Use _Complex for multiplication and division of complex floating point types (PR #83575)

via libcxx-commits libcxx-commits at lists.llvm.org
Fri Mar 1 06:37:21 PST 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-libcxx

Author: Nikolas Klauser (philnik777)

<details>
<summary>Changes</summary>

This significantly simplifies the implementation and improves the codegen. The only downside is that the accuracy can be marginally worse, but that is up to the compiler to decide with this change, which means is can be controlled by compiler flags.

Spies: ldionne, Mordante, libcxx-commits

Differential Revision: https://reviews.llvm.org/D155312


---

Patch is 24.76 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/83575.diff


7 Files Affected:

- (modified) libcxx/include/cmath (-155) 
- (modified) libcxx/include/complex (+84-145) 
- (modified) libcxx/test/std/numerics/complex.number/complex.member.ops/divide_equal_complex.pass.cpp (+12-11) 
- (modified) libcxx/test/std/numerics/complex.number/complex.ops/complex_divide_complex.pass.cpp (+6-3) 
- (modified) libcxx/test/std/numerics/complex.number/complex.ops/complex_times_complex.pass.cpp (+1-1) 
- (modified) libcxx/test/std/numerics/complex.number/complex.ops/scalar_divide_complex.pass.cpp (+5-1) 
- (added) libcxx/test/support/floating_pointer_helpers.h (+21) 


``````````diff
diff --git a/libcxx/include/cmath b/libcxx/include/cmath
index 798ddb4963b0ec..390844cd54d4dd 100644
--- a/libcxx/include/cmath
+++ b/libcxx/include/cmath
@@ -611,161 +611,6 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool __constexpr_isfinite(_A1 __lcpp_x)
   return __builtin_isfinite(__lcpp_x);
 }
 
-_LIBCPP_CONSTEXPR inline _LIBCPP_HIDE_FROM_ABI float __constexpr_copysign(float __x, float __y) _NOEXCEPT {
-  return __builtin_copysignf(__x, __y);
-}
-
-_LIBCPP_CONSTEXPR inline _LIBCPP_HIDE_FROM_ABI double __constexpr_copysign(double __x, double __y) _NOEXCEPT {
-  return __builtin_copysign(__x, __y);
-}
-
-_LIBCPP_CONSTEXPR inline _LIBCPP_HIDE_FROM_ABI long double
-__constexpr_copysign(long double __x, long double __y) _NOEXCEPT {
-  return __builtin_copysignl(__x, __y);
-}
-
-template <class _A1,
-          class _A2,
-          __enable_if_t<std::is_arithmetic<_A1>::value && std::is_arithmetic<_A2>::value, int> = 0>
-_LIBCPP_CONSTEXPR inline _LIBCPP_HIDE_FROM_ABI typename __promote<_A1, _A2>::type
-__constexpr_copysign(_A1 __x, _A2 __y) _NOEXCEPT {
-  typedef typename std::__promote<_A1, _A2>::type __result_type;
-  static_assert((!(std::_IsSame<_A1, __result_type>::value && std::_IsSame<_A2, __result_type>::value)), "");
-  return __builtin_copysign((__result_type)__x, (__result_type)__y);
-}
-
-inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR float __constexpr_fabs(float __x) _NOEXCEPT {
-  return __builtin_fabsf(__x);
-}
-
-inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR double __constexpr_fabs(double __x) _NOEXCEPT {
-  return __builtin_fabs(__x);
-}
-
-inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR long double __constexpr_fabs(long double __x) _NOEXCEPT {
-  return __builtin_fabsl(__x);
-}
-
-template <class _Tp, __enable_if_t<is_integral<_Tp>::value, int> = 0>
-_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR double __constexpr_fabs(_Tp __x) _NOEXCEPT {
-  return __builtin_fabs(static_cast<double>(__x));
-}
-
-inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 float __constexpr_fmax(float __x, float __y) _NOEXCEPT {
-#if !__has_constexpr_builtin(__builtin_fmaxf)
-  if (__libcpp_is_constant_evaluated()) {
-    if (std::__constexpr_isnan(__x))
-      return __y;
-    if (std::__constexpr_isnan(__y))
-      return __x;
-    return __x < __y ? __y : __x;
-  }
-#endif
-  return __builtin_fmaxf(__x, __y);
-}
-
-inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 double __constexpr_fmax(double __x, double __y) _NOEXCEPT {
-#if !__has_constexpr_builtin(__builtin_fmax)
-  if (__libcpp_is_constant_evaluated()) {
-    if (std::__constexpr_isnan(__x))
-      return __y;
-    if (std::__constexpr_isnan(__y))
-      return __x;
-    return __x < __y ? __y : __x;
-  }
-#endif
-  return __builtin_fmax(__x, __y);
-}
-
-inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 long double
-__constexpr_fmax(long double __x, long double __y) _NOEXCEPT {
-#if !__has_constexpr_builtin(__builtin_fmaxl)
-  if (__libcpp_is_constant_evaluated()) {
-    if (std::__constexpr_isnan(__x))
-      return __y;
-    if (std::__constexpr_isnan(__y))
-      return __x;
-    return __x < __y ? __y : __x;
-  }
-#endif
-  return __builtin_fmaxl(__x, __y);
-}
-
-template <class _Tp, class _Up, __enable_if_t<is_arithmetic<_Tp>::value && is_arithmetic<_Up>::value, int> = 0>
-_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 typename __promote<_Tp, _Up>::type
-__constexpr_fmax(_Tp __x, _Up __y) _NOEXCEPT {
-  using __result_type = typename __promote<_Tp, _Up>::type;
-  return std::__constexpr_fmax(static_cast<__result_type>(__x), static_cast<__result_type>(__y));
-}
-
-template <class _Tp>
-_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _Tp __constexpr_logb(_Tp __x) {
-#if !__has_constexpr_builtin(__builtin_logb)
-  if (__libcpp_is_constant_evaluated()) {
-    if (__x == _Tp(0)) {
-      // raise FE_DIVBYZERO
-      return -numeric_limits<_Tp>::infinity();
-    }
-
-    if (std::__constexpr_isinf(__x))
-      return numeric_limits<_Tp>::infinity();
-
-    if (std::__constexpr_isnan(__x))
-      return numeric_limits<_Tp>::quiet_NaN();
-
-    __x                      = std::__constexpr_fabs(__x);
-    unsigned long long __exp = 0;
-    while (__x >= numeric_limits<_Tp>::radix) {
-      __x /= numeric_limits<_Tp>::radix;
-      __exp += 1;
-    }
-    return _Tp(__exp);
-  }
-#endif // !__has_constexpr_builtin(__builtin_logb)
-  return __builtin_logb(__x);
-}
-
-template <class _Tp>
-_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Tp __constexpr_scalbn(_Tp __x, int __exp) {
-#if !__has_constexpr_builtin(__builtin_scalbln)
-  if (__libcpp_is_constant_evaluated()) {
-    if (__x == _Tp(0))
-      return __x;
-
-    if (std::__constexpr_isinf(__x))
-      return __x;
-
-    if (__exp == _Tp(0))
-      return __x;
-
-    if (std::__constexpr_isnan(__x))
-      return numeric_limits<_Tp>::quiet_NaN();
-
-    _Tp __mult(1);
-    if (__exp > 0) {
-      __mult = numeric_limits<_Tp>::radix;
-      --__exp;
-    } else {
-      ++__exp;
-      __exp = -__exp;
-      __mult /= numeric_limits<_Tp>::radix;
-    }
-
-    while (__exp > 0) {
-      if (!(__exp & 1)) {
-        __mult *= __mult;
-        __exp >>= 1;
-      } else {
-        __x *= __mult;
-        --__exp;
-      }
-    }
-    return __x;
-  }
-#endif // !__has_constexpr_builtin(__builtin_scalbln)
-  return __builtin_scalbn(__x, __exp);
-}
-
 #if _LIBCPP_STD_VER >= 20
 template <typename _Fp>
 _LIBCPP_HIDE_FROM_ABI constexpr _Fp __lerp(_Fp __a, _Fp __b, _Fp __t) noexcept {
diff --git a/libcxx/include/complex b/libcxx/include/complex
index 0aba60e514ba22..8f6239035d5ca3 100644
--- a/libcxx/include/complex
+++ b/libcxx/include/complex
@@ -281,10 +281,19 @@ _LIBCPP_BEGIN_NAMESPACE_STD
 template <class _Tp>
 class _LIBCPP_TEMPLATE_VIS complex;
 
-template <class _Tp>
+template <class _Tp, __enable_if_t<is_floating_point<_Tp>::value, int> = 0>
 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 complex<_Tp>
 operator*(const complex<_Tp>& __z, const complex<_Tp>& __w);
-template <class _Tp>
+
+template <class _Tp, __enable_if_t<!is_floating_point<_Tp>::value, int> = 0>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 complex<_Tp>
+operator*(const complex<_Tp>& __z, const complex<_Tp>& __w);
+
+template <class _Tp, __enable_if_t<is_floating_point<_Tp>::value, int> = 0>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 complex<_Tp>
+operator/(const complex<_Tp>& __x, const complex<_Tp>& __y);
+
+template <class _Tp, __enable_if_t<!is_floating_point<_Tp>::value, int> = 0>
 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 complex<_Tp>
 operator/(const complex<_Tp>& __x, const complex<_Tp>& __y);
 
@@ -384,6 +393,23 @@ class _LIBCPP_TEMPLATE_VIS complex<double>;
 template <>
 class _LIBCPP_TEMPLATE_VIS complex<long double>;
 
+struct __from_builtin_tag {};
+
+template <class _Tp>
+using __complex_t =
+    __conditional_t<is_same<_Tp, float>::value,
+                    _Complex float,
+                    __conditional_t<is_same<_Tp, double>::value, _Complex double, _Complex long double> >;
+
+template <class _Tp>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR __complex_t<_Tp> __make_complex(_Tp __re, _Tp __im) {
+#if __has_builtin(__builtin_complex)
+  return __builtin_complex(__re, __im);
+#else
+  return __complex_t<_Tp>{__re, __im};
+#endif
+}
+
 template <>
 class _LIBCPP_TEMPLATE_VIS complex<float> {
   float __re_;
@@ -393,6 +419,10 @@ public:
   typedef float value_type;
 
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR complex(float __re = 0.0f, float __im = 0.0f) : __re_(__re), __im_(__im) {}
+
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR complex(__from_builtin_tag, _Complex float __v)
+      : __re_(__real__ __v), __im_(__imag__ __v) {}
+
   _LIBCPP_HIDE_FROM_ABI explicit _LIBCPP_CONSTEXPR complex(const complex<double>& __c);
   _LIBCPP_HIDE_FROM_ABI explicit _LIBCPP_CONSTEXPR complex(const complex<long double>& __c);
 
@@ -402,6 +432,12 @@ public:
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void real(value_type __re) { __re_ = __re; }
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void imag(value_type __im) { __im_ = __im; }
 
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _Complex float __builtin() const { return std::__make_complex(__re_, __im_); }
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 void __builtin(_Complex float __f) {
+    __re_ = __real__ __f;
+    __im_ = __imag__ __f;
+  }
+
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 complex& operator=(float __re) {
     __re_ = __re;
     __im_ = value_type();
@@ -479,6 +515,10 @@ public:
   typedef double value_type;
 
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR complex(double __re = 0.0, double __im = 0.0) : __re_(__re), __im_(__im) {}
+
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR complex(__from_builtin_tag, _Complex double __v)
+      : __re_(__real__ __v), __im_(__imag__ __v) {}
+
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR complex(const complex<float>& __c);
   _LIBCPP_HIDE_FROM_ABI explicit _LIBCPP_CONSTEXPR complex(const complex<long double>& __c);
 
@@ -488,6 +528,15 @@ public:
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void real(value_type __re) { __re_ = __re; }
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void imag(value_type __im) { __im_ = __im; }
 
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _Complex double __builtin() const {
+    return std::__make_complex(__re_, __im_);
+  }
+
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 void __builtin(_Complex double __f) {
+    __re_ = __real__ __f;
+    __im_ = __imag__ __f;
+  }
+
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 complex& operator=(double __re) {
     __re_ = __re;
     __im_ = value_type();
@@ -566,6 +615,10 @@ public:
 
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR complex(long double __re = 0.0L, long double __im = 0.0L)
       : __re_(__re), __im_(__im) {}
+
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR complex(__from_builtin_tag, _Complex long double __v)
+      : __re_(__real__ __v), __im_(__imag__ __v) {}
+
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR complex(const complex<float>& __c);
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR complex(const complex<double>& __c);
 
@@ -575,6 +628,15 @@ public:
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void real(value_type __re) { __re_ = __re; }
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void imag(value_type __im) { __im_ = __im; }
 
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _Complex long double __builtin() const {
+    return std::__make_complex(__re_, __im_);
+  }
+
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 void __builtin(_Complex long double __f) {
+    __re_ = __real__ __f;
+    __im_ = __imag__ __f;
+  }
+
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 complex& operator=(long double __re) {
     __re_ = __re;
     __im_ = value_type();
@@ -709,7 +771,13 @@ operator-(const _Tp& __x, const complex<_Tp>& __y) {
   return __t;
 }
 
-template <class _Tp>
+template <class _Tp, __enable_if_t<is_floating_point<_Tp>::value, int> >
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 complex<_Tp>
+operator*(const complex<_Tp>& __lhs, const complex<_Tp>& __rhs) {
+  return complex<_Tp>(__from_builtin_tag(), __lhs.__builtin() * __rhs.__builtin());
+}
+
+template <class _Tp, __enable_if_t<!is_floating_point<_Tp>::value, int> >
 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 complex<_Tp>
 operator*(const complex<_Tp>& __z, const complex<_Tp>& __w) {
   _Tp __a = __z.real();
@@ -717,78 +785,7 @@ operator*(const complex<_Tp>& __z, const complex<_Tp>& __w) {
   _Tp __c = __w.real();
   _Tp __d = __w.imag();
 
-  // Avoid floating point operations that are invalid during constant evaluation
-  if (__libcpp_is_constant_evaluated()) {
-    bool __z_zero = __a == _Tp(0) && __b == _Tp(0);
-    bool __w_zero = __c == _Tp(0) && __d == _Tp(0);
-    bool __z_inf  = std::__constexpr_isinf(__a) || std::__constexpr_isinf(__b);
-    bool __w_inf  = std::__constexpr_isinf(__c) || std::__constexpr_isinf(__d);
-    bool __z_nan =
-        !__z_inf && ((std::__constexpr_isnan(__a) && std::__constexpr_isnan(__b)) ||
-                     (std::__constexpr_isnan(__a) && __b == _Tp(0)) || (__a == _Tp(0) && std::__constexpr_isnan(__b)));
-    bool __w_nan =
-        !__w_inf && ((std::__constexpr_isnan(__c) && std::__constexpr_isnan(__d)) ||
-                     (std::__constexpr_isnan(__c) && __d == _Tp(0)) || (__c == _Tp(0) && std::__constexpr_isnan(__d)));
-    if (__z_nan || __w_nan) {
-      return complex<_Tp>(_Tp(numeric_limits<_Tp>::quiet_NaN()), _Tp(0));
-    }
-    if (__z_inf || __w_inf) {
-      if (__z_zero || __w_zero) {
-        return complex<_Tp>(_Tp(numeric_limits<_Tp>::quiet_NaN()), _Tp(0));
-      }
-      return complex<_Tp>(_Tp(numeric_limits<_Tp>::infinity()), _Tp(numeric_limits<_Tp>::infinity()));
-    }
-    bool __z_nonzero_nan = !__z_inf && !__z_nan && (std::__constexpr_isnan(__a) || std::__constexpr_isnan(__b));
-    bool __w_nonzero_nan = !__w_inf && !__w_nan && (std::__constexpr_isnan(__c) || std::__constexpr_isnan(__d));
-    if (__z_nonzero_nan || __w_nonzero_nan) {
-      return complex<_Tp>(_Tp(numeric_limits<_Tp>::quiet_NaN()), _Tp(0));
-    }
-  }
-
-  _Tp __ac = __a * __c;
-  _Tp __bd = __b * __d;
-  _Tp __ad = __a * __d;
-  _Tp __bc = __b * __c;
-  _Tp __x  = __ac - __bd;
-  _Tp __y  = __ad + __bc;
-  if (std::__constexpr_isnan(__x) && std::__constexpr_isnan(__y)) {
-    bool __recalc = false;
-    if (std::__constexpr_isinf(__a) || std::__constexpr_isinf(__b)) {
-      __a = std::__constexpr_copysign(std::__constexpr_isinf(__a) ? _Tp(1) : _Tp(0), __a);
-      __b = std::__constexpr_copysign(std::__constexpr_isinf(__b) ? _Tp(1) : _Tp(0), __b);
-      if (std::__constexpr_isnan(__c))
-        __c = std::__constexpr_copysign(_Tp(0), __c);
-      if (std::__constexpr_isnan(__d))
-        __d = std::__constexpr_copysign(_Tp(0), __d);
-      __recalc = true;
-    }
-    if (std::__constexpr_isinf(__c) || std::__constexpr_isinf(__d)) {
-      __c = std::__constexpr_copysign(std::__constexpr_isinf(__c) ? _Tp(1) : _Tp(0), __c);
-      __d = std::__constexpr_copysign(std::__constexpr_isinf(__d) ? _Tp(1) : _Tp(0), __d);
-      if (std::__constexpr_isnan(__a))
-        __a = std::__constexpr_copysign(_Tp(0), __a);
-      if (std::__constexpr_isnan(__b))
-        __b = std::__constexpr_copysign(_Tp(0), __b);
-      __recalc = true;
-    }
-    if (!__recalc && (std::__constexpr_isinf(__ac) || std::__constexpr_isinf(__bd) || std::__constexpr_isinf(__ad) ||
-                      std::__constexpr_isinf(__bc))) {
-      if (std::__constexpr_isnan(__a))
-        __a = std::__constexpr_copysign(_Tp(0), __a);
-      if (std::__constexpr_isnan(__b))
-        __b = std::__constexpr_copysign(_Tp(0), __b);
-      if (std::__constexpr_isnan(__c))
-        __c = std::__constexpr_copysign(_Tp(0), __c);
-      if (std::__constexpr_isnan(__d))
-        __d = std::__constexpr_copysign(_Tp(0), __d);
-      __recalc = true;
-    }
-    if (__recalc) {
-      __x = _Tp(INFINITY) * (__a * __c - __b * __d);
-      __y = _Tp(INFINITY) * (__a * __d + __b * __c);
-    }
-  }
-  return complex<_Tp>(__x, __y);
+  return complex<_Tp>((__a * __c) - (__b * __d), (__a * __d) + (__b * __c));
 }
 
 template <class _Tp>
@@ -807,80 +804,22 @@ operator*(const _Tp& __x, const complex<_Tp>& __y) {
   return __t;
 }
 
-template <class _Tp>
+template <class _Tp, __enable_if_t<is_floating_point<_Tp>::value, int> >
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 complex<_Tp>
+operator/(const complex<_Tp>& __lhs, const complex<_Tp>& __rhs) {
+  return complex<_Tp>(__from_builtin_tag(), __lhs.__builtin() / __rhs.__builtin());
+}
+
+template <class _Tp, __enable_if_t<!is_floating_point<_Tp>::value, int> >
 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 complex<_Tp>
 operator/(const complex<_Tp>& __z, const complex<_Tp>& __w) {
-  int __ilogbw = 0;
-  _Tp __a      = __z.real();
-  _Tp __b      = __z.imag();
-  _Tp __c      = __w.real();
-  _Tp __d      = __w.imag();
-  _Tp __logbw  = std::__constexpr_logb(std::__constexpr_fmax(std::__constexpr_fabs(__c), std::__constexpr_fabs(__d)));
-  if (std::__constexpr_isfinite(__logbw)) {
-    __ilogbw = static_cast<int>(__logbw);
-    __c      = std::__constexpr_scalbn(__c, -__ilogbw);
-    __d      = std::__constexpr_scalbn(__d, -__ilogbw);
-  }
-
-  // Avoid floating point operations that are invalid during constant evaluation
-  if (__libcpp_is_constant_evaluated()) {
-    bool __z_zero = __a == _Tp(0) && __b == _Tp(0);
-    bool __w_zero = __c == _Tp(0) && __d == _Tp(0);
-    bool __z_inf  = std::__constexpr_isinf(__a) || std::__constexpr_isinf(__b);
-    bool __w_inf  = std::__constexpr_isinf(__c) || std::__constexpr_isinf(__d);
-    bool __z_nan =
-        !__z_inf && ((std::__constexpr_isnan(__a) && std::__constexpr_isnan(__b)) ||
-                     (std::__constexpr_isnan(__a) && __b == _Tp(0)) || (__a == _Tp(0) && std::__constexpr_isnan(__b)));
-    bool __w_nan =
-        !__w_inf && ((std::__constexpr_isnan(__c) && std::__constexpr_isnan(__d)) ||
-                     (std::__constexpr_isnan(__c) && __d == _Tp(0)) || (__c == _Tp(0) && std::__constexpr_isnan(__d)));
-    if ((__z_nan || __w_nan) || (__z_inf && __w_inf)) {
-      return complex<_Tp>(_Tp(numeric_limits<_Tp>::quiet_NaN()), _Tp(0));
-    }
-    bool __z_nonzero_nan = !__z_inf && !__z_nan && (std::__constexpr_isnan(__a) || std::__constexpr_isnan(__b));
-    bool __w_nonzero_nan = !__w_inf && !__w_nan && (std::__constexpr_isnan(__c) || std::__constexpr_isnan(__d));
-    if (__z_nonzero_nan || __w_nonzero_nan) {
-      if (__w_zero) {
-        return complex<_Tp>(_Tp(numeric_limits<_Tp>::infinity()), _Tp(numeric_limits<_Tp>::infinity()));
-      }
-      return complex<_Tp>(_Tp(numeric_limits<_Tp>::quiet_NaN()), _Tp(0));
-    }
-    if (__w_inf) {
-      return complex<_Tp>(_Tp(0), _Tp(0));
-    }
-    if (__z_inf) {
-      return complex<_Tp>(_Tp(numeric_limits<_Tp>::infinity()), _Tp(numeric_limits<_Tp>::infinity()));
-    }
-    if (__w_zero) {
-      if (__z_zero) {
-        return complex<_Tp>(_Tp(numeric_limits<_Tp>::quiet_NaN()), _Tp(0));
-      }
-      return complex<_Tp>(_Tp(numeric_limits<_Tp>::infinity()), _Tp(numeric_limits<_Tp>::infinity()));
-    }
-  }
+  _Tp __a = __z.real();
+  _Tp __b = __z.imag();
+  _Tp __c = __w.real();
+  _Tp __d = __w.imag();
 
   _Tp __denom = __c * __c + __d * __d;
-  _Tp __x     = std::__constexpr_scalbn((__a * __c + __b * __d) / __denom, -__ilogbw);
-  _Tp __y     = std::__constexpr_scalbn((__b * __c - __a * __d) / __denom, -__ilogbw);
-  if (std::__constexpr_isnan(__x) && std::__constexpr_isnan(__y)) {
-    if ((__denom == _Tp(0)) && (!std::__constexpr_isnan(__a) || !std::__constexpr_isnan(__b))) {
-      __x = std::__constexpr_copysign(_Tp(INFINITY), __c) * __a;
-      __y = std::__constexpr_copysign(_Tp(INFINITY), __c) * __b;
-    } else if ((std::__constexpr_isinf(__a) || std::__constexpr_isinf(__b)) && std::__constexpr_isfinite(__c) &&
-               std::__constexpr_isfinite(__d)) {
-      __a = std::__constexpr_copysign(std::__constexpr_isinf(__a) ? _Tp(1) : _Tp(0), __a);
-      __b = std::__constexpr_copysign(std::__constexpr_isinf(__b) ? _Tp(1) : _Tp(0), __b);
-      __x = _Tp(INFINITY) * (__a * __c + __b * __d);
-      __y = _Tp(INFINITY) * (__b * __c - __a * __d);
-    } else if (std::__constexpr_isinf(__logbw) && __logbw > _Tp(0) && std::__constexpr_isfinite(__a) &&
-               std::__constexpr_isfinite(__b)) {
-      __c = std::__constexpr_copysign(std::__constexpr_isinf(__c) ? _Tp(1) : _Tp(0), __c);
-      __d = std::__constexpr_copysign(std::__constexpr_isinf(__d) ? _Tp(1) : _Tp(0), __d);
-      __x = _Tp(0) * (__a * __c + __b * __d);
-      __y = _Tp(0) * (__b * __c - __a * __d);
-    }
-  }
-  return complex<_Tp>(__x, __y);
+  return complex<_Tp>((__a * __c + __b * __d) / __denom, (__b * __c - __a * __d) / __denom);
 }
 
 template <class _Tp>
diff --git a/libcxx/test/std/numerics/complex.number/complex.member.ops/divide_equal_complex.pass.cpp b/libcxx/test/std/numerics/complex.number/complex.member.ops/divide_equal_complex.pass.cpp
index af2561e4cb9e9f..61e0d01f2ae4d7 100644
--- a/libcxx/test/std/numerics/complex.number/complex.member.ops/divide_equal_complex.pass.cpp
+++ b/libcxx/test/std/numerics/complex.number/complex.member.ops/divide_equal_complex.pass.cpp
@@ -10,9 +10,10 @@
 
 // complex& operator/=(const complex& rhs); // constexpr ...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/83575


More information about the libcxx-commits mailing list