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}
124#elif STD_MEMCPY_UNSUPPORTED
125static inline RT_API_ATTRS void memcpy(
126 void *dest, const void *src, std::size_t count) {
127 char *to{reinterpret_cast<char *>(dest)};
128 const char *from{reinterpret_cast<const char *>(src)};
129 if (to == from) {
130 return;
131 }
132 while (count--) {
133 *to++ = *from++;
134 }
135}
136#else
137using std::memcpy;
138#endif
139
140#if STD_MEMMOVE_USE_BUILTIN
141static inline RT_API_ATTRS void memmove(
142 void *dest, const void *src, std::size_t count) {
143 __builtin_memmove(dest, src, count);
144}
145#elif STD_MEMMOVE_UNSUPPORTED
146// Provides alternative implementation for std::memmove(), if
147// it is not supported.
148static inline RT_API_ATTRS void *memmove(
149 void *dest, const void *src, std::size_t count) {
150 char *to{reinterpret_cast<char *>(dest)};
151 const char *from{reinterpret_cast<const char *>(src)};
152
153 if (to == from) {
154 return dest;
155 }
156 if (to + count <= from || from + count <= to) {
157 memcpy(dest, src, count);
158 } else if (to < from) {
159 while (count--) {
160 *to++ = *from++;
161 }
162 } else {
163 to += count;
164 from += count;
165 while (count--) {
166 *--to = *--from;
167 }
168 }
169 return dest;
170}
171#else // !STD_MEMMOVE_UNSUPPORTED
172using std::memmove;
173#endif // !STD_MEMMOVE_UNSUPPORTED
174
175using MemmoveFct = void *(*)(void *, const void *, std::size_t);
176
177#ifdef RT_DEVICE_COMPILATION
178[[maybe_unused]] static RT_API_ATTRS void *MemmoveWrapper(
179 void *dest, const void *src, std::size_t count) {
180 return Fortran::runtime::memmove(dest, src, count);
181}
182#endif
183
184#if STD_STRLEN_USE_BUILTIN
185static inline RT_API_ATTRS std::size_t strlen(const char *str) {
186 return __builtin_strlen(str);
187}
188#elif STD_STRLEN_UNSUPPORTED
189// Provides alternative implementation for std::strlen(), if
190// it is not supported.
191static inline RT_API_ATTRS std::size_t strlen(const char *str) {
192 if (!str) {
193 // Return 0 for nullptr.
194 return 0;
195 }
196 const char *end = str;
197 for (; *end != '\0'; ++end)
198 ;
199 return end - str;
200}
201#else // !STD_STRLEN_UNSUPPORTED
202using std::strlen;
203#endif // !STD_STRLEN_UNSUPPORTED
204
205#if STD_MEMCMP_UNSUPPORTED
206// Provides alternative implementation for std::memcmp(), if
207// it is not supported.
208static inline RT_API_ATTRS int memcmp(
209 const void *RESTRICT lhs, const void *RESTRICT rhs, std::size_t count) {
210 auto m1{reinterpret_cast<const unsigned char *>(lhs)};
211 auto m2{reinterpret_cast<const unsigned char *>(rhs)};
212 for (; count--; ++m1, ++m2) {
213 int diff = *m1 - *m2;
214 if (diff != 0) {
215 return diff;
216 }
217 }
218 return 0;
219}
220#else // !STD_MEMCMP_UNSUPPORTED
221using std::memcmp;
222#endif // !STD_MEMCMP_UNSUPPORTED
223
224#if STD_REALLOC_UNSUPPORTED
225static inline RT_API_ATTRS void *realloc(void *ptr, std::size_t newByteSize) {
226 // Return nullptr and let the callers assert that.
227 // TODO: we can provide a straightforward implementation
228 // via malloc/memcpy/free.
229 return nullptr;
230}
231#else // !STD_REALLOC_UNSUPPORTED
232using std::realloc;
233#endif // !STD_REALLOC_UNSUPPORTED
234
235#if STD_MEMCHR_UNSUPPORTED
236// Provides alternative implementation for std::memchr(), if
237// it is not supported.
238static inline RT_API_ATTRS const void *memchr(
239 const void *ptr, int ch, std::size_t count) {
240 auto buf{reinterpret_cast<const unsigned char *>(ptr)};
241 auto c{static_cast<unsigned char>(ch)};
242 for (; count--; ++buf) {
243 if (*buf == c) {
244 return buf;
245 }
246 }
247 return nullptr;
248}
249#else // !STD_MEMCMP_UNSUPPORTED
250using std::memchr;
251#endif // !STD_MEMCMP_UNSUPPORTED
252
253#if STD_STRCPY_UNSUPPORTED
254// Provides alternative implementation for std::strcpy(), if
255// it is not supported.
256static inline RT_API_ATTRS char *strcpy(char *dest, const char *src) {
257 char *result{dest};
258 do {
259 *dest++ = *src;
260 } while (*src++ != '\0');
261 return result;
262}
263#else // !STD_STRCPY_UNSUPPORTED
264using std::strcpy;
265#endif // !STD_STRCPY_UNSUPPORTED
266
267#if STD_STRCMP_UNSUPPORTED
268// Provides alternative implementation for std::strcmp(), if
269// it is not supported.
270static inline RT_API_ATTRS int strcmp(const char *lhs, const char *rhs) {
271 while (*lhs != '\0' && *lhs == *rhs) {
272 ++lhs;
273 ++rhs;
274 }
275 return static_cast<unsigned char>(*lhs) - static_cast<unsigned char>(*rhs);
276}
277#else // !STD_STRCMP_UNSUPPORTED
278using std::strcmp;
279#endif // !STD_STRCMP_UNSUPPORTED
280
281#if STD_TOUPPER_UNSUPPORTED
282// Provides alternative implementation for std::toupper(), if
283// it is not supported.
284static inline RT_API_ATTRS int toupper(int ch) {
285 if (ch >= 'a' && ch <= 'z') {
286 return ch - 'a' + 'A';
287 }
288 return ch;
289}
290#else // !STD_TOUPPER_UNSUPPORTED
291using std::toupper;
292#endif // !STD_TOUPPER_UNSUPPORTED
293
294} // namespace Fortran::runtime
295#endif // FORTRAN_RUNTIME_FREESTANDING_TOOLS_H_