FLANG
freestanding-tools.h
1//===-- include/flang/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/Common/api-attrs.h"
13#include "flang/Runtime/c-or-cpp.h"
14#include <algorithm>
15#include <cctype>
16#include <cstdlib>
17#include <cstring>
18
19// The file defines a set of utilities/classes that might be
20// used to get reduce the dependency on external libraries (e.g. libstdc++).
21
22#if !defined(STD_FILL_N_UNSUPPORTED) && \
23 (defined(__CUDACC__) || defined(__CUDA__)) && defined(__CUDA_ARCH__)
24#define STD_FILL_N_UNSUPPORTED 1
25#endif
26
27#if !defined(STD_MEMMOVE_UNSUPPORTED) && \
28 (defined(__CUDACC__) || defined(__CUDA__)) && defined(__CUDA_ARCH__)
29#define STD_MEMMOVE_UNSUPPORTED 1
30#endif
31
32#if !defined(STD_STRLEN_UNSUPPORTED) && \
33 (defined(__CUDACC__) || defined(__CUDA__)) && defined(__CUDA_ARCH__)
34#define STD_STRLEN_UNSUPPORTED 1
35#endif
36
37#if !defined(STD_MEMCMP_UNSUPPORTED) && \
38 (defined(__CUDACC__) || defined(__CUDA__)) && defined(__CUDA_ARCH__)
39#define STD_MEMCMP_UNSUPPORTED 1
40#endif
41
42#if !defined(STD_REALLOC_UNSUPPORTED) && \
43 (defined(__CUDACC__) || defined(__CUDA__)) && defined(__CUDA_ARCH__)
44#define STD_REALLOC_UNSUPPORTED 1
45#endif
46
47#if !defined(STD_MEMCHR_UNSUPPORTED) && \
48 (defined(__CUDACC__) || defined(__CUDA__)) && defined(__CUDA_ARCH__)
49#define STD_MEMCHR_UNSUPPORTED 1
50#endif
51
52#if !defined(STD_STRCPY_UNSUPPORTED) && \
53 (defined(__CUDACC__) || defined(__CUDA__)) && defined(__CUDA_ARCH__)
54#define STD_STRCPY_UNSUPPORTED 1
55#endif
56
57#if !defined(STD_STRCMP_UNSUPPORTED) && \
58 (defined(__CUDACC__) || defined(__CUDA__)) && defined(__CUDA_ARCH__)
59#define STD_STRCMP_UNSUPPORTED 1
60#endif
61
62#if !defined(STD_TOUPPER_UNSUPPORTED) && \
63 (defined(__CUDACC__) || defined(__CUDA__)) && defined(__CUDA_ARCH__)
64#define STD_TOUPPER_UNSUPPORTED 1
65#endif
66
67#if defined(OMP_OFFLOAD_BUILD) && defined(__clang__)
68#define STD_FILL_N_UNSUPPORTED 1
69#define STD_MEMSET_USE_BUILTIN 1
70#define STD_MEMSET_UNSUPPORTED 1
71#define STD_MEMCPY_USE_BUILTIN 1
72#define STD_MEMCPY_UNSUPPORTED 1
73#define STD_MEMMOVE_UNSUPPORTED 1
74#define STD_STRLEN_UNSUPPORTED 1
75#define STD_MEMCMP_UNSUPPORTED 1
76#define STD_REALLOC_UNSUPPORTED 1
77#define STD_MEMCHR_UNSUPPORTED 1
78#define STD_STRCPY_UNSUPPORTED 1
79#define STD_STRCMP_UNSUPPORTED 1
80#define STD_TOUPPER_UNSUPPORTED 1
81#define STD_ABORT_USE_BUILTIN 1
82#define STD_ABORT_UNSUPPORTED 1
83#endif
84
85namespace Fortran::runtime {
86
87#if STD_FILL_N_UNSUPPORTED
88// Provides alternative implementation for std::fill_n(), if
89// it is not supported.
90template <typename A, typename B>
91static inline RT_API_ATTRS std::enable_if_t<std::is_convertible_v<B, A>, void>
92fill_n(A *start, std::size_t count, const B &value) {
93 for (std::size_t j{0}; j < count; ++j) {
94 start[j] = value;
95 }
96}
97#else // !STD_FILL_N_UNSUPPORTED
98using std::fill_n;
99#endif // !STD_FILL_N_UNSUPPORTED
100
101#if STD_MEMSET_USE_BUILTIN
102static inline RT_API_ATTRS void memset(
103 void *dest, unsigned char value, std::size_t count) {
104 __builtin_memset(dest, value, count);
105}
106#elif STD_MEMSET_UNSUPPORTED
107static inline RT_API_ATTRS void memset(
108 void *dest, unsigned char value, std::size_t count) {
109 char *to{reinterpret_cast<char *>(dest)};
110 while (count--) {
111 *to++ = value;
112 }
113 return;
114}
115#else
116using std::memset;
117#endif
118
119#if STD_MEMCPY_USE_BUILTIN
120static inline RT_API_ATTRS void *memcpy(
121 void *dest, const void *src, std::size_t count) {
122 __builtin_memcpy(dest, src, count);
123 return dest;
124}
125#elif STD_MEMCPY_UNSUPPORTED
126static inline RT_API_ATTRS void *memcpy(
127 void *dest, const void *src, std::size_t count) {
128 char *to{reinterpret_cast<char *>(dest)};
129 const char *from{reinterpret_cast<const char *>(src)};
130 if (to == from) {
131 return dest;
132 }
133 while (count--) {
134 *to++ = *from++;
135 }
136 return dest;
137}
138#else
139using std::memcpy;
140#endif
141
142#if STD_MEMMOVE_USE_BUILTIN
143static inline RT_API_ATTRS void *memmove(
144 void *dest, const void *src, std::size_t count) {
145 __builtin_memmove(dest, src, count);
146 return dest;
147}
148#elif STD_MEMMOVE_UNSUPPORTED
149// Provides alternative implementation for std::memmove(), if
150// it is not supported.
151static inline RT_API_ATTRS void *memmove(
152 void *dest, const void *src, std::size_t count) {
153 char *to{reinterpret_cast<char *>(dest)};
154 const char *from{reinterpret_cast<const char *>(src)};
155
156 if (to == from) {
157 return dest;
158 }
159 if (to + count <= from || from + count <= to) {
160 memcpy(dest, src, count);
161 } else if (to < from) {
162 while (count--) {
163 *to++ = *from++;
164 }
165 } else {
166 to += count;
167 from += count;
168 while (count--) {
169 *--to = *--from;
170 }
171 }
172 return dest;
173}
174#else // !STD_MEMMOVE_UNSUPPORTED
175using std::memmove;
176#endif // !STD_MEMMOVE_UNSUPPORTED
177
178using MemmoveFct = void *(*)(void *, const void *, std::size_t);
179using MemcpyFct = void *(*)(void *, const void *, std::size_t);
180
181#ifdef RT_DEVICE_COMPILATION
182[[maybe_unused]] static RT_API_ATTRS void *MemmoveWrapper(
183 void *dest, const void *src, std::size_t count) {
184 return Fortran::runtime::memmove(dest, src, count);
185}
186[[maybe_unused]] static RT_API_ATTRS void *MemcpyWrapper(
187 void *dest, const void *src, std::size_t count) {
188 return Fortran::runtime::memcpy(dest, src, count);
189}
190#endif
191
192#if STD_STRLEN_USE_BUILTIN
193static inline RT_API_ATTRS std::size_t strlen(const char *str) {
194 return __builtin_strlen(str);
195}
196#elif STD_STRLEN_UNSUPPORTED
197// Provides alternative implementation for std::strlen(), if
198// it is not supported.
199static inline RT_API_ATTRS std::size_t strlen(const char *str) {
200 if (!str) {
201 // Return 0 for nullptr.
202 return 0;
203 }
204 const char *end = str;
205 for (; *end != '\0'; ++end)
206 ;
207 return end - str;
208}
209#else // !STD_STRLEN_UNSUPPORTED
210using std::strlen;
211#endif // !STD_STRLEN_UNSUPPORTED
212
213#if STD_MEMCMP_UNSUPPORTED
214// Provides alternative implementation for std::memcmp(), if
215// it is not supported.
216static inline RT_API_ATTRS int memcmp(
217 const void *RESTRICT lhs, const void *RESTRICT rhs, std::size_t count) {
218 auto m1{reinterpret_cast<const unsigned char *>(lhs)};
219 auto m2{reinterpret_cast<const unsigned char *>(rhs)};
220 for (; count--; ++m1, ++m2) {
221 int diff = *m1 - *m2;
222 if (diff != 0) {
223 return diff;
224 }
225 }
226 return 0;
227}
228#else // !STD_MEMCMP_UNSUPPORTED
229using std::memcmp;
230#endif // !STD_MEMCMP_UNSUPPORTED
231
232#if STD_REALLOC_UNSUPPORTED
233static inline RT_API_ATTRS void *realloc(void *ptr, std::size_t newByteSize) {
234 // Return nullptr and let the callers assert that.
235 // TODO: we can provide a straightforward implementation
236 // via malloc/memcpy/free.
237 return nullptr;
238}
239#else // !STD_REALLOC_UNSUPPORTED
240using std::realloc;
241#endif // !STD_REALLOC_UNSUPPORTED
242
243#if STD_MEMCHR_UNSUPPORTED
244// Provides alternative implementation for std::memchr(), if
245// it is not supported.
246static inline RT_API_ATTRS const void *memchr(
247 const void *ptr, int ch, std::size_t count) {
248 auto buf{reinterpret_cast<const unsigned char *>(ptr)};
249 auto c{static_cast<unsigned char>(ch)};
250 for (; count--; ++buf) {
251 if (*buf == c) {
252 return buf;
253 }
254 }
255 return nullptr;
256}
257#else // !STD_MEMCMP_UNSUPPORTED
258using std::memchr;
259#endif // !STD_MEMCMP_UNSUPPORTED
260
261#if STD_STRCPY_UNSUPPORTED
262// Provides alternative implementation for std::strcpy(), if
263// it is not supported.
264static inline RT_API_ATTRS char *strcpy(char *dest, const char *src) {
265 char *result{dest};
266 do {
267 *dest++ = *src;
268 } while (*src++ != '\0');
269 return result;
270}
271#else // !STD_STRCPY_UNSUPPORTED
272using std::strcpy;
273#endif // !STD_STRCPY_UNSUPPORTED
274
275#if STD_STRCMP_UNSUPPORTED
276// Provides alternative implementation for std::strcmp(), if
277// it is not supported.
278static inline RT_API_ATTRS int strcmp(const char *lhs, const char *rhs) {
279 while (*lhs != '\0' && *lhs == *rhs) {
280 ++lhs;
281 ++rhs;
282 }
283 return static_cast<unsigned char>(*lhs) - static_cast<unsigned char>(*rhs);
284}
285#else // !STD_STRCMP_UNSUPPORTED
286using std::strcmp;
287#endif // !STD_STRCMP_UNSUPPORTED
288
289#if STD_TOUPPER_UNSUPPORTED
290// Provides alternative implementation for std::toupper(), if
291// it is not supported.
292static inline RT_API_ATTRS int toupper(int ch) {
293 if (ch >= 'a' && ch <= 'z') {
294 return ch - 'a' + 'A';
295 }
296 return ch;
297}
298#else // !STD_TOUPPER_UNSUPPORTED
299using std::toupper;
300#endif // !STD_TOUPPER_UNSUPPORTED
301
302} // namespace Fortran::runtime
303#endif // FORTRAN_RUNTIME_FREESTANDING_TOOLS_H_