llvm-project
168 строк · 4.3 Кб
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/Common/float128.h"
10#include "flang/Runtime/entry-names.h"
11#include <cstdint>
12#include <cstdio>
13#include <limits>
14
15#ifdef __clang_major__
16#pragma clang diagnostic ignored "-Wc99-extensions"
17#endif
18
19template <typename C, typename I> C tgpowi(C base, I exp) {
20if (exp == 0) {
21return C{1};
22}
23
24bool invertResult{exp < 0};
25bool isMin{exp == std::numeric_limits<I>::min()};
26
27if (isMin) {
28exp = std::numeric_limits<I>::max();
29}
30
31if (exp < 0) {
32exp = exp * -1;
33}
34
35C origBase{base};
36
37while ((exp & 1) == 0) {
38base *= base;
39exp >>= 1;
40}
41
42C acc{base};
43
44while (exp > 1) {
45exp >>= 1;
46base *= base;
47if ((exp & 1) == 1) {
48acc *= base;
49}
50}
51
52if (isMin) {
53acc *= origBase;
54}
55
56if (invertResult) {
57acc = C{1} / acc;
58}
59
60return acc;
61}
62
63#ifndef _MSC_VER
64// With most compilers, C complex is implemented as a builtin type that may have
65// specific ABI requirements
66extern "C" float _Complex RTNAME(cpowi)(float _Complex base, std::int32_t exp) {
67return tgpowi(base, exp);
68}
69
70extern "C" double _Complex RTNAME(zpowi)(
71double _Complex base, std::int32_t exp) {
72return tgpowi(base, exp);
73}
74
75extern "C" float _Complex RTNAME(cpowk)(float _Complex base, std::int64_t exp) {
76return tgpowi(base, exp);
77}
78
79extern "C" double _Complex RTNAME(zpowk)(
80double _Complex base, std::int64_t exp) {
81return tgpowi(base, exp);
82}
83
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
90typedef long double _Complex Qcomplex;
91#elif HAS_FLOAT128
92#if !defined(_ARCH_PPC) || defined(__LONG_DOUBLE_IEEE128__)
93typedef _Complex float __attribute__((mode(TC))) Qcomplex;
94#else
95typedef _Complex float __attribute__((mode(KC))) Qcomplex;
96#endif
97#endif
98
99extern "C" Qcomplex RTNAME(cqpowi)(Qcomplex base, std::int32_t exp) {
100return tgpowi(base, exp);
101}
102extern "C" Qcomplex RTNAME(cqpowk)(Qcomplex base, std::int64_t exp) {
103return tgpowi(base, exp);
104}
105#endif
106
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>
113
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.
116struct Fcomplex {
117float re;
118float im;
119};
120
121struct Dcomplex {
122double re;
123double im;
124};
125
126extern "C" Fcomplex RTNAME(cpowi)(Fcomplex base, std::int32_t exp) {
127auto cppbase = *(std::complex<float> *)(&base);
128auto cppres = tgpowi(cppbase, exp);
129return *(Fcomplex *)(&cppres);
130}
131
132extern "C" Dcomplex RTNAME(zpowi)(Dcomplex base, std::int32_t exp) {
133auto cppbase = *(std::complex<double> *)(&base);
134auto cppres = tgpowi(cppbase, exp);
135return *(Dcomplex *)(&cppres);
136}
137
138extern "C" Fcomplex RTNAME(cpowk)(Fcomplex base, std::int64_t exp) {
139auto cppbase = *(std::complex<float> *)(&base);
140auto cppres = tgpowi(cppbase, exp);
141return *(Fcomplex *)(&cppres);
142}
143
144extern "C" Dcomplex RTNAME(zpowk)(Dcomplex base, std::int64_t exp) {
145auto cppbase = *(std::complex<double> *)(&base);
146auto cppres = tgpowi(cppbase, exp);
147return *(Dcomplex *)(&cppres);
148}
149
150#if LDBL_MANT_DIG == 113 || HAS_FLOAT128
151struct Qcomplex {
152CFloat128Type re;
153CFloat128Type im;
154};
155
156extern "C" Dcomplex RTNAME(cqpowi)(Qcomplex base, std::int32_t exp) {
157auto cppbase = *(std::complex<CFloat128Type> *)(&base);
158auto cppres = tgpowi(cppbase, exp);
159return *(Qcomplex *)(&cppres);
160}
161
162extern "C" Dcomplex RTNAME(cqpowk)(Qcomplex base, std::int64_t exp) {
163auto cppbase = *(std::complex<CFloat128Type> *)(&base);
164auto cppres = tgpowi(cppbase, exp);
165return *(Qcomplex *)(&cppres);
166}
167#endif
168#endif
169