xref: /llvm-project/flang/include/flang/Runtime/freestanding-tools.h (revision 42be165dde50c29e1d104f38938c03c95b4471cf)
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 
66 namespace Fortran::runtime {
67 
68 #if STD_FILL_N_UNSUPPORTED
69 // Provides alternative implementation for std::fill_n(), if
70 // it is not supported.
71 template <typename A, typename B>
72 static inline RT_API_ATTRS std::enable_if_t<std::is_convertible_v<B, A>, void>
73 fill_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
79 using 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.
85 static 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
109 using std::memmove;
110 #endif // !STD_MEMMOVE_UNSUPPORTED
111 
112 using MemmoveFct = void *(*)(void *, const void *, std::size_t);
113 
114 #ifdef RT_DEVICE_COMPILATION
115 static 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.
124 static 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
135 using 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.
141 static 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
154 using std::memcmp;
155 #endif // !STD_MEMCMP_UNSUPPORTED
156 
157 #if STD_REALLOC_UNSUPPORTED
158 static 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
165 using 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.
171 static 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
183 using 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.
189 static 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
197 using 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.
203 static 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
211 using 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.
217 static 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
224 using std::toupper;
225 #endif // !STD_TOUPPER_UNSUPPORTED
226 
227 } // namespace Fortran::runtime
228 #endif // FORTRAN_RUNTIME_FREESTANDING_TOOLS_H_
229