xref: /llvm-project/libcxx/src/support/win32/compiler_rt_shims.cpp (revision 5aacf93a8968b1ae83382ed0ce6de8279b0cd753)
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>
mul_impl(T a,T b,T c,T d)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 
__muldc3(double a,double b,double c,double d)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 
__mulsc3(float a,float b,float c,float d)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>
div_impl(T a,T b,T c,T d)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 
__divdc3(double a,double b,double c,double d)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 
__divsc3(float a,float b,float c,float d)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