9#ifndef FORTRAN_RUNTIME_TOOLS_H_
10#define FORTRAN_RUNTIME_TOOLS_H_
13#include "terminator.h"
14#include "flang/Common/optional.h"
15#include "flang/Runtime/cpp-type.h"
16#include "flang/Runtime/descriptor.h"
17#include "flang/Runtime/freestanding-tools.h"
18#include "flang/Runtime/memory.h"
31#define RT_PRETTY_FUNCTION __FUNCSIG__
32#elif defined(__GNUC__) || defined(__clang__)
33#define RT_PRETTY_FUNCTION __PRETTY_FUNCTION__
35#define RT_PRETTY_FUNCTION __func__
38#if defined(RT_DEVICE_COMPILATION)
41#define RT_USE_PSEUDO_LOCK 1
42#define RT_USE_PSEUDO_FILE_UNIT 1
45namespace Fortran::runtime {
49RT_API_ATTRS std::size_t TrimTrailingSpaces(
const char *, std::size_t);
51RT_API_ATTRS OwningPtr<char> SaveDefaultCharacter(
52 const char *, std::size_t,
const Terminator &);
58RT_API_ATTRS
int IdentifyValue(
59 const char *value, std::size_t length,
const char *possibilities[]);
62RT_API_ATTRS
void ToFortranDefaultCharacter(
63 char *to, std::size_t toLength,
const char *from);
66inline RT_API_ATTRS
bool IsLogicalElementTrue(
67 const Descriptor &logical,
const SubscriptValue at[]) {
69 const char *p{logical.Element<
char>(at)};
70 for (std::size_t j{logical.ElementBytes()}; j-- > 0; ++p) {
77inline RT_API_ATTRS
bool IsLogicalScalarTrue(
const Descriptor &logical) {
79 const char *p{logical.OffsetElement<
char>()};
80 for (std::size_t j{logical.ElementBytes()}; j-- > 0; ++p) {
89RT_API_ATTRS
void CheckConformability(
const Descriptor &to,
const Descriptor &x,
90 Terminator &,
const char *funcName,
const char *toName,
91 const char *fromName);
96 std::size_t at, std::int64_t value)
const {
97 *result.ZeroBasedIndexedElement<Fortran::runtime::CppTypeFor<
98 Fortran::common::TypeCategory::Integer, KIND>>(at) = value;
105 std::size_t at, std::double_t value)
const {
106 *result.ZeroBasedIndexedElement<Fortran::runtime::CppTypeFor<
107 Fortran::common::TypeCategory::Real, KIND>>(at) = value;
112RT_API_ATTRS
void CheckIntegerKind(
113 Terminator &,
int kind,
const char *intrinsic);
115template <
typename TO,
typename FROM>
116inline RT_API_ATTRS
void PutContiguousConverted(
117 TO *to, FROM *from, std::size_t count) {
118 while (count-- > 0) {
123static inline RT_API_ATTRS std::int64_t GetInt64(
124 const char *p, std::size_t bytes, Terminator &terminator) {
127 return *
reinterpret_cast<const CppTypeFor<TypeCategory::Integer, 1> *
>(p);
129 return *
reinterpret_cast<const CppTypeFor<TypeCategory::Integer, 2> *
>(p);
131 return *
reinterpret_cast<const CppTypeFor<TypeCategory::Integer, 4> *
>(p);
133 return *
reinterpret_cast<const CppTypeFor<TypeCategory::Integer, 8> *
>(p);
135 terminator.Crash(
"GetInt64: no case for %zd bytes", bytes);
139static inline RT_API_ATTRS Fortran::common::optional<std::int64_t> GetInt64Safe(
140 const char *p, std::size_t bytes, Terminator &terminator) {
143 return *
reinterpret_cast<const CppTypeFor<TypeCategory::Integer, 1> *
>(p);
145 return *
reinterpret_cast<const CppTypeFor<TypeCategory::Integer, 2> *
>(p);
147 return *
reinterpret_cast<const CppTypeFor<TypeCategory::Integer, 4> *
>(p);
149 return *
reinterpret_cast<const CppTypeFor<TypeCategory::Integer, 8> *
>(p);
151 using Int128 = CppTypeFor<TypeCategory::Integer, 16>;
152 auto n{*
reinterpret_cast<const Int128 *
>(p)};
153 std::int64_t result{
static_cast<std::int64_t
>(n)};
154 if (
static_cast<Int128
>(result) == n) {
157 return Fortran::common::nullopt;
160 terminator.Crash(
"GetInt64Safe: no case for %zd bytes", bytes);
164template <
typename INT>
165inline RT_API_ATTRS
bool SetInteger(INT &x,
int kind, std::int64_t value) {
168 reinterpret_cast<CppTypeFor<TypeCategory::Integer, 1> &
>(x) = value;
169 return value ==
reinterpret_cast<CppTypeFor<TypeCategory::Integer, 1> &
>(x);
171 reinterpret_cast<CppTypeFor<TypeCategory::Integer, 2> &
>(x) = value;
172 return value ==
reinterpret_cast<CppTypeFor<TypeCategory::Integer, 2> &
>(x);
174 reinterpret_cast<CppTypeFor<TypeCategory::Integer, 4> &
>(x) = value;
175 return value ==
reinterpret_cast<CppTypeFor<TypeCategory::Integer, 4> &
>(x);
177 reinterpret_cast<CppTypeFor<TypeCategory::Integer, 8> &
>(x) = value;
178 return value ==
reinterpret_cast<CppTypeFor<TypeCategory::Integer, 8> &
>(x);
187template <
template <TypeCategory,
int>
class FUNC,
typename RESULT,
189inline RT_API_ATTRS RESULT ApplyType(
190 TypeCategory cat,
int kind, Terminator &terminator, A &&...x) {
192 case TypeCategory::Integer:
195 return FUNC<TypeCategory::Integer, 1>{}(std::forward<A>(x)...);
197 return FUNC<TypeCategory::Integer, 2>{}(std::forward<A>(x)...);
199 return FUNC<TypeCategory::Integer, 4>{}(std::forward<A>(x)...);
201 return FUNC<TypeCategory::Integer, 8>{}(std::forward<A>(x)...);
202#if defined __SIZEOF_INT128__ && !AVOID_NATIVE_UINT128_T
204 return FUNC<TypeCategory::Integer, 16>{}(std::forward<A>(x)...);
207 terminator.Crash(
"not yet implemented: INTEGER(KIND=%d)", kind);
209 case TypeCategory::Unsigned:
212 return FUNC<TypeCategory::Unsigned, 1>{}(std::forward<A>(x)...);
214 return FUNC<TypeCategory::Unsigned, 2>{}(std::forward<A>(x)...);
216 return FUNC<TypeCategory::Unsigned, 4>{}(std::forward<A>(x)...);
218 return FUNC<TypeCategory::Unsigned, 8>{}(std::forward<A>(x)...);
219#if defined __SIZEOF_INT128__ && !AVOID_NATIVE_UINT128_T
221 return FUNC<TypeCategory::Unsigned, 16>{}(std::forward<A>(x)...);
224 terminator.Crash(
"not yet implemented: UNSIGNED(KIND=%d)", kind);
226 case TypeCategory::Real:
230 return FUNC<TypeCategory::Real, 2>{}(std::forward<A>(x)...);
232 return FUNC<TypeCategory::Real, 3>{}(std::forward<A>(x)...);
235 return FUNC<TypeCategory::Real, 4>{}(std::forward<A>(x)...);
237 return FUNC<TypeCategory::Real, 8>{}(std::forward<A>(x)...);
239 if constexpr (HasCppTypeFor<TypeCategory::Real, 10>) {
240 return FUNC<TypeCategory::Real, 10>{}(std::forward<A>(x)...);
244 if constexpr (HasCppTypeFor<TypeCategory::Real, 16>) {
245 return FUNC<TypeCategory::Real, 16>{}(std::forward<A>(x)...);
249 terminator.Crash(
"not yet implemented: REAL(KIND=%d)", kind);
250 case TypeCategory::Complex:
254 return FUNC<TypeCategory::Complex, 2>{}(std::forward<A>(x)...);
256 return FUNC<TypeCategory::Complex, 3>{}(std::forward<A>(x)...);
259 return FUNC<TypeCategory::Complex, 4>{}(std::forward<A>(x)...);
261 return FUNC<TypeCategory::Complex, 8>{}(std::forward<A>(x)...);
263 if constexpr (HasCppTypeFor<TypeCategory::Real, 10>) {
264 return FUNC<TypeCategory::Complex, 10>{}(std::forward<A>(x)...);
268 if constexpr (HasCppTypeFor<TypeCategory::Real, 16>) {
269 return FUNC<TypeCategory::Complex, 16>{}(std::forward<A>(x)...);
273 terminator.Crash(
"not yet implemented: COMPLEX(KIND=%d)", kind);
274 case TypeCategory::Character:
277 return FUNC<TypeCategory::Character, 1>{}(std::forward<A>(x)...);
279 return FUNC<TypeCategory::Character, 2>{}(std::forward<A>(x)...);
281 return FUNC<TypeCategory::Character, 4>{}(std::forward<A>(x)...);
283 terminator.Crash(
"not yet implemented: CHARACTER(KIND=%d)", kind);
285 case TypeCategory::Logical:
288 return FUNC<TypeCategory::Logical, 1>{}(std::forward<A>(x)...);
290 return FUNC<TypeCategory::Logical, 2>{}(std::forward<A>(x)...);
292 return FUNC<TypeCategory::Logical, 4>{}(std::forward<A>(x)...);
294 return FUNC<TypeCategory::Logical, 8>{}(std::forward<A>(x)...);
296 terminator.Crash(
"not yet implemented: LOGICAL(KIND=%d)", kind);
300 "not yet implemented: type category(%d)",
static_cast<int>(cat));
306template <
template <
int KIND>
class FUNC,
typename RESULT,
typename... A>
307inline RT_API_ATTRS RESULT ApplyIntegerKind(
308 int kind, Terminator &terminator, A &&...x) {
311 return FUNC<1>{}(std::forward<A>(x)...);
313 return FUNC<2>{}(std::forward<A>(x)...);
315 return FUNC<4>{}(std::forward<A>(x)...);
317 return FUNC<8>{}(std::forward<A>(x)...);
318#if defined __SIZEOF_INT128__ && !AVOID_NATIVE_UINT128_T
320 return FUNC<16>{}(std::forward<A>(x)...);
323 terminator.Crash(
"not yet implemented: INTEGER/UNSIGNED(KIND=%d)", kind);
327template <
template <
int KIND>
class FUNC,
typename RESULT,
328 bool NEEDSMATH =
false,
typename... A>
329inline RT_API_ATTRS RESULT ApplyFloatingPointKind(
330 int kind, Terminator &terminator, A &&...x) {
334 return FUNC<2>{}(std::forward<A>(x)...);
336 return FUNC<3>{}(std::forward<A>(x)...);
339 return FUNC<4>{}(std::forward<A>(x)...);
341 return FUNC<8>{}(std::forward<A>(x)...);
343 if constexpr (HasCppTypeFor<TypeCategory::Real, 10>) {
344 return FUNC<10>{}(std::forward<A>(x)...);
348 if constexpr (HasCppTypeFor<TypeCategory::Real, 16>) {
353 if constexpr (!NEEDSMATH) {
354 return FUNC<16>{}(std::forward<A>(x)...);
359 terminator.Crash(
"not yet implemented: REAL/COMPLEX(KIND=%d)", kind);
362template <
template <
int KIND>
class FUNC,
typename RESULT,
typename... A>
363inline RT_API_ATTRS RESULT ApplyCharacterKind(
364 int kind, Terminator &terminator, A &&...x) {
367 return FUNC<1>{}(std::forward<A>(x)...);
369 return FUNC<2>{}(std::forward<A>(x)...);
371 return FUNC<4>{}(std::forward<A>(x)...);
373 terminator.Crash(
"not yet implemented: CHARACTER(KIND=%d)", kind);
377template <
template <
int KIND>
class FUNC,
typename RESULT,
typename... A>
378inline RT_API_ATTRS RESULT ApplyLogicalKind(
379 int kind, Terminator &terminator, A &&...x) {
382 return FUNC<1>{}(std::forward<A>(x)...);
384 return FUNC<2>{}(std::forward<A>(x)...);
386 return FUNC<4>{}(std::forward<A>(x)...);
388 return FUNC<8>{}(std::forward<A>(x)...);
390 terminator.Crash(
"not yet implemented: LOGICAL(KIND=%d)", kind);
395Fortran::common::optional<
396 std::pair<TypeCategory, int>>
inline constexpr RT_API_ATTRS
397GetResultType(TypeCategory xCat,
int xKind, TypeCategory yCat,
int yKind) {
398 int maxKind{std::max(xKind, yKind)};
400 case TypeCategory::Integer:
402 case TypeCategory::Integer:
403 return std::make_pair(TypeCategory::Integer, maxKind);
404 case TypeCategory::Real:
405 case TypeCategory::Complex:
406#if !(defined __SIZEOF_INT128__ && !AVOID_NATIVE_UINT128_T)
411 return std::make_pair(yCat, yKind);
416 case TypeCategory::Unsigned:
418 case TypeCategory::Unsigned:
419 return std::make_pair(TypeCategory::Unsigned, maxKind);
420 case TypeCategory::Real:
421 case TypeCategory::Complex:
422#if !(defined __SIZEOF_INT128__ && !AVOID_NATIVE_UINT128_T)
427 return std::make_pair(yCat, yKind);
432 case TypeCategory::Real:
434 case TypeCategory::Integer:
435 case TypeCategory::Unsigned:
436#if !(defined __SIZEOF_INT128__ && !AVOID_NATIVE_UINT128_T)
441 return std::make_pair(TypeCategory::Real, xKind);
442 case TypeCategory::Real:
443 case TypeCategory::Complex:
444 return std::make_pair(yCat, maxKind);
449 case TypeCategory::Complex:
451 case TypeCategory::Integer:
452 case TypeCategory::Unsigned:
453#if !(defined __SIZEOF_INT128__ && !AVOID_NATIVE_UINT128_T)
458 return std::make_pair(TypeCategory::Complex, xKind);
459 case TypeCategory::Real:
460 case TypeCategory::Complex:
461 return std::make_pair(TypeCategory::Complex, maxKind);
466 case TypeCategory::Character:
467 if (yCat == TypeCategory::Character) {
468 return std::make_pair(TypeCategory::Character, maxKind);
470 return Fortran::common::nullopt;
472 case TypeCategory::Logical:
473 if (yCat == TypeCategory::Logical) {
474 return std::make_pair(TypeCategory::Logical, maxKind);
476 return Fortran::common::nullopt;
481 return Fortran::common::nullopt;
485template <TypeCategory CAT,
int KIND>
486using AccumulationType = CppTypeFor<CAT,
487 CAT == TypeCategory::Real || CAT == TypeCategory::Complex
488 ? std::max(KIND,
static_cast<int>(
sizeof(
double)))
492template <
typename CHAR>
493static inline RT_API_ATTRS
const CHAR *FindCharacter(
494 const CHAR *data, CHAR ch, std::size_t chars) {
495 const CHAR *end{data + chars};
496 for (
const CHAR *p{data}; p < end; ++p) {
505inline RT_API_ATTRS
const char *FindCharacter(
506 const char *data,
char ch, std::size_t chars) {
507 return reinterpret_cast<const char *
>(
508 runtime::memchr(data,
static_cast<int>(ch), chars));
514RT_API_ATTRS
void ShallowCopyDiscontiguousToDiscontiguous(
515 const Descriptor &to,
const Descriptor &from);
516RT_API_ATTRS
void ShallowCopyDiscontiguousToContiguous(
517 const Descriptor &to,
const Descriptor &from);
518RT_API_ATTRS
void ShallowCopyContiguousToDiscontiguous(
519 const Descriptor &to,
const Descriptor &from);
520RT_API_ATTRS
void ShallowCopy(
const Descriptor &to,
const Descriptor &from,
521 bool toIsContiguous,
bool fromIsContiguous);
522RT_API_ATTRS
void ShallowCopy(
const Descriptor &to,
const Descriptor &from);
528RT_API_ATTRS
char *EnsureNullTerminated(
529 char *str, std::size_t length, Terminator &terminator);
531RT_API_ATTRS
bool IsValidCharDescriptor(
const Descriptor *value);
533RT_API_ATTRS
bool IsValidIntDescriptor(
const Descriptor *intVal);
539RT_API_ATTRS std::int32_t CopyCharsToDescriptor(
const Descriptor &value,
540 const char *rawValue, std::size_t rawValueLength,
541 const Descriptor *errmsg =
nullptr, std::size_t offset = 0);
543RT_API_ATTRS
void StoreIntToDescriptor(
544 const Descriptor *length, std::int64_t value, Terminator &terminator);
547template <
typename TO,
typename FROM>
548RT_API_ATTRS
void CopyAndPad(
549 TO *to,
const FROM *from, std::size_t toChars, std::size_t fromChars) {
550 if constexpr (
sizeof(TO) !=
sizeof(FROM)) {
551 std::size_t copyChars{std::min(toChars, fromChars)};
552 for (std::size_t j{0}; j < copyChars; ++j) {
555 for (std::size_t j{copyChars}; j < toChars; ++j) {
556 to[j] =
static_cast<TO
>(
' ');
558 }
else if (toChars <= fromChars) {
559 std::memcpy(to, from, toChars *
sizeof(TO));
561 std::memcpy(to, from, std::min(toChars, fromChars) *
sizeof(TO));
562 for (std::size_t j{fromChars}; j < toChars; ++j) {
563 to[j] =
static_cast<TO
>(
' ');
568RT_API_ATTRS
void CreatePartialReductionResult(Descriptor &result,
569 const Descriptor &x, std::size_t resultElementSize,
int dim, Terminator &,
570 const char *intrinsic, TypeCode);
Definition: descriptor.h:138
Definition: terminator.h:23