[X86] AMD Zen 5 Initial enablement
[llvm-project.git] / flang / runtime / complex-powi.cpp
blob77031e40242791b9cdb26611d8c0e4413474e251
1 /*===-- flang/runtime/complex-powi.cpp ----------------------------*- C++ -*-===
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
7 * ===-----------------------------------------------------------------------===
8 */
9 #include "flang/Common/float128.h"
10 #include "flang/Runtime/entry-names.h"
11 #include <cstdint>
12 #include <cstdio>
13 #include <limits>
15 #ifdef __clang_major__
16 #pragma clang diagnostic ignored "-Wc99-extensions"
17 #endif
19 template <typename C, typename I> C tgpowi(C base, I exp) {
20 if (exp == 0) {
21 return C{1};
24 bool invertResult{exp < 0};
25 bool isMin{exp == std::numeric_limits<I>::min()};
27 if (isMin) {
28 exp = std::numeric_limits<I>::max();
31 if (exp < 0) {
32 exp = exp * -1;
35 C origBase{base};
37 while ((exp & 1) == 0) {
38 base *= base;
39 exp >>= 1;
42 C acc{base};
44 while (exp > 1) {
45 exp >>= 1;
46 base *= base;
47 if ((exp & 1) == 1) {
48 acc *= base;
52 if (isMin) {
53 acc *= origBase;
56 if (invertResult) {
57 acc = C{1} / acc;
60 return acc;
63 #ifndef _MSC_VER
64 // With most compilers, C complex is implemented as a builtin type that may have
65 // specific ABI requirements
66 extern "C" float _Complex RTNAME(cpowi)(float _Complex base, std::int32_t exp) {
67 return tgpowi(base, exp);
70 extern "C" double _Complex RTNAME(zpowi)(
71 double _Complex base, std::int32_t exp) {
72 return tgpowi(base, exp);
75 extern "C" float _Complex RTNAME(cpowk)(float _Complex base, std::int64_t exp) {
76 return tgpowi(base, exp);
79 extern "C" double _Complex RTNAME(zpowk)(
80 double _Complex base, std::int64_t exp) {
81 return tgpowi(base, exp);
84 #if LDBL_MANT_DIG == 113 || HAS_FLOAT128
85 // Duplicate CFloat128ComplexType definition from flang/Common/float128.h.
86 // float128.h does not define it for C++, because _Complex triggers
87 // c99-extension warnings. We decided to disable warnings for this
88 // particular file, so we can use _Complex here.
89 #if LDBL_MANT_DIG == 113
90 typedef long double _Complex Qcomplex;
91 #elif HAS_FLOAT128
92 #if !defined(_ARCH_PPC) || defined(__LONG_DOUBLE_IEEE128__)
93 typedef _Complex float __attribute__((mode(TC))) Qcomplex;
94 #else
95 typedef _Complex float __attribute__((mode(KC))) Qcomplex;
96 #endif
97 #endif
99 extern "C" Qcomplex RTNAME(cqpowi)(Qcomplex base, std::int32_t exp) {
100 return tgpowi(base, exp);
102 extern "C" Qcomplex RTNAME(cqpowk)(Qcomplex base, std::int64_t exp) {
103 return tgpowi(base, exp);
105 #endif
107 #else
108 // on MSVC, C complex is always just a struct of two members as it is not
109 // supported as a builtin type. So we use C++ complex here as that has the
110 // same ABI and layout. See:
111 // https://learn.microsoft.com/en-us/cpp/c-runtime-library/complex-math-support
112 #include <complex>
114 // MSVC doesn't allow including <ccomplex> or <complex.h> in C++17 mode to get
115 // the Windows definitions of these structs so just redefine here.
116 struct Fcomplex {
117 float re;
118 float im;
121 struct Dcomplex {
122 double re;
123 double im;
126 extern "C" Fcomplex RTNAME(cpowi)(Fcomplex base, std::int32_t exp) {
127 auto cppbase = *(std::complex<float> *)(&base);
128 auto cppres = tgpowi(cppbase, exp);
129 return *(Fcomplex *)(&cppres);
132 extern "C" Dcomplex RTNAME(zpowi)(Dcomplex base, std::int32_t exp) {
133 auto cppbase = *(std::complex<double> *)(&base);
134 auto cppres = tgpowi(cppbase, exp);
135 return *(Dcomplex *)(&cppres);
138 extern "C" Fcomplex RTNAME(cpowk)(Fcomplex base, std::int64_t exp) {
139 auto cppbase = *(std::complex<float> *)(&base);
140 auto cppres = tgpowi(cppbase, exp);
141 return *(Fcomplex *)(&cppres);
144 extern "C" Dcomplex RTNAME(zpowk)(Dcomplex base, std::int64_t exp) {
145 auto cppbase = *(std::complex<double> *)(&base);
146 auto cppres = tgpowi(cppbase, exp);
147 return *(Dcomplex *)(&cppres);
150 #if LDBL_MANT_DIG == 113 || HAS_FLOAT128
151 struct Qcomplex {
152 CFloat128Type re;
153 CFloat128Type im;
156 extern "C" Dcomplex RTNAME(cqpowi)(Qcomplex base, std::int32_t exp) {
157 auto cppbase = *(std::complex<CFloat128Type> *)(&base);
158 auto cppres = tgpowi(cppbase, exp);
159 return *(Qcomplex *)(&cppres);
162 extern "C" Dcomplex RTNAME(cqpowk)(Qcomplex base, std::int64_t exp) {
163 auto cppbase = *(std::complex<CFloat128Type> *)(&base);
164 auto cppres = tgpowi(cppbase, exp);
165 return *(Qcomplex *)(&cppres);
167 #endif
168 #endif