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