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
18template <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
65extern "C" float _Complex RTNAME(cpowi)(float _Complex base, std::int32_t exp) {
66 return tgpowi(base, exp);
67}
68
69extern "C" double _Complex RTNAME(zpowi)(
70 double _Complex base, std::int32_t exp) {
71 return tgpowi(base, exp);
72}
73
74extern "C" float _Complex RTNAME(cpowk)(float _Complex base, std::int64_t exp) {
75 return tgpowi(base, exp);
76}
77
78extern "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.
91struct Fcomplex {
92 float re;
93 float im;
94};
95
96struct Dcomplex {
97 double re;
98 double im;
99};
100
101extern "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
107extern "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
113extern "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
119extern "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
126

source code of flang/runtime/complex-powi.cpp