[flang] Add cpowi function to runtime and use instead of pgmath
[platform/upstream/llvm.git] / flang / runtime / complex-powi.cpp
1 /*===-- flang/runtime/complex-powi.cpp ----------------------------*- C++ -*-===
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 #include "flang/Runtime/entry-names.h"
10 #include <cstdint>
11 #include <cstdio>
12 #include <limits>
13
14 #ifdef __clang_major__
15 #pragma clang diagnostic ignored "-Wc99-extensions"
16 #endif
17
18 template <typename C, typename I> C tgpowi(C base, I exp) {
19   if (exp == 0) {
20     return C{1};
21   }
22
23   bool invertResult{exp < 0};
24   bool isMin{exp == std::numeric_limits<I>::min()};
25
26   if (isMin) {
27     exp = std::numeric_limits<I>::max();
28   }
29
30   if (exp < 0) {
31     exp = exp * -1;
32   }
33
34   C origBase{base};
35
36   while ((exp & 1) == 0) {
37     base *= base;
38     exp >>= 1;
39   }
40
41   C acc{base};
42
43   while (exp > 1) {
44     exp >>= 1;
45     base *= base;
46     if ((exp & 1) == 1) {
47       acc *= base;
48     }
49   }
50
51   if (isMin) {
52     acc *= origBase;
53   }
54
55   if (invertResult) {
56     acc = C{1} / acc;
57   }
58
59   return acc;
60 }
61
62 #ifndef _MSC_VER
63 // With most compilers, C complex is implemented as a builtin type that may have
64 // specific ABI requirements
65 extern "C" float _Complex RTNAME(cpowi)(float _Complex base, std::int32_t exp) {
66   return tgpowi(base, exp);
67 }
68
69 extern "C" double _Complex RTNAME(zpowi)(
70     double _Complex base, std::int32_t exp) {
71   return tgpowi(base, exp);
72 }
73
74 extern "C" float _Complex RTNAME(cpowk)(float _Complex base, std::int64_t exp) {
75   return tgpowi(base, exp);
76 }
77
78 extern "C" double _Complex RTNAME(zpowk)(
79     double _Complex base, std::int64_t exp) {
80   return tgpowi(base, exp);
81 }
82 #else
83 // on MSVC, C complex is always just a struct of two members as it is not
84 // supported as a builtin type. So we use C++ complex here as that has the
85 // same ABI and layout. See:
86 // https://learn.microsoft.com/en-us/cpp/c-runtime-library/complex-math-support
87 #include <complex>
88
89 // MSVC doesn't allow including <ccomplex> or <complex.h> in C++17 mode to get
90 // the Windows definitions of these structs so just redefine here.
91 struct Fcomplex {
92   float re;
93   float im;
94 };
95
96 struct Dcomplex {
97   double re;
98   double im;
99 };
100
101 extern "C" Fcomplex RTNAME(cpowi)(Fcomplex base, std::int32_t exp) {
102   auto cppbase = *(std::complex<float> *)(&base);
103   auto cppres = tgpowi(cppbase, exp);
104   return *(Fcomplex *)(&cppres);
105 }
106
107 extern "C" Dcomplex RTNAME(zpowi)(Dcomplex base, std::int32_t exp) {
108   auto cppbase = *(std::complex<double> *)(&base);
109   auto cppres = tgpowi(cppbase, exp);
110   return *(Dcomplex *)(&cppres);
111 }
112
113 extern "C" Fcomplex RTNAME(cpowk)(Fcomplex base, std::int64_t exp) {
114   auto cppbase = *(std::complex<float> *)(&base);
115   auto cppres = tgpowi(cppbase, exp);
116   return *(Fcomplex *)(&cppres);
117 }
118
119 extern "C" Dcomplex RTNAME(zpowk)(Dcomplex base, std::int32_t exp) {
120   auto cppbase = *(std::complex<double> *)(&base);
121   auto cppres = tgpowi(cppbase, exp);
122   return *(Dcomplex *)(&cppres);
123 }
124
125 #endif