blob: d4a070868abc5a5ab05d2a8eac5b66f939318429 [file] [log] [blame]
peter klauslerfae12a02020-01-24 00:10:001//===-- runtime/tools.h -----------------------------------------*- 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#ifndef FORTRAN_RUNTIME_TOOLS_H_
10#define FORTRAN_RUNTIME_TOOLS_H_
peter klauslerf7be2512020-01-24 00:59:2711
peter klauslere372e0f2021-03-31 16:14:0812#include "cpp-type.h"
13#include "descriptor.h"
peter klauslerfae12a02020-01-24 00:10:0014#include "memory.h"
peter klauslere372e0f2021-03-31 16:14:0815#include "terminator.h"
peter klausler8d672c0b2021-04-20 16:19:2116#include "flang/Common/long-double.h"
peter klauslerf7be2512020-01-24 00:59:2717#include <functional>
18#include <map>
19#include <type_traits>
20
peter klauslerfae12a02020-01-24 00:10:0021namespace Fortran::runtime {
22
23class Terminator;
24
peter klausler675ad1b2020-08-03 18:35:2925std::size_t TrimTrailingSpaces(const char *, std::size_t);
26
peter klausler95696d52020-02-05 00:55:4527OwningPtr<char> SaveDefaultCharacter(
28 const char *, std::size_t, const Terminator &);
peter klauslerfae12a02020-01-24 00:10:0029
30// For validating and recognizing default CHARACTER values in a
31// case-insensitive manner. Returns the zero-based index into the
32// null-terminated array of upper-case possibilities when the value is valid,
33// or -1 when it has no match.
34int IdentifyValue(
35 const char *value, std::size_t length, const char *possibilities[]);
peter klauslerf7be2512020-01-24 00:59:2736
peter klausler3b635712020-02-13 22:41:5637// Truncates or pads as necessary
38void ToFortranDefaultCharacter(
39 char *to, std::size_t toLength, const char *from);
peter klauslere372e0f2021-03-31 16:14:0840
41// Utility for dealing with elemental LOGICAL arguments
42inline bool IsLogicalElementTrue(
43 const Descriptor &logical, const SubscriptValue at[]) {
44 // A LOGICAL value is false if and only if all of its bytes are zero.
45 const char *p{logical.Element<char>(at)};
46 for (std::size_t j{logical.ElementBytes()}; j-- > 0; ++p) {
47 if (*p) {
48 return true;
49 }
50 }
51 return false;
52}
53
54// Check array conformability; a scalar 'x' conforms. Crashes on error.
55void CheckConformability(const Descriptor &to, const Descriptor &x,
56 Terminator &, const char *funcName, const char *toName,
57 const char *fromName);
58
59// Validate a KIND= argument
60void CheckIntegerKind(Terminator &, int kind, const char *intrinsic);
61
62template <typename TO, typename FROM>
63inline void PutContiguousConverted(TO *to, FROM *from, std::size_t count) {
64 while (count-- > 0) {
65 *to++ = *from++;
66 }
67}
68
peter klauslerc1db35f2021-05-20 17:37:0369static inline std::int64_t GetInt64(
70 const char *p, std::size_t bytes, Terminator &terminator) {
peter klauslere372e0f2021-03-31 16:14:0871 switch (bytes) {
72 case 1:
73 return *reinterpret_cast<const CppTypeFor<TypeCategory::Integer, 1> *>(p);
74 case 2:
75 return *reinterpret_cast<const CppTypeFor<TypeCategory::Integer, 2> *>(p);
76 case 4:
77 return *reinterpret_cast<const CppTypeFor<TypeCategory::Integer, 4> *>(p);
78 case 8:
79 return *reinterpret_cast<const CppTypeFor<TypeCategory::Integer, 8> *>(p);
80 default:
peter klauslerc1db35f2021-05-20 17:37:0381 terminator.Crash("GetInt64: no case for %zd bytes", bytes);
peter klauslere372e0f2021-03-31 16:14:0882 }
83}
84
85template <typename INT>
86inline bool SetInteger(INT &x, int kind, std::int64_t value) {
87 switch (kind) {
88 case 1:
89 reinterpret_cast<CppTypeFor<TypeCategory::Integer, 1> &>(x) = value;
90 return true;
91 case 2:
92 reinterpret_cast<CppTypeFor<TypeCategory::Integer, 2> &>(x) = value;
93 return true;
94 case 4:
95 reinterpret_cast<CppTypeFor<TypeCategory::Integer, 4> &>(x) = value;
96 return true;
97 case 8:
98 reinterpret_cast<CppTypeFor<TypeCategory::Integer, 8> &>(x) = value;
99 return true;
100 default:
101 return false;
102 }
103}
104
peter klausler50e0b292021-05-12 19:07:51105// Maps intrinsic runtime type category and kind values to the appropriate
106// instantiation of a function object template and calls it with the supplied
107// arguments.
108template <template <TypeCategory, int> class FUNC, typename RESULT,
109 typename... A>
110inline RESULT ApplyType(
111 TypeCategory cat, int kind, Terminator &terminator, A &&...x) {
112 switch (cat) {
113 case TypeCategory::Integer:
114 switch (kind) {
115 case 1:
116 return FUNC<TypeCategory::Integer, 1>{}(std::forward<A>(x)...);
117 case 2:
118 return FUNC<TypeCategory::Integer, 2>{}(std::forward<A>(x)...);
119 case 4:
120 return FUNC<TypeCategory::Integer, 4>{}(std::forward<A>(x)...);
121 case 8:
122 return FUNC<TypeCategory::Integer, 8>{}(std::forward<A>(x)...);
123#ifdef __SIZEOF_INT128__
124 case 16:
125 return FUNC<TypeCategory::Integer, 16>{}(std::forward<A>(x)...);
126#endif
127 default:
128 terminator.Crash("unsupported INTEGER(KIND=%d)", kind);
129 }
130 case TypeCategory::Real:
131 switch (kind) {
132#if 0 // TODO: REAL(2 & 3)
133 case 2:
134 return FUNC<TypeCategory::Real, 2>{}(std::forward<A>(x)...);
135 case 3:
136 return FUNC<TypeCategory::Real, 3>{}(std::forward<A>(x)...);
137#endif
138 case 4:
139 return FUNC<TypeCategory::Real, 4>{}(std::forward<A>(x)...);
140 case 8:
141 return FUNC<TypeCategory::Real, 8>{}(std::forward<A>(x)...);
142#if LONG_DOUBLE == 80
143 case 10:
144 return FUNC<TypeCategory::Real, 10>{}(std::forward<A>(x)...);
145#elif LONG_DOUBLE == 128
146 case 16:
147 return FUNC<TypeCategory::Real, 16>{}(std::forward<A>(x)...);
148#endif
149 default:
150 terminator.Crash("unsupported REAL(KIND=%d)", kind);
151 }
152 case TypeCategory::Complex:
153 switch (kind) {
154#if 0 // TODO: COMPLEX(2 & 3)
155 case 2:
156 return FUNC<TypeCategory::Complex, 2>{}(std::forward<A>(x)...);
157 case 3:
158 return FUNC<TypeCategory::Complex, 3>{}(std::forward<A>(x)...);
159#endif
160 case 4:
161 return FUNC<TypeCategory::Complex, 4>{}(std::forward<A>(x)...);
162 case 8:
163 return FUNC<TypeCategory::Complex, 8>{}(std::forward<A>(x)...);
164#if LONG_DOUBLE == 80
165 case 10:
166 return FUNC<TypeCategory::Complex, 10>{}(std::forward<A>(x)...);
167#elif LONG_DOUBLE == 128
168 case 16:
169 return FUNC<TypeCategory::Complex, 16>{}(std::forward<A>(x)...);
170#endif
171 default:
172 terminator.Crash("unsupported COMPLEX(KIND=%d)", kind);
173 }
174 case TypeCategory::Character:
175 switch (kind) {
176 case 1:
177 return FUNC<TypeCategory::Character, 1>{}(std::forward<A>(x)...);
178 case 2:
179 return FUNC<TypeCategory::Character, 2>{}(std::forward<A>(x)...);
180 case 4:
181 return FUNC<TypeCategory::Character, 4>{}(std::forward<A>(x)...);
182 default:
183 terminator.Crash("unsupported CHARACTER(KIND=%d)", kind);
184 }
185 case TypeCategory::Logical:
186 switch (kind) {
187 case 1:
188 return FUNC<TypeCategory::Logical, 1>{}(std::forward<A>(x)...);
189 case 2:
190 return FUNC<TypeCategory::Logical, 2>{}(std::forward<A>(x)...);
191 case 4:
192 return FUNC<TypeCategory::Logical, 4>{}(std::forward<A>(x)...);
193 case 8:
194 return FUNC<TypeCategory::Logical, 8>{}(std::forward<A>(x)...);
195 default:
196 terminator.Crash("unsupported LOGICAL(KIND=%d)", kind);
197 }
198 default:
199 terminator.Crash("unsupported type category(%d)", static_cast<int>(cat));
200 }
201}
202
peter klausler8d672c0b2021-04-20 16:19:21203// Maps a runtime INTEGER kind value to the appropriate instantiation of
204// a function object template and calls it with the supplied arguments.
205template <template <int KIND> class FUNC, typename RESULT, typename... A>
206inline RESULT ApplyIntegerKind(int kind, Terminator &terminator, A &&...x) {
207 switch (kind) {
208 case 1:
209 return FUNC<1>{}(std::forward<A>(x)...);
210 case 2:
211 return FUNC<2>{}(std::forward<A>(x)...);
212 case 4:
213 return FUNC<4>{}(std::forward<A>(x)...);
214 case 8:
215 return FUNC<8>{}(std::forward<A>(x)...);
216#ifdef __SIZEOF_INT128__
217 case 16:
218 return FUNC<16>{}(std::forward<A>(x)...);
219#endif
220 default:
221 terminator.Crash("unsupported INTEGER(KIND=%d)", kind);
222 }
223}
224
225template <template <int KIND> class FUNC, typename RESULT, typename... A>
226inline RESULT ApplyFloatingPointKind(
227 int kind, Terminator &terminator, A &&...x) {
228 switch (kind) {
229#if 0 // TODO: REAL/COMPLEX (2 & 3)
230 case 2:
231 return FUNC<2>{}(std::forward<A>(x)...);
232 case 3:
233 return FUNC<3>{}(std::forward<A>(x)...);
234#endif
235 case 4:
236 return FUNC<4>{}(std::forward<A>(x)...);
237 case 8:
238 return FUNC<8>{}(std::forward<A>(x)...);
239#if LONG_DOUBLE == 80
240 case 10:
241 return FUNC<10>{}(std::forward<A>(x)...);
242#elif LONG_DOUBLE == 128
243 case 16:
244 return FUNC<16>{}(std::forward<A>(x)...);
245#endif
246 default:
247 terminator.Crash("unsupported REAL/COMPLEX(KIND=%d)", kind);
248 }
249}
250
251template <template <int KIND> class FUNC, typename RESULT, typename... A>
252inline RESULT ApplyCharacterKind(int kind, Terminator &terminator, A &&...x) {
253 switch (kind) {
254 case 1:
255 return FUNC<1>{}(std::forward<A>(x)...);
256 case 2:
257 return FUNC<2>{}(std::forward<A>(x)...);
258 case 4:
259 return FUNC<4>{}(std::forward<A>(x)...);
260 default:
261 terminator.Crash("unsupported CHARACTER(KIND=%d)", kind);
262 }
263}
264
265template <template <int KIND> class FUNC, typename RESULT, typename... A>
266inline RESULT ApplyLogicalKind(int kind, Terminator &terminator, A &&...x) {
267 switch (kind) {
268 case 1:
269 return FUNC<1>{}(std::forward<A>(x)...);
270 case 2:
271 return FUNC<2>{}(std::forward<A>(x)...);
272 case 4:
273 return FUNC<4>{}(std::forward<A>(x)...);
274 case 8:
275 return FUNC<8>{}(std::forward<A>(x)...);
276 default:
277 terminator.Crash("unsupported LOGICAL(KIND=%d)", kind);
278 }
279}
280
peter klausler50e0b292021-05-12 19:07:51281// Calculate result type of (X op Y) for *, //, DOT_PRODUCT, &c.
282std::optional<std::pair<TypeCategory, int>> inline constexpr GetResultType(
283 TypeCategory xCat, int xKind, TypeCategory yCat, int yKind) {
284 int maxKind{std::max(xKind, yKind)};
285 switch (xCat) {
286 case TypeCategory::Integer:
287 switch (yCat) {
288 case TypeCategory::Integer:
289 return std::make_pair(TypeCategory::Integer, maxKind);
290 case TypeCategory::Real:
291 case TypeCategory::Complex:
292 return std::make_pair(yCat, yKind);
293 default:
294 break;
295 }
296 break;
297 case TypeCategory::Real:
298 switch (yCat) {
299 case TypeCategory::Integer:
300 return std::make_pair(TypeCategory::Real, xKind);
301 case TypeCategory::Real:
302 case TypeCategory::Complex:
303 return std::make_pair(yCat, maxKind);
304 default:
305 break;
306 }
307 break;
308 case TypeCategory::Complex:
309 switch (yCat) {
310 case TypeCategory::Integer:
311 return std::make_pair(TypeCategory::Complex, xKind);
312 case TypeCategory::Real:
313 case TypeCategory::Complex:
314 return std::make_pair(TypeCategory::Complex, maxKind);
315 default:
316 break;
317 }
318 break;
319 case TypeCategory::Character:
320 if (yCat == TypeCategory::Character) {
321 return std::make_pair(TypeCategory::Character, maxKind);
322 } else {
323 return std::nullopt;
324 }
325 case TypeCategory::Logical:
326 if (yCat == TypeCategory::Logical) {
327 return std::make_pair(TypeCategory::Logical, maxKind);
328 } else {
329 return std::nullopt;
330 }
331 default:
332 break;
333 }
334 return std::nullopt;
335}
Tim Keith1f879002020-03-29 04:00:16336} // namespace Fortran::runtime
337#endif // FORTRAN_RUNTIME_TOOLS_H_