| //===----------------------------------------------------------------------===// |
| // |
| // 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 |
| // |
| //===----------------------------------------------------------------------===// |
| |
| // |
| // This file reimplements builtins that are normally provided by compiler-rt, which is |
| // not provided on Windows. This should go away once compiler-rt is shipped on Windows. |
| // |
| |
| #include <cmath> |
| #include <complex> |
| |
| template <class T> |
| static std::__complex_t<T> mul_impl(T a, T b, T c, T d) { |
| T __ac = a * c; |
| T __bd = b * d; |
| T __ad = a * d; |
| T __bc = b * c; |
| T __x = __ac - __bd; |
| T __y = __ad + __bc; |
| if (std::isnan(__x) && std::isnan(__y)) { |
| bool recalc = false; |
| if (std::isinf(a) || std::isinf(b)) { |
| a = std::copysign(std::isinf(a) ? T(1) : T(0), a); |
| b = std::copysign(std::isinf(b) ? T(1) : T(0), b); |
| if (std::isnan(c)) |
| c = std::copysign(T(0), c); |
| if (std::isnan(d)) |
| d = std::copysign(T(0), d); |
| recalc = true; |
| } |
| if (std::isinf(c) || std::isinf(d)) { |
| c = std::copysign(std::isinf(c) ? T(1) : T(0), c); |
| d = std::copysign(std::isinf(d) ? T(1) : T(0), d); |
| if (std::isnan(a)) |
| a = std::copysign(T(0), a); |
| if (std::isnan(b)) |
| b = std::copysign(T(0), b); |
| recalc = true; |
| } |
| if (!recalc && (std::isinf(__ac) || std::isinf(__bd) || std::isinf(__ad) || std::isinf(__bc))) { |
| if (std::isnan(a)) |
| a = std::copysign(T(0), a); |
| if (std::isnan(b)) |
| b = std::copysign(T(0), b); |
| if (std::isnan(c)) |
| c = std::copysign(T(0), c); |
| if (std::isnan(d)) |
| d = std::copysign(T(0), d); |
| recalc = true; |
| } |
| if (recalc) { |
| __x = T(INFINITY) * (a * c - b * d); |
| __y = T(INFINITY) * (a * d + b * c); |
| } |
| } |
| return {__x, __y}; |
| } |
| |
| extern "C" _LIBCPP_EXPORTED_FROM_ABI _Complex double __muldc3(double a, double b, double c, double d) { |
| return mul_impl(a, b, c, d); |
| } |
| |
| extern "C" _LIBCPP_EXPORTED_FROM_ABI _Complex float __mulsc3(float a, float b, float c, float d) { |
| return mul_impl(a, b, c, d); |
| } |
| |
| template <class T> |
| std::__complex_t<T> div_impl(T a, T b, T c, T d) { |
| int ilogbw = 0; |
| T __logbw = std::logb(std::fmax(std::fabs(c), std::fabs(d))); |
| if (std::isfinite(__logbw)) { |
| ilogbw = static_cast<int>(__logbw); |
| c = std::scalbn(c, -ilogbw); |
| d = std::scalbn(d, -ilogbw); |
| } |
| |
| T denom = c * c + d * d; |
| T x = std::scalbn((a * c + b * d) / denom, -ilogbw); |
| T y = std::scalbn((b * c - a * d) / denom, -ilogbw); |
| if (std::isnan(x) && std::isnan(y)) { |
| if ((denom == T(0)) && (!std::isnan(a) || !std::isnan(b))) { |
| x = std::copysign(T(INFINITY), c) * a; |
| y = std::copysign(T(INFINITY), c) * b; |
| } else if ((std::isinf(a) || std::isinf(b)) && std::isfinite(c) && std::isfinite(d)) { |
| a = std::copysign(std::isinf(a) ? T(1) : T(0), a); |
| b = std::copysign(std::isinf(b) ? T(1) : T(0), b); |
| x = T(INFINITY) * (a * c + b * d); |
| y = T(INFINITY) * (b * c - a * d); |
| } else if (std::isinf(__logbw) && __logbw > T(0) && std::isfinite(a) && std::isfinite(b)) { |
| c = std::copysign(std::isinf(c) ? T(1) : T(0), c); |
| d = std::copysign(std::isinf(d) ? T(1) : T(0), d); |
| x = T(0) * (a * c + b * d); |
| y = T(0) * (b * c - a * d); |
| } |
| } |
| return {x, y}; |
| } |
| |
| extern "C" _LIBCPP_EXPORTED_FROM_ABI _Complex double __divdc3(double a, double b, double c, double d) { |
| return div_impl(a, b, c, d); |
| } |
| |
| extern "C" _LIBCPP_EXPORTED_FROM_ABI _Complex float __divsc3(float a, float b, float c, float d) { |
| return div_impl(a, b, c, d); |
| } |