peter klausler | fae12a0 | 2020-01-24 00:10:00 | [diff] [blame] | 1 | //===-- runtime/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_TOOLS_H_ |
| 10 | #define FORTRAN_RUNTIME_TOOLS_H_ |
peter klausler | f7be251 | 2020-01-24 00:59:27 | [diff] [blame] | 11 | |
peter klausler | e372e0f | 2021-03-31 16:14:08 | [diff] [blame] | 12 | #include "cpp-type.h" |
| 13 | #include "descriptor.h" |
peter klausler | fae12a0 | 2020-01-24 00:10:00 | [diff] [blame] | 14 | #include "memory.h" |
peter klausler | e372e0f | 2021-03-31 16:14:08 | [diff] [blame] | 15 | #include "terminator.h" |
peter klausler | 8d672c0b | 2021-04-20 16:19:21 | [diff] [blame] | 16 | #include "flang/Common/long-double.h" |
peter klausler | f7be251 | 2020-01-24 00:59:27 | [diff] [blame] | 17 | #include <functional> |
| 18 | #include <map> |
| 19 | #include <type_traits> |
| 20 | |
peter klausler | fae12a0 | 2020-01-24 00:10:00 | [diff] [blame] | 21 | namespace Fortran::runtime { |
| 22 | |
| 23 | class Terminator; |
| 24 | |
peter klausler | 675ad1b | 2020-08-03 18:35:29 | [diff] [blame] | 25 | std::size_t TrimTrailingSpaces(const char *, std::size_t); |
| 26 | |
peter klausler | 95696d5 | 2020-02-05 00:55:45 | [diff] [blame] | 27 | OwningPtr<char> SaveDefaultCharacter( |
| 28 | const char *, std::size_t, const Terminator &); |
peter klausler | fae12a0 | 2020-01-24 00:10:00 | [diff] [blame] | 29 | |
| 30 | // For validating and recognizing default CHARACTER values in a |
| 31 | // case-insensitive manner. Returns the zero-based index into the |
| 32 | // null-terminated array of upper-case possibilities when the value is valid, |
| 33 | // or -1 when it has no match. |
| 34 | int IdentifyValue( |
| 35 | const char *value, std::size_t length, const char *possibilities[]); |
peter klausler | f7be251 | 2020-01-24 00:59:27 | [diff] [blame] | 36 | |
peter klausler | 3b63571 | 2020-02-13 22:41:56 | [diff] [blame] | 37 | // Truncates or pads as necessary |
| 38 | void ToFortranDefaultCharacter( |
| 39 | char *to, std::size_t toLength, const char *from); |
peter klausler | e372e0f | 2021-03-31 16:14:08 | [diff] [blame] | 40 | |
| 41 | // Utility for dealing with elemental LOGICAL arguments |
| 42 | inline bool IsLogicalElementTrue( |
| 43 | const Descriptor &logical, const SubscriptValue at[]) { |
| 44 | // A LOGICAL value is false if and only if all of its bytes are zero. |
| 45 | const char *p{logical.Element<char>(at)}; |
| 46 | for (std::size_t j{logical.ElementBytes()}; j-- > 0; ++p) { |
| 47 | if (*p) { |
| 48 | return true; |
| 49 | } |
| 50 | } |
| 51 | return false; |
| 52 | } |
| 53 | |
| 54 | // Check array conformability; a scalar 'x' conforms. Crashes on error. |
| 55 | void CheckConformability(const Descriptor &to, const Descriptor &x, |
| 56 | Terminator &, const char *funcName, const char *toName, |
| 57 | const char *fromName); |
| 58 | |
| 59 | // Validate a KIND= argument |
| 60 | void CheckIntegerKind(Terminator &, int kind, const char *intrinsic); |
| 61 | |
| 62 | template <typename TO, typename FROM> |
| 63 | inline void PutContiguousConverted(TO *to, FROM *from, std::size_t count) { |
| 64 | while (count-- > 0) { |
| 65 | *to++ = *from++; |
| 66 | } |
| 67 | } |
| 68 | |
peter klausler | c1db35f | 2021-05-20 17:37:03 | [diff] [blame^] | 69 | static inline std::int64_t GetInt64( |
| 70 | const char *p, std::size_t bytes, Terminator &terminator) { |
peter klausler | e372e0f | 2021-03-31 16:14:08 | [diff] [blame] | 71 | switch (bytes) { |
| 72 | case 1: |
| 73 | return *reinterpret_cast<const CppTypeFor<TypeCategory::Integer, 1> *>(p); |
| 74 | case 2: |
| 75 | return *reinterpret_cast<const CppTypeFor<TypeCategory::Integer, 2> *>(p); |
| 76 | case 4: |
| 77 | return *reinterpret_cast<const CppTypeFor<TypeCategory::Integer, 4> *>(p); |
| 78 | case 8: |
| 79 | return *reinterpret_cast<const CppTypeFor<TypeCategory::Integer, 8> *>(p); |
| 80 | default: |
peter klausler | c1db35f | 2021-05-20 17:37:03 | [diff] [blame^] | 81 | terminator.Crash("GetInt64: no case for %zd bytes", bytes); |
peter klausler | e372e0f | 2021-03-31 16:14:08 | [diff] [blame] | 82 | } |
| 83 | } |
| 84 | |
| 85 | template <typename INT> |
| 86 | inline bool SetInteger(INT &x, int kind, std::int64_t value) { |
| 87 | switch (kind) { |
| 88 | case 1: |
| 89 | reinterpret_cast<CppTypeFor<TypeCategory::Integer, 1> &>(x) = value; |
| 90 | return true; |
| 91 | case 2: |
| 92 | reinterpret_cast<CppTypeFor<TypeCategory::Integer, 2> &>(x) = value; |
| 93 | return true; |
| 94 | case 4: |
| 95 | reinterpret_cast<CppTypeFor<TypeCategory::Integer, 4> &>(x) = value; |
| 96 | return true; |
| 97 | case 8: |
| 98 | reinterpret_cast<CppTypeFor<TypeCategory::Integer, 8> &>(x) = value; |
| 99 | return true; |
| 100 | default: |
| 101 | return false; |
| 102 | } |
| 103 | } |
| 104 | |
peter klausler | 50e0b29 | 2021-05-12 19:07:51 | [diff] [blame] | 105 | // Maps intrinsic runtime type category and kind values to the appropriate |
| 106 | // instantiation of a function object template and calls it with the supplied |
| 107 | // arguments. |
| 108 | template <template <TypeCategory, int> class FUNC, typename RESULT, |
| 109 | typename... A> |
| 110 | inline RESULT ApplyType( |
| 111 | TypeCategory cat, int kind, Terminator &terminator, A &&...x) { |
| 112 | switch (cat) { |
| 113 | case TypeCategory::Integer: |
| 114 | switch (kind) { |
| 115 | case 1: |
| 116 | return FUNC<TypeCategory::Integer, 1>{}(std::forward<A>(x)...); |
| 117 | case 2: |
| 118 | return FUNC<TypeCategory::Integer, 2>{}(std::forward<A>(x)...); |
| 119 | case 4: |
| 120 | return FUNC<TypeCategory::Integer, 4>{}(std::forward<A>(x)...); |
| 121 | case 8: |
| 122 | return FUNC<TypeCategory::Integer, 8>{}(std::forward<A>(x)...); |
| 123 | #ifdef __SIZEOF_INT128__ |
| 124 | case 16: |
| 125 | return FUNC<TypeCategory::Integer, 16>{}(std::forward<A>(x)...); |
| 126 | #endif |
| 127 | default: |
| 128 | terminator.Crash("unsupported INTEGER(KIND=%d)", kind); |
| 129 | } |
| 130 | case TypeCategory::Real: |
| 131 | switch (kind) { |
| 132 | #if 0 // TODO: REAL(2 & 3) |
| 133 | case 2: |
| 134 | return FUNC<TypeCategory::Real, 2>{}(std::forward<A>(x)...); |
| 135 | case 3: |
| 136 | return FUNC<TypeCategory::Real, 3>{}(std::forward<A>(x)...); |
| 137 | #endif |
| 138 | case 4: |
| 139 | return FUNC<TypeCategory::Real, 4>{}(std::forward<A>(x)...); |
| 140 | case 8: |
| 141 | return FUNC<TypeCategory::Real, 8>{}(std::forward<A>(x)...); |
| 142 | #if LONG_DOUBLE == 80 |
| 143 | case 10: |
| 144 | return FUNC<TypeCategory::Real, 10>{}(std::forward<A>(x)...); |
| 145 | #elif LONG_DOUBLE == 128 |
| 146 | case 16: |
| 147 | return FUNC<TypeCategory::Real, 16>{}(std::forward<A>(x)...); |
| 148 | #endif |
| 149 | default: |
| 150 | terminator.Crash("unsupported REAL(KIND=%d)", kind); |
| 151 | } |
| 152 | case TypeCategory::Complex: |
| 153 | switch (kind) { |
| 154 | #if 0 // TODO: COMPLEX(2 & 3) |
| 155 | case 2: |
| 156 | return FUNC<TypeCategory::Complex, 2>{}(std::forward<A>(x)...); |
| 157 | case 3: |
| 158 | return FUNC<TypeCategory::Complex, 3>{}(std::forward<A>(x)...); |
| 159 | #endif |
| 160 | case 4: |
| 161 | return FUNC<TypeCategory::Complex, 4>{}(std::forward<A>(x)...); |
| 162 | case 8: |
| 163 | return FUNC<TypeCategory::Complex, 8>{}(std::forward<A>(x)...); |
| 164 | #if LONG_DOUBLE == 80 |
| 165 | case 10: |
| 166 | return FUNC<TypeCategory::Complex, 10>{}(std::forward<A>(x)...); |
| 167 | #elif LONG_DOUBLE == 128 |
| 168 | case 16: |
| 169 | return FUNC<TypeCategory::Complex, 16>{}(std::forward<A>(x)...); |
| 170 | #endif |
| 171 | default: |
| 172 | terminator.Crash("unsupported COMPLEX(KIND=%d)", kind); |
| 173 | } |
| 174 | case TypeCategory::Character: |
| 175 | switch (kind) { |
| 176 | case 1: |
| 177 | return FUNC<TypeCategory::Character, 1>{}(std::forward<A>(x)...); |
| 178 | case 2: |
| 179 | return FUNC<TypeCategory::Character, 2>{}(std::forward<A>(x)...); |
| 180 | case 4: |
| 181 | return FUNC<TypeCategory::Character, 4>{}(std::forward<A>(x)...); |
| 182 | default: |
| 183 | terminator.Crash("unsupported CHARACTER(KIND=%d)", kind); |
| 184 | } |
| 185 | case TypeCategory::Logical: |
| 186 | switch (kind) { |
| 187 | case 1: |
| 188 | return FUNC<TypeCategory::Logical, 1>{}(std::forward<A>(x)...); |
| 189 | case 2: |
| 190 | return FUNC<TypeCategory::Logical, 2>{}(std::forward<A>(x)...); |
| 191 | case 4: |
| 192 | return FUNC<TypeCategory::Logical, 4>{}(std::forward<A>(x)...); |
| 193 | case 8: |
| 194 | return FUNC<TypeCategory::Logical, 8>{}(std::forward<A>(x)...); |
| 195 | default: |
| 196 | terminator.Crash("unsupported LOGICAL(KIND=%d)", kind); |
| 197 | } |
| 198 | default: |
| 199 | terminator.Crash("unsupported type category(%d)", static_cast<int>(cat)); |
| 200 | } |
| 201 | } |
| 202 | |
peter klausler | 8d672c0b | 2021-04-20 16:19:21 | [diff] [blame] | 203 | // Maps a runtime INTEGER kind value to the appropriate instantiation of |
| 204 | // a function object template and calls it with the supplied arguments. |
| 205 | template <template <int KIND> class FUNC, typename RESULT, typename... A> |
| 206 | inline RESULT ApplyIntegerKind(int kind, Terminator &terminator, A &&...x) { |
| 207 | switch (kind) { |
| 208 | case 1: |
| 209 | return FUNC<1>{}(std::forward<A>(x)...); |
| 210 | case 2: |
| 211 | return FUNC<2>{}(std::forward<A>(x)...); |
| 212 | case 4: |
| 213 | return FUNC<4>{}(std::forward<A>(x)...); |
| 214 | case 8: |
| 215 | return FUNC<8>{}(std::forward<A>(x)...); |
| 216 | #ifdef __SIZEOF_INT128__ |
| 217 | case 16: |
| 218 | return FUNC<16>{}(std::forward<A>(x)...); |
| 219 | #endif |
| 220 | default: |
| 221 | terminator.Crash("unsupported INTEGER(KIND=%d)", kind); |
| 222 | } |
| 223 | } |
| 224 | |
| 225 | template <template <int KIND> class FUNC, typename RESULT, typename... A> |
| 226 | inline RESULT ApplyFloatingPointKind( |
| 227 | int kind, Terminator &terminator, A &&...x) { |
| 228 | switch (kind) { |
| 229 | #if 0 // TODO: REAL/COMPLEX (2 & 3) |
| 230 | case 2: |
| 231 | return FUNC<2>{}(std::forward<A>(x)...); |
| 232 | case 3: |
| 233 | return FUNC<3>{}(std::forward<A>(x)...); |
| 234 | #endif |
| 235 | case 4: |
| 236 | return FUNC<4>{}(std::forward<A>(x)...); |
| 237 | case 8: |
| 238 | return FUNC<8>{}(std::forward<A>(x)...); |
| 239 | #if LONG_DOUBLE == 80 |
| 240 | case 10: |
| 241 | return FUNC<10>{}(std::forward<A>(x)...); |
| 242 | #elif LONG_DOUBLE == 128 |
| 243 | case 16: |
| 244 | return FUNC<16>{}(std::forward<A>(x)...); |
| 245 | #endif |
| 246 | default: |
| 247 | terminator.Crash("unsupported REAL/COMPLEX(KIND=%d)", kind); |
| 248 | } |
| 249 | } |
| 250 | |
| 251 | template <template <int KIND> class FUNC, typename RESULT, typename... A> |
| 252 | inline RESULT ApplyCharacterKind(int kind, Terminator &terminator, A &&...x) { |
| 253 | switch (kind) { |
| 254 | case 1: |
| 255 | return FUNC<1>{}(std::forward<A>(x)...); |
| 256 | case 2: |
| 257 | return FUNC<2>{}(std::forward<A>(x)...); |
| 258 | case 4: |
| 259 | return FUNC<4>{}(std::forward<A>(x)...); |
| 260 | default: |
| 261 | terminator.Crash("unsupported CHARACTER(KIND=%d)", kind); |
| 262 | } |
| 263 | } |
| 264 | |
| 265 | template <template <int KIND> class FUNC, typename RESULT, typename... A> |
| 266 | inline RESULT ApplyLogicalKind(int kind, Terminator &terminator, A &&...x) { |
| 267 | switch (kind) { |
| 268 | case 1: |
| 269 | return FUNC<1>{}(std::forward<A>(x)...); |
| 270 | case 2: |
| 271 | return FUNC<2>{}(std::forward<A>(x)...); |
| 272 | case 4: |
| 273 | return FUNC<4>{}(std::forward<A>(x)...); |
| 274 | case 8: |
| 275 | return FUNC<8>{}(std::forward<A>(x)...); |
| 276 | default: |
| 277 | terminator.Crash("unsupported LOGICAL(KIND=%d)", kind); |
| 278 | } |
| 279 | } |
| 280 | |
peter klausler | 50e0b29 | 2021-05-12 19:07:51 | [diff] [blame] | 281 | // Calculate result type of (X op Y) for *, //, DOT_PRODUCT, &c. |
| 282 | std::optional<std::pair<TypeCategory, int>> inline constexpr GetResultType( |
| 283 | TypeCategory xCat, int xKind, TypeCategory yCat, int yKind) { |
| 284 | int maxKind{std::max(xKind, yKind)}; |
| 285 | switch (xCat) { |
| 286 | case TypeCategory::Integer: |
| 287 | switch (yCat) { |
| 288 | case TypeCategory::Integer: |
| 289 | return std::make_pair(TypeCategory::Integer, maxKind); |
| 290 | case TypeCategory::Real: |
| 291 | case TypeCategory::Complex: |
| 292 | return std::make_pair(yCat, yKind); |
| 293 | default: |
| 294 | break; |
| 295 | } |
| 296 | break; |
| 297 | case TypeCategory::Real: |
| 298 | switch (yCat) { |
| 299 | case TypeCategory::Integer: |
| 300 | return std::make_pair(TypeCategory::Real, xKind); |
| 301 | case TypeCategory::Real: |
| 302 | case TypeCategory::Complex: |
| 303 | return std::make_pair(yCat, maxKind); |
| 304 | default: |
| 305 | break; |
| 306 | } |
| 307 | break; |
| 308 | case TypeCategory::Complex: |
| 309 | switch (yCat) { |
| 310 | case TypeCategory::Integer: |
| 311 | return std::make_pair(TypeCategory::Complex, xKind); |
| 312 | case TypeCategory::Real: |
| 313 | case TypeCategory::Complex: |
| 314 | return std::make_pair(TypeCategory::Complex, maxKind); |
| 315 | default: |
| 316 | break; |
| 317 | } |
| 318 | break; |
| 319 | case TypeCategory::Character: |
| 320 | if (yCat == TypeCategory::Character) { |
| 321 | return std::make_pair(TypeCategory::Character, maxKind); |
| 322 | } else { |
| 323 | return std::nullopt; |
| 324 | } |
| 325 | case TypeCategory::Logical: |
| 326 | if (yCat == TypeCategory::Logical) { |
| 327 | return std::make_pair(TypeCategory::Logical, maxKind); |
| 328 | } else { |
| 329 | return std::nullopt; |
| 330 | } |
| 331 | default: |
| 332 | break; |
| 333 | } |
| 334 | return std::nullopt; |
| 335 | } |
Tim Keith | 1f87900 | 2020-03-29 04:00:16 | [diff] [blame] | 336 | } // namespace Fortran::runtime |
| 337 | #endif // FORTRAN_RUNTIME_TOOLS_H_ |