| 1 | //===----------------------------------------------------------------------===// |
| 2 | // |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 4 | // See https://llvm.org/LICENSE.txt for license information. |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | |
| 9 | // |
| 10 | // This file reimplements builtins that are normally provided by compiler-rt, which is |
| 11 | // not provided on Windows. This should go away once compiler-rt is shipped on Windows. |
| 12 | // |
| 13 | |
| 14 | #include <cmath> |
| 15 | #include <complex> |
| 16 | |
| 17 | template <class T> |
| 18 | static std::__complex_t<T> mul_impl(T a, T b, T c, T d) { |
| 19 | T __ac = a * c; |
| 20 | T __bd = b * d; |
| 21 | T __ad = a * d; |
| 22 | T __bc = b * c; |
| 23 | T __x = __ac - __bd; |
| 24 | T __y = __ad + __bc; |
| 25 | if (std::isnan(__x) && std::isnan(__y)) { |
| 26 | bool recalc = false; |
| 27 | if (std::isinf(a) || std::isinf(b)) { |
| 28 | a = std::copysign(std::isinf(a) ? T(1) : T(0), a); |
| 29 | b = std::copysign(std::isinf(b) ? T(1) : T(0), b); |
| 30 | if (std::isnan(c)) |
| 31 | c = std::copysign(T(0), c); |
| 32 | if (std::isnan(d)) |
| 33 | d = std::copysign(T(0), d); |
| 34 | recalc = true; |
| 35 | } |
| 36 | if (std::isinf(c) || std::isinf(d)) { |
| 37 | c = std::copysign(std::isinf(c) ? T(1) : T(0), c); |
| 38 | d = std::copysign(std::isinf(d) ? T(1) : T(0), d); |
| 39 | if (std::isnan(a)) |
| 40 | a = std::copysign(T(0), a); |
| 41 | if (std::isnan(b)) |
| 42 | b = std::copysign(T(0), b); |
| 43 | recalc = true; |
| 44 | } |
| 45 | if (!recalc && (std::isinf(__ac) || std::isinf(__bd) || std::isinf(__ad) || std::isinf(__bc))) { |
| 46 | if (std::isnan(a)) |
| 47 | a = std::copysign(T(0), a); |
| 48 | if (std::isnan(b)) |
| 49 | b = std::copysign(T(0), b); |
| 50 | if (std::isnan(c)) |
| 51 | c = std::copysign(T(0), c); |
| 52 | if (std::isnan(d)) |
| 53 | d = std::copysign(T(0), d); |
| 54 | recalc = true; |
| 55 | } |
| 56 | if (recalc) { |
| 57 | __x = T(INFINITY) * (a * c - b * d); |
| 58 | __y = T(INFINITY) * (a * d + b * c); |
| 59 | } |
| 60 | } |
| 61 | return {__x, __y}; |
| 62 | } |
| 63 | |
| 64 | extern "C" _LIBCPP_EXPORTED_FROM_ABI _Complex double __muldc3(double a, double b, double c, double d) { |
| 65 | return mul_impl(a, b, c, d); |
| 66 | } |
| 67 | |
| 68 | extern "C" _LIBCPP_EXPORTED_FROM_ABI _Complex float __mulsc3(float a, float b, float c, float d) { |
| 69 | return mul_impl(a, b, c, d); |
| 70 | } |
| 71 | |
| 72 | template <class T> |
| 73 | std::__complex_t<T> div_impl(T a, T b, T c, T d) { |
| 74 | int ilogbw = 0; |
| 75 | T __logbw = std::logb(std::fmax(std::fabs(c), std::fabs(d))); |
| 76 | if (std::isfinite(__logbw)) { |
| 77 | ilogbw = static_cast<int>(__logbw); |
| 78 | c = std::scalbn(c, -ilogbw); |
| 79 | d = std::scalbn(d, -ilogbw); |
| 80 | } |
| 81 | |
| 82 | T denom = c * c + d * d; |
| 83 | T x = std::scalbn((a * c + b * d) / denom, -ilogbw); |
| 84 | T y = std::scalbn((b * c - a * d) / denom, -ilogbw); |
| 85 | if (std::isnan(x) && std::isnan(y)) { |
| 86 | if ((denom == T(0)) && (!std::isnan(a) || !std::isnan(b))) { |
| 87 | x = std::copysign(T(INFINITY), c) * a; |
| 88 | y = std::copysign(T(INFINITY), c) * b; |
| 89 | } else if ((std::isinf(a) || std::isinf(b)) && std::isfinite(c) && std::isfinite(d)) { |
| 90 | a = std::copysign(std::isinf(a) ? T(1) : T(0), a); |
| 91 | b = std::copysign(std::isinf(b) ? T(1) : T(0), b); |
| 92 | x = T(INFINITY) * (a * c + b * d); |
| 93 | y = T(INFINITY) * (b * c - a * d); |
| 94 | } else if (std::isinf(__logbw) && __logbw > T(0) && std::isfinite(a) && std::isfinite(b)) { |
| 95 | c = std::copysign(std::isinf(c) ? T(1) : T(0), c); |
| 96 | d = std::copysign(std::isinf(d) ? T(1) : T(0), d); |
| 97 | x = T(0) * (a * c + b * d); |
| 98 | y = T(0) * (b * c - a * d); |
| 99 | } |
| 100 | } |
| 101 | return {x, y}; |
| 102 | } |
| 103 | |
| 104 | extern "C" _LIBCPP_EXPORTED_FROM_ABI _Complex double __divdc3(double a, double b, double c, double d) { |
| 105 | return div_impl(a, b, c, d); |
| 106 | } |
| 107 | |
| 108 | extern "C" _LIBCPP_EXPORTED_FROM_ABI _Complex float __divsc3(float a, float b, float c, float d) { |
| 109 | return div_impl(a, b, c, d); |
| 110 | } |
| 111 | |