1 | //===-- runtime/freestanding-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_FREESTANDING_TOOLS_H_ |
10 | #define FORTRAN_RUNTIME_FREESTANDING_TOOLS_H_ |
11 | |
12 | #include "flang/Runtime/api-attrs.h" |
13 | #include "flang/Runtime/c-or-cpp.h" |
14 | #include <algorithm> |
15 | #include <cstring> |
16 | |
17 | // The file defines a set of utilities/classes that might be |
18 | // used to get reduce the dependency on external libraries (e.g. libstdc++). |
19 | |
20 | #if !defined(STD_FILL_N_UNSUPPORTED) && \ |
21 | (defined(__CUDACC__) || defined(__CUDA__)) && defined(__CUDA_ARCH__) |
22 | #define STD_FILL_N_UNSUPPORTED 1 |
23 | #endif |
24 | |
25 | #if !defined(STD_MEMMOVE_UNSUPPORTED) && \ |
26 | (defined(__CUDACC__) || defined(__CUDA__)) && defined(__CUDA_ARCH__) |
27 | #define STD_MEMMOVE_UNSUPPORTED 1 |
28 | #endif |
29 | |
30 | #if !defined(STD_STRLEN_UNSUPPORTED) && \ |
31 | (defined(__CUDACC__) || defined(__CUDA__)) && defined(__CUDA_ARCH__) |
32 | #define STD_STRLEN_UNSUPPORTED 1 |
33 | #endif |
34 | |
35 | #if !defined(STD_MEMCMP_UNSUPPORTED) && \ |
36 | (defined(__CUDACC__) || defined(__CUDA__)) && defined(__CUDA_ARCH__) |
37 | #define STD_MEMCMP_UNSUPPORTED 1 |
38 | #endif |
39 | |
40 | #if !defined(STD_REALLOC_UNSUPPORTED) && \ |
41 | (defined(__CUDACC__) || defined(__CUDA__)) && defined(__CUDA_ARCH__) |
42 | #define STD_REALLOC_UNSUPPORTED 1 |
43 | #endif |
44 | |
45 | namespace Fortran::runtime { |
46 | |
47 | #if STD_FILL_N_UNSUPPORTED |
48 | // Provides alternative implementation for std::fill_n(), if |
49 | // it is not supported. |
50 | template <typename A> |
51 | static inline RT_API_ATTRS void fill_n( |
52 | A *start, std::size_t count, const A &value) { |
53 | for (std::size_t j{0}; j < count; ++j) { |
54 | start[j] = value; |
55 | } |
56 | } |
57 | #else // !STD_FILL_N_UNSUPPORTED |
58 | using std::fill_n; |
59 | #endif // !STD_FILL_N_UNSUPPORTED |
60 | |
61 | #if STD_MEMMOVE_UNSUPPORTED |
62 | // Provides alternative implementation for std::memmove(), if |
63 | // it is not supported. |
64 | static inline RT_API_ATTRS void memmove( |
65 | void *dest, const void *src, std::size_t count) { |
66 | char *to{reinterpret_cast<char *>(dest)}; |
67 | const char *from{reinterpret_cast<const char *>(src)}; |
68 | |
69 | if (to == from) { |
70 | return; |
71 | } |
72 | if (to + count <= from || from + count <= to) { |
73 | std::memcpy(dest, src, count); |
74 | } else if (to < from) { |
75 | while (count--) { |
76 | *to++ = *from++; |
77 | } |
78 | } else { |
79 | to += count; |
80 | from += count; |
81 | while (count--) { |
82 | *--to = *--from; |
83 | } |
84 | } |
85 | } |
86 | #else // !STD_MEMMOVE_UNSUPPORTED |
87 | using std::memmove; |
88 | #endif // !STD_MEMMOVE_UNSUPPORTED |
89 | |
90 | #if STD_STRLEN_UNSUPPORTED |
91 | // Provides alternative implementation for std::strlen(), if |
92 | // it is not supported. |
93 | static inline RT_API_ATTRS std::size_t strlen(const char *str) { |
94 | if (!str) { |
95 | // Return 0 for nullptr. |
96 | return 0; |
97 | } |
98 | const char *end = str; |
99 | for (; *end != '\0'; ++end) |
100 | ; |
101 | return end - str; |
102 | } |
103 | #else // !STD_STRLEN_UNSUPPORTED |
104 | using std::strlen; |
105 | #endif // !STD_STRLEN_UNSUPPORTED |
106 | |
107 | #if STD_MEMCMP_UNSUPPORTED |
108 | // Provides alternative implementation for std::memcmp(), if |
109 | // it is not supported. |
110 | static inline RT_API_ATTRS int memcmp( |
111 | const void *RESTRICT lhs, const void *RESTRICT rhs, std::size_t count) { |
112 | auto m1{reinterpret_cast<const unsigned char *>(lhs)}; |
113 | auto m2{reinterpret_cast<const unsigned char *>(rhs)}; |
114 | for (; count--; ++m1, ++m2) { |
115 | int diff = *m1 - *m2; |
116 | if (diff != 0) { |
117 | return diff; |
118 | } |
119 | } |
120 | return 0; |
121 | } |
122 | #else // !STD_MEMCMP_UNSUPPORTED |
123 | using std::memcmp; |
124 | #endif // !STD_MEMCMP_UNSUPPORTED |
125 | |
126 | #if STD_REALLOC_UNSUPPORTED |
127 | static inline RT_API_ATTRS void *realloc(void *ptr, std::size_t newByteSize) { |
128 | // Return nullptr and let the callers assert that. |
129 | // TODO: we can provide a straightforward implementation |
130 | // via malloc/memcpy/free. |
131 | return nullptr; |
132 | } |
133 | #else // !STD_REALLOC_UNSUPPORTED |
134 | using std::realloc; |
135 | #endif // !STD_REALLOC_UNSUPPORTED |
136 | |
137 | } // namespace Fortran::runtime |
138 | #endif // FORTRAN_RUNTIME_FREESTANDING_TOOLS_H_ |
139 | |