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 <cstring>
17
18// The file defines a set of utilities/classes that might be
19// used to get reduce the dependency on external libraries (e.g. libstdc++).
20
21#if !defined(STD_FILL_N_UNSUPPORTED) && \
22 (defined(__CUDACC__) || defined(__CUDA__)) && defined(__CUDA_ARCH__)
23#define STD_FILL_N_UNSUPPORTED 1
24#endif
25
26#if !defined(STD_MEMMOVE_UNSUPPORTED) && \
27 (defined(__CUDACC__) || defined(__CUDA__)) && defined(__CUDA_ARCH__)
28#define STD_MEMMOVE_UNSUPPORTED 1
29#endif
30
31#if !defined(STD_STRLEN_UNSUPPORTED) && \
32 (defined(__CUDACC__) || defined(__CUDA__)) && defined(__CUDA_ARCH__)
33#define STD_STRLEN_UNSUPPORTED 1
34#endif
35
36#if !defined(STD_MEMCMP_UNSUPPORTED) && \
37 (defined(__CUDACC__) || defined(__CUDA__)) && defined(__CUDA_ARCH__)
38#define STD_MEMCMP_UNSUPPORTED 1
39#endif
40
41#if !defined(STD_REALLOC_UNSUPPORTED) && \
42 (defined(__CUDACC__) || defined(__CUDA__)) && defined(__CUDA_ARCH__)
43#define STD_REALLOC_UNSUPPORTED 1
44#endif
45
46#if !defined(STD_MEMCHR_UNSUPPORTED) && \
47 (defined(__CUDACC__) || defined(__CUDA__)) && defined(__CUDA_ARCH__)
48#define STD_MEMCHR_UNSUPPORTED 1
49#endif
50
51#if !defined(STD_STRCPY_UNSUPPORTED) && \
52 (defined(__CUDACC__) || defined(__CUDA__)) && defined(__CUDA_ARCH__)
53#define STD_STRCPY_UNSUPPORTED 1
54#endif
55
56#if !defined(STD_STRCMP_UNSUPPORTED) && \
57 (defined(__CUDACC__) || defined(__CUDA__)) && defined(__CUDA_ARCH__)
58#define STD_STRCMP_UNSUPPORTED 1
59#endif
60
61#if !defined(STD_TOUPPER_UNSUPPORTED) && \
62 (defined(__CUDACC__) || defined(__CUDA__)) && defined(__CUDA_ARCH__)
63#define STD_TOUPPER_UNSUPPORTED 1
64#endif
65
66namespace Fortran::runtime {
67
68#if STD_FILL_N_UNSUPPORTED
69// Provides alternative implementation for std::fill_n(), if
70// it is not supported.
71template <typename A, typename B>
72static inline RT_API_ATTRS std::enable_if_t<std::is_convertible_v<B, A>, void>
73fill_n(A *start, std::size_t count, const B &value) {
74 for (std::size_t j{0}; j < count; ++j) {
75 start[j] = value;
76 }
77}
78#else // !STD_FILL_N_UNSUPPORTED
79using std::fill_n;
80#endif // !STD_FILL_N_UNSUPPORTED
81
82#if STD_MEMMOVE_UNSUPPORTED
83// Provides alternative implementation for std::memmove(), if
84// it is not supported.
85static inline RT_API_ATTRS void *memmove(
86 void *dest, const void *src, std::size_t count) {
87 char *to{reinterpret_cast<char *>(dest)};
88 const char *from{reinterpret_cast<const char *>(src)};
89
90 if (to == from) {
91 return;
92 }
93 if (to + count <= from || from + count <= to) {
94 std::memcpy(dest, src, count);
95 } else if (to < from) {
96 while (count--) {
97 *to++ = *from++;
98 }
99 } else {
100 to += count;
101 from += count;
102 while (count--) {
103 *--to = *--from;
104 }
105 }
106 return dest;
107}
108#else // !STD_MEMMOVE_UNSUPPORTED
109using std::memmove;
110#endif // !STD_MEMMOVE_UNSUPPORTED
111
112using MemmoveFct = void *(*)(void *, const void *, std::size_t);
113
114#ifdef RT_DEVICE_COMPILATION
115static RT_API_ATTRS void *MemmoveWrapper(
116 void *dest, const void *src, std::size_t count) {
117 return Fortran::runtime::memmove(dest, src, count);
118}
119#endif
120
121#if STD_STRLEN_UNSUPPORTED
122// Provides alternative implementation for std::strlen(), if
123// it is not supported.
124static inline RT_API_ATTRS std::size_t strlen(const char *str) {
125 if (!str) {
126 // Return 0 for nullptr.
127 return 0;
128 }
129 const char *end = str;
130 for (; *end != '\0'; ++end)
131 ;
132 return end - str;
133}
134#else // !STD_STRLEN_UNSUPPORTED
135using std::strlen;
136#endif // !STD_STRLEN_UNSUPPORTED
137
138#if STD_MEMCMP_UNSUPPORTED
139// Provides alternative implementation for std::memcmp(), if
140// it is not supported.
141static inline RT_API_ATTRS int memcmp(
142 const void *RESTRICT lhs, const void *RESTRICT rhs, std::size_t count) {
143 auto m1{reinterpret_cast<const unsigned char *>(lhs)};
144 auto m2{reinterpret_cast<const unsigned char *>(rhs)};
145 for (; count--; ++m1, ++m2) {
146 int diff = *m1 - *m2;
147 if (diff != 0) {
148 return diff;
149 }
150 }
151 return 0;
152}
153#else // !STD_MEMCMP_UNSUPPORTED
154using std::memcmp;
155#endif // !STD_MEMCMP_UNSUPPORTED
156
157#if STD_REALLOC_UNSUPPORTED
158static inline RT_API_ATTRS void *realloc(void *ptr, std::size_t newByteSize) {
159 // Return nullptr and let the callers assert that.
160 // TODO: we can provide a straightforward implementation
161 // via malloc/memcpy/free.
162 return nullptr;
163}
164#else // !STD_REALLOC_UNSUPPORTED
165using std::realloc;
166#endif // !STD_REALLOC_UNSUPPORTED
167
168#if STD_MEMCHR_UNSUPPORTED
169// Provides alternative implementation for std::memchr(), if
170// it is not supported.
171static inline RT_API_ATTRS const void *memchr(
172 const void *ptr, int ch, std::size_t count) {
173 auto buf{reinterpret_cast<const unsigned char *>(ptr)};
174 auto c{static_cast<unsigned char>(ch)};
175 for (; count--; ++buf) {
176 if (*buf == c) {
177 return buf;
178 }
179 }
180 return nullptr;
181}
182#else // !STD_MEMCMP_UNSUPPORTED
183using std::memchr;
184#endif // !STD_MEMCMP_UNSUPPORTED
185
186#if STD_STRCPY_UNSUPPORTED
187// Provides alternative implementation for std::strcpy(), if
188// it is not supported.
189static inline RT_API_ATTRS char *strcpy(char *dest, const char *src) {
190 char *result{dest};
191 do {
192 *dest++ = *src;
193 } while (*src++ != '\0');
194 return result;
195}
196#else // !STD_STRCPY_UNSUPPORTED
197using std::strcpy;
198#endif // !STD_STRCPY_UNSUPPORTED
199
200#if STD_STRCMP_UNSUPPORTED
201// Provides alternative implementation for std::strcmp(), if
202// it is not supported.
203static inline RT_API_ATTRS int strcmp(const char *lhs, const char *rhs) {
204 while (*lhs != '\0' && *lhs == *rhs) {
205 ++lhs;
206 ++rhs;
207 }
208 return static_cast<unsigned char>(*lhs) - static_cast<unsigned char>(*rhs);
209}
210#else // !STD_STRCMP_UNSUPPORTED
211using std::strcmp;
212#endif // !STD_STRCMP_UNSUPPORTED
213
214#if STD_TOUPPER_UNSUPPORTED
215// Provides alternative implementation for std::toupper(), if
216// it is not supported.
217static inline RT_API_ATTRS int toupper(int ch) {
218 if (ch >= 'a' && ch <= 'z') {
219 return ch - 'a' + 'A';
220 }
221 return ch;
222}
223#else // !STD_TOUPPER_UNSUPPORTED
224using std::toupper;
225#endif // !STD_TOUPPER_UNSUPPORTED
226
227} // namespace Fortran::runtime
228#endif // FORTRAN_RUNTIME_FREESTANDING_TOOLS_H_