|  | //===----------------------------------------------------------------------===// | 
|  | // | 
|  | // 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); | 
|  | } |