File: complex-powi.cpp

package info (click to toggle)
swiftlang 6.0.3-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,519,992 kB
  • sloc: cpp: 9,107,863; ansic: 2,040,022; asm: 1,135,751; python: 296,500; objc: 82,456; f90: 60,502; lisp: 34,951; pascal: 19,946; sh: 18,133; perl: 7,482; ml: 4,937; javascript: 4,117; makefile: 3,840; awk: 3,535; xml: 914; fortran: 619; cs: 573; ruby: 573
file content (125 lines) | stat: -rw-r--r-- 3,048 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
/*===-- flang/runtime/complex-powi.cpp ----------------------------*- C++ -*-===
 *
 * Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 * See https://llvm.org/LICENSE.txt for license information.
 * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 *
 * ===-----------------------------------------------------------------------===
 */
#include "flang/Runtime/entry-names.h"
#include <cstdint>
#include <cstdio>
#include <limits>

#ifdef __clang_major__
#pragma clang diagnostic ignored "-Wc99-extensions"
#endif

template <typename C, typename I> C tgpowi(C base, I exp) {
  if (exp == 0) {
    return C{1};
  }

  bool invertResult{exp < 0};
  bool isMin{exp == std::numeric_limits<I>::min()};

  if (isMin) {
    exp = std::numeric_limits<I>::max();
  }

  if (exp < 0) {
    exp = exp * -1;
  }

  C origBase{base};

  while ((exp & 1) == 0) {
    base *= base;
    exp >>= 1;
  }

  C acc{base};

  while (exp > 1) {
    exp >>= 1;
    base *= base;
    if ((exp & 1) == 1) {
      acc *= base;
    }
  }

  if (isMin) {
    acc *= origBase;
  }

  if (invertResult) {
    acc = C{1} / acc;
  }

  return acc;
}

#ifndef _MSC_VER
// With most compilers, C complex is implemented as a builtin type that may have
// specific ABI requirements
extern "C" float _Complex RTNAME(cpowi)(float _Complex base, std::int32_t exp) {
  return tgpowi(base, exp);
}

extern "C" double _Complex RTNAME(zpowi)(
    double _Complex base, std::int32_t exp) {
  return tgpowi(base, exp);
}

extern "C" float _Complex RTNAME(cpowk)(float _Complex base, std::int64_t exp) {
  return tgpowi(base, exp);
}

extern "C" double _Complex RTNAME(zpowk)(
    double _Complex base, std::int64_t exp) {
  return tgpowi(base, exp);
}
#else
// on MSVC, C complex is always just a struct of two members as it is not
// supported as a builtin type. So we use C++ complex here as that has the
// same ABI and layout. See:
// https://learn.microsoft.com/en-us/cpp/c-runtime-library/complex-math-support
#include <complex>

// MSVC doesn't allow including <ccomplex> or <complex.h> in C++17 mode to get
// the Windows definitions of these structs so just redefine here.
struct Fcomplex {
  float re;
  float im;
};

struct Dcomplex {
  double re;
  double im;
};

extern "C" Fcomplex RTNAME(cpowi)(Fcomplex base, std::int32_t exp) {
  auto cppbase = *(std::complex<float> *)(&base);
  auto cppres = tgpowi(cppbase, exp);
  return *(Fcomplex *)(&cppres);
}

extern "C" Dcomplex RTNAME(zpowi)(Dcomplex base, std::int32_t exp) {
  auto cppbase = *(std::complex<double> *)(&base);
  auto cppres = tgpowi(cppbase, exp);
  return *(Dcomplex *)(&cppres);
}

extern "C" Fcomplex RTNAME(cpowk)(Fcomplex base, std::int64_t exp) {
  auto cppbase = *(std::complex<float> *)(&base);
  auto cppres = tgpowi(cppbase, exp);
  return *(Fcomplex *)(&cppres);
}

extern "C" Dcomplex RTNAME(zpowk)(Dcomplex base, std::int32_t exp) {
  auto cppbase = *(std::complex<double> *)(&base);
  auto cppres = tgpowi(cppbase, exp);
  return *(Dcomplex *)(&cppres);
}

#endif