blob: 52049c511f13edffd355b5bce83d461945fa1417 [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
Yi Wue2b896a2024-01-10 10:02:4812#include "stat.h"
peter klauslere372e0f2021-03-31 16:14:0813#include "terminator.h"
Slava Zakharin71e02612024-03-15 21:25:4714#include "flang/Common/optional.h"
Peter Klausler830c0b92021-09-01 23:00:5315#include "flang/Runtime/cpp-type.h"
16#include "flang/Runtime/descriptor.h"
Slava Zakharin3b337242024-04-05 22:10:0417#include "flang/Runtime/freestanding-tools.h"
Peter Klausler830c0b92021-09-01 23:00:5318#include "flang/Runtime/memory.h"
Peter Klausler52a0b022023-04-12 19:32:3719#include <cstring>
peter klauslerf7be2512020-01-24 00:59:2720#include <functional>
21#include <map>
22#include <type_traits>
23
Slava Zakharin00f34542024-03-21 22:12:3124/// \macro RT_PRETTY_FUNCTION
25/// Gets a user-friendly looking function signature for the current scope
26/// using the best available method on each platform. The exact format of the
27/// resulting string is implementation specific and non-portable, so this should
28/// only be used, for example, for logging or diagnostics.
29/// Copy of LLVM_PRETTY_FUNCTION
30#if defined(_MSC_VER)
31#define RT_PRETTY_FUNCTION __FUNCSIG__
32#elif defined(__GNUC__) || defined(__clang__)
33#define RT_PRETTY_FUNCTION __PRETTY_FUNCTION__
34#else
35#define RT_PRETTY_FUNCTION __func__
36#endif
37
38#if defined(RT_DEVICE_COMPILATION)
39// Use the pseudo lock and pseudo file unit implementations
40// for the device.
41#define RT_USE_PSEUDO_LOCK 1
42#define RT_USE_PSEUDO_FILE_UNIT 1
43#endif
44
peter klauslerfae12a02020-01-24 00:10:0045namespace Fortran::runtime {
46
47class Terminator;
48
Slava Zakharin8b953fd2023-10-04 15:21:4649RT_API_ATTRS std::size_t TrimTrailingSpaces(const char *, std::size_t);
peter klausler675ad1b2020-08-03 18:35:2950
Slava Zakharin8b953fd2023-10-04 15:21:4651RT_API_ATTRS OwningPtr<char> SaveDefaultCharacter(
peter klausler95696d52020-02-05 00:55:4552 const char *, std::size_t, const Terminator &);
peter klauslerfae12a02020-01-24 00:10:0053
54// For validating and recognizing default CHARACTER values in a
55// case-insensitive manner. Returns the zero-based index into the
56// null-terminated array of upper-case possibilities when the value is valid,
57// or -1 when it has no match.
Slava Zakharin8b953fd2023-10-04 15:21:4658RT_API_ATTRS int IdentifyValue(
peter klauslerfae12a02020-01-24 00:10:0059 const char *value, std::size_t length, const char *possibilities[]);
peter klauslerf7be2512020-01-24 00:59:2760
peter klausler3b635712020-02-13 22:41:5661// Truncates or pads as necessary
Slava Zakharin8b953fd2023-10-04 15:21:4662RT_API_ATTRS void ToFortranDefaultCharacter(
peter klausler3b635712020-02-13 22:41:5663 char *to, std::size_t toLength, const char *from);
peter klauslere372e0f2021-03-31 16:14:0864
Peter Klausler3ada8832024-03-26 16:21:1665// Utilities for dealing with elemental LOGICAL arguments
Slava Zakharin32120512023-05-22 21:05:1866inline RT_API_ATTRS bool IsLogicalElementTrue(
peter klauslere372e0f2021-03-31 16:14:0867 const Descriptor &logical, const SubscriptValue at[]) {
68 // A LOGICAL value is false if and only if all of its bytes are zero.
69 const char *p{logical.Element<char>(at)};
70 for (std::size_t j{logical.ElementBytes()}; j-- > 0; ++p) {
71 if (*p) {
72 return true;
73 }
74 }
75 return false;
76}
Peter Klausler3ada8832024-03-26 16:21:1677inline RT_API_ATTRS bool IsLogicalScalarTrue(const Descriptor &logical) {
78 // A LOGICAL value is false if and only if all of its bytes are zero.
79 const char *p{logical.OffsetElement<char>()};
80 for (std::size_t j{logical.ElementBytes()}; j-- > 0; ++p) {
81 if (*p) {
82 return true;
83 }
84 }
85 return false;
86}
peter klauslere372e0f2021-03-31 16:14:0887
88// Check array conformability; a scalar 'x' conforms. Crashes on error.
Slava Zakharin32120512023-05-22 21:05:1889RT_API_ATTRS void CheckConformability(const Descriptor &to, const Descriptor &x,
peter klauslere372e0f2021-03-31 16:14:0890 Terminator &, const char *funcName, const char *toName,
91 const char *fromName);
92
Peter Steinfeld6cd417b2022-02-09 19:17:1893// Helper to store integer value in result[at].
94template <int KIND> struct StoreIntegerAt {
Slava Zakharin8b953fd2023-10-04 15:21:4695 RT_API_ATTRS void operator()(const Fortran::runtime::Descriptor &result,
96 std::size_t at, std::int64_t value) const {
Peter Steinfeld6cd417b2022-02-09 19:17:1897 *result.ZeroBasedIndexedElement<Fortran::runtime::CppTypeFor<
98 Fortran::common::TypeCategory::Integer, KIND>>(at) = value;
99 }
100};
101
peter klauslere372e0f2021-03-31 16:14:08102// Validate a KIND= argument
Slava Zakharin32120512023-05-22 21:05:18103RT_API_ATTRS void CheckIntegerKind(
104 Terminator &, int kind, const char *intrinsic);
peter klauslere372e0f2021-03-31 16:14:08105
106template <typename TO, typename FROM>
Slava Zakharin8b953fd2023-10-04 15:21:46107inline RT_API_ATTRS void PutContiguousConverted(
108 TO *to, FROM *from, std::size_t count) {
peter klauslere372e0f2021-03-31 16:14:08109 while (count-- > 0) {
110 *to++ = *from++;
111 }
112}
113
Slava Zakharin32120512023-05-22 21:05:18114static inline RT_API_ATTRS std::int64_t GetInt64(
peter klauslerc1db35f2021-05-20 17:37:03115 const char *p, std::size_t bytes, Terminator &terminator) {
peter klauslere372e0f2021-03-31 16:14:08116 switch (bytes) {
117 case 1:
118 return *reinterpret_cast<const CppTypeFor<TypeCategory::Integer, 1> *>(p);
119 case 2:
120 return *reinterpret_cast<const CppTypeFor<TypeCategory::Integer, 2> *>(p);
121 case 4:
122 return *reinterpret_cast<const CppTypeFor<TypeCategory::Integer, 4> *>(p);
123 case 8:
124 return *reinterpret_cast<const CppTypeFor<TypeCategory::Integer, 8> *>(p);
125 default:
peter klauslerc1db35f2021-05-20 17:37:03126 terminator.Crash("GetInt64: no case for %zd bytes", bytes);
peter klauslere372e0f2021-03-31 16:14:08127 }
128}
129
Slava Zakharin71e02612024-03-15 21:25:47130static inline RT_API_ATTRS Fortran::common::optional<std::int64_t> GetInt64Safe(
Peter Klausler8fc045e2023-12-26 23:12:39131 const char *p, std::size_t bytes, Terminator &terminator) {
132 switch (bytes) {
133 case 1:
134 return *reinterpret_cast<const CppTypeFor<TypeCategory::Integer, 1> *>(p);
135 case 2:
136 return *reinterpret_cast<const CppTypeFor<TypeCategory::Integer, 2> *>(p);
137 case 4:
138 return *reinterpret_cast<const CppTypeFor<TypeCategory::Integer, 4> *>(p);
139 case 8:
140 return *reinterpret_cast<const CppTypeFor<TypeCategory::Integer, 8> *>(p);
141 case 16: {
142 using Int128 = CppTypeFor<TypeCategory::Integer, 16>;
143 auto n{*reinterpret_cast<const Int128 *>(p)};
Slava Zakharin76facde2023-12-28 21:50:43144 std::int64_t result{static_cast<std::int64_t>(n)};
145 if (static_cast<Int128>(result) == n) {
Peter Klausler8fc045e2023-12-26 23:12:39146 return result;
147 }
Slava Zakharin71e02612024-03-15 21:25:47148 return Fortran::common::nullopt;
Peter Klausler8fc045e2023-12-26 23:12:39149 }
150 default:
151 terminator.Crash("GetInt64Safe: no case for %zd bytes", bytes);
152 }
153}
154
peter klauslere372e0f2021-03-31 16:14:08155template <typename INT>
Slava Zakharin8b953fd2023-10-04 15:21:46156inline RT_API_ATTRS bool SetInteger(INT &x, int kind, std::int64_t value) {
peter klauslere372e0f2021-03-31 16:14:08157 switch (kind) {
158 case 1:
159 reinterpret_cast<CppTypeFor<TypeCategory::Integer, 1> &>(x) = value;
Peter Klausler73b193a2022-02-16 21:26:44160 return value == reinterpret_cast<CppTypeFor<TypeCategory::Integer, 1> &>(x);
peter klauslere372e0f2021-03-31 16:14:08161 case 2:
162 reinterpret_cast<CppTypeFor<TypeCategory::Integer, 2> &>(x) = value;
Peter Klausler73b193a2022-02-16 21:26:44163 return value == reinterpret_cast<CppTypeFor<TypeCategory::Integer, 2> &>(x);
peter klauslere372e0f2021-03-31 16:14:08164 case 4:
165 reinterpret_cast<CppTypeFor<TypeCategory::Integer, 4> &>(x) = value;
Peter Klausler73b193a2022-02-16 21:26:44166 return value == reinterpret_cast<CppTypeFor<TypeCategory::Integer, 4> &>(x);
peter klauslere372e0f2021-03-31 16:14:08167 case 8:
168 reinterpret_cast<CppTypeFor<TypeCategory::Integer, 8> &>(x) = value;
Peter Klausler73b193a2022-02-16 21:26:44169 return value == reinterpret_cast<CppTypeFor<TypeCategory::Integer, 8> &>(x);
peter klauslere372e0f2021-03-31 16:14:08170 default:
171 return false;
172 }
173}
174
peter klausler50e0b292021-05-12 19:07:51175// Maps intrinsic runtime type category and kind values to the appropriate
176// instantiation of a function object template and calls it with the supplied
177// arguments.
178template <template <TypeCategory, int> class FUNC, typename RESULT,
179 typename... A>
Slava Zakharin32120512023-05-22 21:05:18180inline RT_API_ATTRS RESULT ApplyType(
peter klausler50e0b292021-05-12 19:07:51181 TypeCategory cat, int kind, Terminator &terminator, A &&...x) {
182 switch (cat) {
183 case TypeCategory::Integer:
184 switch (kind) {
185 case 1:
186 return FUNC<TypeCategory::Integer, 1>{}(std::forward<A>(x)...);
187 case 2:
188 return FUNC<TypeCategory::Integer, 2>{}(std::forward<A>(x)...);
189 case 4:
190 return FUNC<TypeCategory::Integer, 4>{}(std::forward<A>(x)...);
191 case 8:
192 return FUNC<TypeCategory::Integer, 8>{}(std::forward<A>(x)...);
Peter Klausler1c35c1a2023-07-06 22:03:05193#if defined __SIZEOF_INT128__ && !AVOID_NATIVE_UINT128_T
peter klausler50e0b292021-05-12 19:07:51194 case 16:
195 return FUNC<TypeCategory::Integer, 16>{}(std::forward<A>(x)...);
196#endif
197 default:
Peter Steinfeldebe24a22022-05-05 21:54:57198 terminator.Crash("not yet implemented: INTEGER(KIND=%d)", kind);
peter klausler50e0b292021-05-12 19:07:51199 }
200 case TypeCategory::Real:
201 switch (kind) {
202#if 0 // TODO: REAL(2 & 3)
203 case 2:
204 return FUNC<TypeCategory::Real, 2>{}(std::forward<A>(x)...);
205 case 3:
206 return FUNC<TypeCategory::Real, 3>{}(std::forward<A>(x)...);
207#endif
208 case 4:
209 return FUNC<TypeCategory::Real, 4>{}(std::forward<A>(x)...);
210 case 8:
211 return FUNC<TypeCategory::Real, 8>{}(std::forward<A>(x)...);
peter klausler50e0b292021-05-12 19:07:51212 case 10:
Peter Klausler4daa33f2022-05-31 21:06:11213 if constexpr (HasCppTypeFor<TypeCategory::Real, 10>) {
214 return FUNC<TypeCategory::Real, 10>{}(std::forward<A>(x)...);
215 }
216 break;
peter klausler50e0b292021-05-12 19:07:51217 case 16:
Peter Klausler4daa33f2022-05-31 21:06:11218 if constexpr (HasCppTypeFor<TypeCategory::Real, 16>) {
219 return FUNC<TypeCategory::Real, 16>{}(std::forward<A>(x)...);
220 }
221 break;
peter klausler50e0b292021-05-12 19:07:51222 }
Peter Klausler4daa33f2022-05-31 21:06:11223 terminator.Crash("not yet implemented: REAL(KIND=%d)", kind);
peter klausler50e0b292021-05-12 19:07:51224 case TypeCategory::Complex:
225 switch (kind) {
226#if 0 // TODO: COMPLEX(2 & 3)
227 case 2:
228 return FUNC<TypeCategory::Complex, 2>{}(std::forward<A>(x)...);
229 case 3:
230 return FUNC<TypeCategory::Complex, 3>{}(std::forward<A>(x)...);
231#endif
232 case 4:
233 return FUNC<TypeCategory::Complex, 4>{}(std::forward<A>(x)...);
234 case 8:
235 return FUNC<TypeCategory::Complex, 8>{}(std::forward<A>(x)...);
peter klausler50e0b292021-05-12 19:07:51236 case 10:
Peter Klausler4daa33f2022-05-31 21:06:11237 if constexpr (HasCppTypeFor<TypeCategory::Real, 10>) {
238 return FUNC<TypeCategory::Complex, 10>{}(std::forward<A>(x)...);
239 }
240 break;
peter klausler50e0b292021-05-12 19:07:51241 case 16:
Peter Klausler4daa33f2022-05-31 21:06:11242 if constexpr (HasCppTypeFor<TypeCategory::Real, 16>) {
243 return FUNC<TypeCategory::Complex, 16>{}(std::forward<A>(x)...);
244 }
245 break;
peter klausler50e0b292021-05-12 19:07:51246 }
Peter Klausler4daa33f2022-05-31 21:06:11247 terminator.Crash("not yet implemented: COMPLEX(KIND=%d)", kind);
peter klausler50e0b292021-05-12 19:07:51248 case TypeCategory::Character:
249 switch (kind) {
250 case 1:
251 return FUNC<TypeCategory::Character, 1>{}(std::forward<A>(x)...);
252 case 2:
253 return FUNC<TypeCategory::Character, 2>{}(std::forward<A>(x)...);
254 case 4:
255 return FUNC<TypeCategory::Character, 4>{}(std::forward<A>(x)...);
256 default:
Peter Steinfeldebe24a22022-05-05 21:54:57257 terminator.Crash("not yet implemented: CHARACTER(KIND=%d)", kind);
peter klausler50e0b292021-05-12 19:07:51258 }
259 case TypeCategory::Logical:
260 switch (kind) {
261 case 1:
262 return FUNC<TypeCategory::Logical, 1>{}(std::forward<A>(x)...);
263 case 2:
264 return FUNC<TypeCategory::Logical, 2>{}(std::forward<A>(x)...);
265 case 4:
266 return FUNC<TypeCategory::Logical, 4>{}(std::forward<A>(x)...);
267 case 8:
268 return FUNC<TypeCategory::Logical, 8>{}(std::forward<A>(x)...);
269 default:
Peter Steinfeldebe24a22022-05-05 21:54:57270 terminator.Crash("not yet implemented: LOGICAL(KIND=%d)", kind);
peter klausler50e0b292021-05-12 19:07:51271 }
272 default:
Peter Steinfeldebe24a22022-05-05 21:54:57273 terminator.Crash(
274 "not yet implemented: type category(%d)", static_cast<int>(cat));
peter klausler50e0b292021-05-12 19:07:51275 }
276}
277
peter klausler8d672c0b2021-04-20 16:19:21278// Maps a runtime INTEGER kind value to the appropriate instantiation of
279// a function object template and calls it with the supplied arguments.
280template <template <int KIND> class FUNC, typename RESULT, typename... A>
Slava Zakharin32120512023-05-22 21:05:18281inline RT_API_ATTRS RESULT ApplyIntegerKind(
282 int kind, Terminator &terminator, A &&...x) {
peter klausler8d672c0b2021-04-20 16:19:21283 switch (kind) {
284 case 1:
285 return FUNC<1>{}(std::forward<A>(x)...);
286 case 2:
287 return FUNC<2>{}(std::forward<A>(x)...);
288 case 4:
289 return FUNC<4>{}(std::forward<A>(x)...);
290 case 8:
291 return FUNC<8>{}(std::forward<A>(x)...);
Peter Klausler1c35c1a2023-07-06 22:03:05292#if defined __SIZEOF_INT128__ && !AVOID_NATIVE_UINT128_T
peter klausler8d672c0b2021-04-20 16:19:21293 case 16:
294 return FUNC<16>{}(std::forward<A>(x)...);
295#endif
296 default:
Peter Steinfeldebe24a22022-05-05 21:54:57297 terminator.Crash("not yet implemented: INTEGER(KIND=%d)", kind);
peter klausler8d672c0b2021-04-20 16:19:21298 }
299}
300
Slava Zakharinbaf67252024-02-28 18:39:14301template <template <int KIND> class FUNC, typename RESULT,
302 bool NEEDSMATH = false, typename... A>
Slava Zakharin32120512023-05-22 21:05:18303inline RT_API_ATTRS RESULT ApplyFloatingPointKind(
peter klausler8d672c0b2021-04-20 16:19:21304 int kind, Terminator &terminator, A &&...x) {
305 switch (kind) {
306#if 0 // TODO: REAL/COMPLEX (2 & 3)
307 case 2:
308 return FUNC<2>{}(std::forward<A>(x)...);
309 case 3:
310 return FUNC<3>{}(std::forward<A>(x)...);
311#endif
312 case 4:
313 return FUNC<4>{}(std::forward<A>(x)...);
314 case 8:
315 return FUNC<8>{}(std::forward<A>(x)...);
peter klausler8d672c0b2021-04-20 16:19:21316 case 10:
Peter Klausler4daa33f2022-05-31 21:06:11317 if constexpr (HasCppTypeFor<TypeCategory::Real, 10>) {
318 return FUNC<10>{}(std::forward<A>(x)...);
319 }
320 break;
peter klausler8d672c0b2021-04-20 16:19:21321 case 16:
Peter Klausler4daa33f2022-05-31 21:06:11322 if constexpr (HasCppTypeFor<TypeCategory::Real, 16>) {
Slava Zakharinbaf67252024-02-28 18:39:14323 // If FUNC implemenation relies on FP math functions,
324 // then we should not be here. The compiler should have
325 // generated a call to an entry in FortranFloat128Math
326 // library.
327 if constexpr (!NEEDSMATH) {
328 return FUNC<16>{}(std::forward<A>(x)...);
329 }
Peter Klausler4daa33f2022-05-31 21:06:11330 }
331 break;
peter klausler8d672c0b2021-04-20 16:19:21332 }
Peter Klausler4daa33f2022-05-31 21:06:11333 terminator.Crash("not yet implemented: REAL/COMPLEX(KIND=%d)", kind);
peter klausler8d672c0b2021-04-20 16:19:21334}
335
336template <template <int KIND> class FUNC, typename RESULT, typename... A>
Slava Zakharin32120512023-05-22 21:05:18337inline RT_API_ATTRS RESULT ApplyCharacterKind(
338 int kind, Terminator &terminator, A &&...x) {
peter klausler8d672c0b2021-04-20 16:19:21339 switch (kind) {
340 case 1:
341 return FUNC<1>{}(std::forward<A>(x)...);
342 case 2:
343 return FUNC<2>{}(std::forward<A>(x)...);
344 case 4:
345 return FUNC<4>{}(std::forward<A>(x)...);
346 default:
Peter Steinfeldebe24a22022-05-05 21:54:57347 terminator.Crash("not yet implemented: CHARACTER(KIND=%d)", kind);
peter klausler8d672c0b2021-04-20 16:19:21348 }
349}
350
351template <template <int KIND> class FUNC, typename RESULT, typename... A>
Slava Zakharin32120512023-05-22 21:05:18352inline RT_API_ATTRS RESULT ApplyLogicalKind(
353 int kind, Terminator &terminator, A &&...x) {
peter klausler8d672c0b2021-04-20 16:19:21354 switch (kind) {
355 case 1:
356 return FUNC<1>{}(std::forward<A>(x)...);
357 case 2:
358 return FUNC<2>{}(std::forward<A>(x)...);
359 case 4:
360 return FUNC<4>{}(std::forward<A>(x)...);
361 case 8:
362 return FUNC<8>{}(std::forward<A>(x)...);
363 default:
Peter Steinfeldebe24a22022-05-05 21:54:57364 terminator.Crash("not yet implemented: LOGICAL(KIND=%d)", kind);
peter klausler8d672c0b2021-04-20 16:19:21365 }
366}
367
peter klausler50e0b292021-05-12 19:07:51368// Calculate result type of (X op Y) for *, //, DOT_PRODUCT, &c.
Slava Zakharin71e02612024-03-15 21:25:47369Fortran::common::optional<
370 std::pair<TypeCategory, int>> inline constexpr RT_API_ATTRS
Slava Zakharin8b953fd2023-10-04 15:21:46371GetResultType(TypeCategory xCat, int xKind, TypeCategory yCat, int yKind) {
peter klausler50e0b292021-05-12 19:07:51372 int maxKind{std::max(xKind, yKind)};
373 switch (xCat) {
374 case TypeCategory::Integer:
375 switch (yCat) {
376 case TypeCategory::Integer:
377 return std::make_pair(TypeCategory::Integer, maxKind);
378 case TypeCategory::Real:
379 case TypeCategory::Complex:
Peter Klausler1c35c1a2023-07-06 22:03:05380#if !(defined __SIZEOF_INT128__ && !AVOID_NATIVE_UINT128_T)
381 if (xKind == 16) {
382 break;
383 }
384#endif
peter klausler50e0b292021-05-12 19:07:51385 return std::make_pair(yCat, yKind);
386 default:
387 break;
388 }
389 break;
390 case TypeCategory::Real:
391 switch (yCat) {
392 case TypeCategory::Integer:
Peter Klausler1c35c1a2023-07-06 22:03:05393#if !(defined __SIZEOF_INT128__ && !AVOID_NATIVE_UINT128_T)
394 if (yKind == 16) {
395 break;
396 }
397#endif
peter klausler50e0b292021-05-12 19:07:51398 return std::make_pair(TypeCategory::Real, xKind);
399 case TypeCategory::Real:
400 case TypeCategory::Complex:
401 return std::make_pair(yCat, maxKind);
402 default:
403 break;
404 }
405 break;
406 case TypeCategory::Complex:
407 switch (yCat) {
408 case TypeCategory::Integer:
Peter Klausler1c35c1a2023-07-06 22:03:05409#if !(defined __SIZEOF_INT128__ && !AVOID_NATIVE_UINT128_T)
410 if (yKind == 16) {
411 break;
412 }
413#endif
peter klausler50e0b292021-05-12 19:07:51414 return std::make_pair(TypeCategory::Complex, xKind);
415 case TypeCategory::Real:
416 case TypeCategory::Complex:
417 return std::make_pair(TypeCategory::Complex, maxKind);
418 default:
419 break;
420 }
421 break;
422 case TypeCategory::Character:
423 if (yCat == TypeCategory::Character) {
424 return std::make_pair(TypeCategory::Character, maxKind);
425 } else {
Slava Zakharin71e02612024-03-15 21:25:47426 return Fortran::common::nullopt;
peter klausler50e0b292021-05-12 19:07:51427 }
428 case TypeCategory::Logical:
429 if (yCat == TypeCategory::Logical) {
430 return std::make_pair(TypeCategory::Logical, maxKind);
431 } else {
Slava Zakharin71e02612024-03-15 21:25:47432 return Fortran::common::nullopt;
peter klausler50e0b292021-05-12 19:07:51433 }
434 default:
435 break;
436 }
Slava Zakharin71e02612024-03-15 21:25:47437 return Fortran::common::nullopt;
peter klausler50e0b292021-05-12 19:07:51438}
peter klausler79caf692021-06-17 20:13:19439
Peter Klauslera5a493e2021-10-19 18:30:45440// Accumulate floating-point results in (at least) double precision
441template <TypeCategory CAT, int KIND>
442using AccumulationType = CppTypeFor<CAT,
443 CAT == TypeCategory::Real || CAT == TypeCategory::Complex
444 ? std::max(KIND, static_cast<int>(sizeof(double)))
445 : KIND>;
446
Peter Klausler52a0b022023-04-12 19:32:37447// memchr() for any character type
448template <typename CHAR>
Slava Zakharin8b953fd2023-10-04 15:21:46449static inline RT_API_ATTRS const CHAR *FindCharacter(
Peter Klausler52a0b022023-04-12 19:32:37450 const CHAR *data, CHAR ch, std::size_t chars) {
451 const CHAR *end{data + chars};
452 for (const CHAR *p{data}; p < end; ++p) {
453 if (*p == ch) {
454 return p;
455 }
456 }
457 return nullptr;
458}
459
460template <>
Slava Zakharin8b953fd2023-10-04 15:21:46461inline RT_API_ATTRS const char *FindCharacter(
462 const char *data, char ch, std::size_t chars) {
Peter Klausler52a0b022023-04-12 19:32:37463 return reinterpret_cast<const char *>(
Slava Zakharinf4e90e32024-03-18 23:29:58464 runtime::memchr(data, static_cast<int>(ch), chars));
Peter Klausler52a0b022023-04-12 19:32:37465}
466
Peter Klauslerb21c24c2023-07-29 15:34:14467// Copy payload data from one allocated descriptor to another.
468// Assumes element counts and element sizes match, and that both
469// descriptors are allocated.
Slava Zakharin8b953fd2023-10-04 15:21:46470RT_API_ATTRS void ShallowCopyDiscontiguousToDiscontiguous(
Peter Klauslerb21c24c2023-07-29 15:34:14471 const Descriptor &to, const Descriptor &from);
Slava Zakharin8b953fd2023-10-04 15:21:46472RT_API_ATTRS void ShallowCopyDiscontiguousToContiguous(
Peter Klauslerb21c24c2023-07-29 15:34:14473 const Descriptor &to, const Descriptor &from);
Slava Zakharin8b953fd2023-10-04 15:21:46474RT_API_ATTRS void ShallowCopyContiguousToDiscontiguous(
Peter Klauslerb21c24c2023-07-29 15:34:14475 const Descriptor &to, const Descriptor &from);
Slava Zakharin8b953fd2023-10-04 15:21:46476RT_API_ATTRS void ShallowCopy(const Descriptor &to, const Descriptor &from,
Peter Klauslerb21c24c2023-07-29 15:34:14477 bool toIsContiguous, bool fromIsContiguous);
Slava Zakharin8b953fd2023-10-04 15:21:46478RT_API_ATTRS void ShallowCopy(const Descriptor &to, const Descriptor &from);
Peter Klauslerb21c24c2023-07-29 15:34:14479
Yi Wue2b896a2024-01-10 10:02:48480// Ensures that a character string is null-terminated, allocating a /p length +1
481// size memory for null-terminator if necessary. Returns the original or a newly
482// allocated null-terminated string (responsibility for deallocation is on the
483// caller).
Yi Wu7dd4d282024-01-13 01:22:40484RT_API_ATTRS char *EnsureNullTerminated(
485 char *str, std::size_t length, Terminator &terminator);
Yi Wue2b896a2024-01-10 10:02:48486
487RT_API_ATTRS bool IsValidCharDescriptor(const Descriptor *value);
488
489RT_API_ATTRS bool IsValidIntDescriptor(const Descriptor *intVal);
490
491// Copy a null-terminated character array \p rawValue to descriptor \p value.
492// The copy starts at the given \p offset, if not present then start at 0.
493// If descriptor `errmsg` is provided, error messages will be stored to it.
494// Returns stats specified in standard.
495RT_API_ATTRS std::int32_t CopyCharsToDescriptor(const Descriptor &value,
496 const char *rawValue, std::size_t rawValueLength,
497 const Descriptor *errmsg = nullptr, std::size_t offset = 0);
498
499RT_API_ATTRS void StoreIntToDescriptor(
500 const Descriptor *length, std::int64_t value, Terminator &terminator);
501
Yi Wu18af0322023-12-21 10:35:28502// Defines a utility function for copying and padding characters
503template <typename TO, typename FROM>
504RT_API_ATTRS void CopyAndPad(
505 TO *to, const FROM *from, std::size_t toChars, std::size_t fromChars) {
506 if constexpr (sizeof(TO) != sizeof(FROM)) {
507 std::size_t copyChars{std::min(toChars, fromChars)};
508 for (std::size_t j{0}; j < copyChars; ++j) {
509 to[j] = from[j];
510 }
511 for (std::size_t j{copyChars}; j < toChars; ++j) {
512 to[j] = static_cast<TO>(' ');
513 }
514 } else if (toChars <= fromChars) {
515 std::memcpy(to, from, toChars * sizeof(TO));
516 } else {
517 std::memcpy(to, from, std::min(toChars, fromChars) * sizeof(TO));
518 for (std::size_t j{fromChars}; j < toChars; ++j) {
519 to[j] = static_cast<TO>(' ');
520 }
521 }
522}
523
Peter Klausler3ada8832024-03-26 16:21:16524RT_API_ATTRS void CreatePartialReductionResult(Descriptor &result,
525 const Descriptor &x, std::size_t resultElementSize, int dim, Terminator &,
526 const char *intrinsic, TypeCode);
527
Tim Keith1f879002020-03-29 04:00:16528} // namespace Fortran::runtime
529#endif // FORTRAN_RUNTIME_TOOLS_H_