| //===----------------------------------------------------------------------===// | |
| // | |
| // 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> | |
| _LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wmissing-prototypes") // See comment above | |
| 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); | |
| } |