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 | |