1 //===-- runtime/extrema.cpp -----------------------------------------------===// 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 // Implements MAXLOC, MINLOC, MAXVAL, & MINVAL for all required operand types 10 // and shapes and (for MAXLOC & MINLOC) result integer kinds. 11 12 #include "character.h" 13 #include "reduction-templates.h" 14 #include "reduction.h" 15 #include "flang/Common/long-double.h" 16 #include <cinttypes> 17 18 namespace Fortran::runtime { 19 // MAXLOC & MINLOC 20 21 template <typename T, bool IS_MAX, bool BACK> struct NumericCompare { 22 using Type = T; 23 explicit NumericCompare(std::size_t /*elemLen; ignored*/) {} 24 bool operator()(const T &value, const T &previous) const { 25 if (value == previous) { 26 return BACK; 27 } else if constexpr (IS_MAX) { 28 return value > previous; 29 } else { 30 return value < previous; 31 } 32 } 33 }; 34 35 template <typename T, bool IS_MAX, bool BACK> class CharacterCompare { 36 public: 37 using Type = T; 38 explicit CharacterCompare(std::size_t elemLen) 39 : chars_{elemLen / sizeof(T)} {} 40 bool operator()(const T &value, const T &previous) const { 41 int cmp{CharacterScalarCompare<T>(&value, &previous, chars_, chars_)}; 42 if (cmp == 0) { 43 return BACK; 44 } else if constexpr (IS_MAX) { 45 return cmp > 0; 46 } else { 47 return cmp < 0; 48 } 49 } 50 51 private: 52 std::size_t chars_; 53 }; 54 55 template <typename COMPARE> class ExtremumLocAccumulator { 56 public: 57 using Type = typename COMPARE::Type; 58 ExtremumLocAccumulator(const Descriptor &array, std::size_t chars = 0) 59 : array_{array}, argRank_{array.rank()}, compare_{array.ElementBytes()} { 60 Reinitialize(); 61 } 62 void Reinitialize() { 63 // per standard: result indices are all zero if no data 64 for (int j{0}; j < argRank_; ++j) { 65 extremumLoc_[j] = 0; 66 } 67 previous_ = nullptr; 68 } 69 int argRank() const { return argRank_; } 70 template <typename A> void GetResult(A *p, int zeroBasedDim = -1) { 71 if (zeroBasedDim >= 0) { 72 *p = extremumLoc_[zeroBasedDim] - 73 array_.GetDimension(zeroBasedDim).LowerBound() + 1; 74 } else { 75 for (int j{0}; j < argRank_; ++j) { 76 p[j] = extremumLoc_[j] - array_.GetDimension(j).LowerBound() + 1; 77 } 78 } 79 } 80 template <typename IGNORED> bool AccumulateAt(const SubscriptValue at[]) { 81 const auto &value{*array_.Element<Type>(at)}; 82 if (!previous_ || compare_(value, *previous_)) { 83 previous_ = &value; 84 for (int j{0}; j < argRank_; ++j) { 85 extremumLoc_[j] = at[j]; 86 } 87 } 88 return true; 89 } 90 91 private: 92 const Descriptor &array_; 93 int argRank_; 94 SubscriptValue extremumLoc_[maxRank]; 95 const Type *previous_{nullptr}; 96 COMPARE compare_; 97 }; 98 99 template <typename ACCUMULATOR, typename CPPTYPE> 100 static void LocationHelper(const char *intrinsic, Descriptor &result, 101 const Descriptor &x, int kind, const Descriptor *mask, 102 Terminator &terminator) { 103 ACCUMULATOR accumulator{x}; 104 DoTotalReduction<CPPTYPE>(x, 0, mask, accumulator, intrinsic, terminator); 105 ApplyIntegerKind<LocationResultHelper<ACCUMULATOR>::template Functor, void>( 106 kind, terminator, accumulator, result); 107 } 108 109 template <TypeCategory CAT, int KIND, bool IS_MAX, 110 template <typename, bool, bool> class COMPARE> 111 inline void DoMaxOrMinLoc(const char *intrinsic, Descriptor &result, 112 const Descriptor &x, int kind, const char *source, int line, 113 const Descriptor *mask, bool back) { 114 using CppType = CppTypeFor<CAT, KIND>; 115 Terminator terminator{source, line}; 116 if (back) { 117 LocationHelper<ExtremumLocAccumulator<COMPARE<CppType, IS_MAX, true>>, 118 CppType>(intrinsic, result, x, kind, mask, terminator); 119 } else { 120 LocationHelper<ExtremumLocAccumulator<COMPARE<CppType, IS_MAX, false>>, 121 CppType>(intrinsic, result, x, kind, mask, terminator); 122 } 123 } 124 125 template <TypeCategory CAT, bool IS_MAX> struct TypedMaxOrMinLocHelper { 126 template <int KIND> struct Functor { 127 void operator()(const char *intrinsic, Descriptor &result, 128 const Descriptor &x, int kind, const char *source, int line, 129 const Descriptor *mask, bool back) const { 130 DoMaxOrMinLoc<TypeCategory::Integer, KIND, IS_MAX, NumericCompare>( 131 intrinsic, result, x, kind, source, line, mask, back); 132 } 133 }; 134 }; 135 136 template <bool IS_MAX> 137 inline void TypedMaxOrMinLoc(const char *intrinsic, Descriptor &result, 138 const Descriptor &x, int kind, const char *source, int line, 139 const Descriptor *mask, bool back) { 140 int rank{x.rank()}; 141 SubscriptValue extent[1]{rank}; 142 result.Establish(TypeCategory::Integer, kind, nullptr, 1, extent, 143 CFI_attribute_allocatable); 144 result.GetDimension(0).SetBounds(1, extent[0]); 145 Terminator terminator{source, line}; 146 if (int stat{result.Allocate()}) { 147 terminator.Crash( 148 "%s: could not allocate memory for result; STAT=%d", intrinsic, stat); 149 } 150 CheckIntegerKind(terminator, kind, intrinsic); 151 auto catKind{x.type().GetCategoryAndKind()}; 152 RUNTIME_CHECK(terminator, catKind.has_value()); 153 switch (catKind->first) { 154 case TypeCategory::Integer: 155 ApplyIntegerKind< 156 TypedMaxOrMinLocHelper<TypeCategory::Integer, IS_MAX>::template Functor, 157 void>(catKind->second, terminator, intrinsic, result, x, kind, source, 158 line, mask, back); 159 break; 160 case TypeCategory::Real: 161 ApplyFloatingPointKind< 162 TypedMaxOrMinLocHelper<TypeCategory::Real, IS_MAX>::template Functor, 163 void>(catKind->second, terminator, intrinsic, result, x, kind, source, 164 line, mask, back); 165 break; 166 case TypeCategory::Character: 167 ApplyCharacterKind<TypedMaxOrMinLocHelper<TypeCategory::Character, 168 IS_MAX>::template Functor, 169 void>(catKind->second, terminator, intrinsic, result, x, kind, source, 170 line, mask, back); 171 break; 172 default: 173 terminator.Crash( 174 "%s: Bad data type code (%d) for array", intrinsic, x.type().raw()); 175 } 176 } 177 178 extern "C" { 179 void RTNAME(Maxloc)(Descriptor &result, const Descriptor &x, int kind, 180 const char *source, int line, const Descriptor *mask, bool back) { 181 TypedMaxOrMinLoc<true>("MAXLOC", result, x, kind, source, line, mask, back); 182 } 183 void RTNAME(Minloc)(Descriptor &result, const Descriptor &x, int kind, 184 const char *source, int line, const Descriptor *mask, bool back) { 185 TypedMaxOrMinLoc<false>("MINLOC", result, x, kind, source, line, mask, back); 186 } 187 } // extern "C" 188 189 // MAXLOC/MINLOC with DIM= 190 191 template <TypeCategory CAT, int KIND, bool IS_MAX, 192 template <typename, bool, bool> class COMPARE, bool BACK> 193 static void DoPartialMaxOrMinLocDirection(const char *intrinsic, 194 Descriptor &result, const Descriptor &x, int kind, int dim, 195 const Descriptor *mask, Terminator &terminator) { 196 using CppType = CppTypeFor<CAT, KIND>; 197 using Accumulator = ExtremumLocAccumulator<COMPARE<CppType, IS_MAX, BACK>>; 198 Accumulator accumulator{x}; 199 ApplyIntegerKind<PartialLocationHelper<Accumulator>::template Functor, void>( 200 kind, terminator, result, x, dim, mask, terminator, intrinsic, 201 accumulator); 202 } 203 204 template <TypeCategory CAT, int KIND, bool IS_MAX, 205 template <typename, bool, bool> class COMPARE> 206 inline void DoPartialMaxOrMinLoc(const char *intrinsic, Descriptor &result, 207 const Descriptor &x, int kind, int dim, const Descriptor *mask, bool back, 208 Terminator &terminator) { 209 if (back) { 210 DoPartialMaxOrMinLocDirection<CAT, KIND, IS_MAX, COMPARE, true>( 211 intrinsic, result, x, kind, dim, mask, terminator); 212 } else { 213 DoPartialMaxOrMinLocDirection<CAT, KIND, IS_MAX, COMPARE, false>( 214 intrinsic, result, x, kind, dim, mask, terminator); 215 } 216 } 217 218 template <TypeCategory CAT, bool IS_MAX, 219 template <typename, bool, bool> class COMPARE> 220 struct DoPartialMaxOrMinLocHelper { 221 template <int KIND> struct Functor { 222 void operator()(const char *intrinsic, Descriptor &result, 223 const Descriptor &x, int kind, int dim, const Descriptor *mask, 224 bool back, Terminator &terminator) const { 225 DoPartialMaxOrMinLoc<CAT, KIND, IS_MAX, COMPARE>( 226 intrinsic, result, x, kind, dim, mask, back, terminator); 227 } 228 }; 229 }; 230 231 template <bool IS_MAX> 232 inline void TypedPartialMaxOrMinLoc(const char *intrinsic, Descriptor &result, 233 const Descriptor &x, int kind, int dim, const char *source, int line, 234 const Descriptor *mask, bool back) { 235 Terminator terminator{source, line}; 236 CheckIntegerKind(terminator, kind, intrinsic); 237 auto catKind{x.type().GetCategoryAndKind()}; 238 RUNTIME_CHECK(terminator, catKind.has_value()); 239 switch (catKind->first) { 240 case TypeCategory::Integer: 241 ApplyIntegerKind<DoPartialMaxOrMinLocHelper<TypeCategory::Integer, IS_MAX, 242 NumericCompare>::template Functor, 243 void>(catKind->second, terminator, intrinsic, result, x, kind, dim, 244 mask, back, terminator); 245 break; 246 case TypeCategory::Real: 247 ApplyFloatingPointKind<DoPartialMaxOrMinLocHelper<TypeCategory::Real, 248 IS_MAX, NumericCompare>::template Functor, 249 void>(catKind->second, terminator, intrinsic, result, x, kind, dim, 250 mask, back, terminator); 251 break; 252 case TypeCategory::Character: 253 ApplyCharacterKind<DoPartialMaxOrMinLocHelper<TypeCategory::Character, 254 IS_MAX, CharacterCompare>::template Functor, 255 void>(catKind->second, terminator, intrinsic, result, x, kind, dim, 256 mask, back, terminator); 257 break; 258 default: 259 terminator.Crash( 260 "%s: Bad data type code (%d) for array", intrinsic, x.type().raw()); 261 } 262 } 263 264 extern "C" { 265 void RTNAME(MaxlocDim)(Descriptor &result, const Descriptor &x, int kind, 266 int dim, const char *source, int line, const Descriptor *mask, bool back) { 267 TypedPartialMaxOrMinLoc<true>( 268 "MAXLOC", result, x, kind, dim, source, line, mask, back); 269 } 270 void RTNAME(MinlocDim)(Descriptor &result, const Descriptor &x, int kind, 271 int dim, const char *source, int line, const Descriptor *mask, bool back) { 272 TypedPartialMaxOrMinLoc<false>( 273 "MINLOC", result, x, kind, dim, source, line, mask, back); 274 } 275 } // extern "C" 276 277 // MAXVAL and MINVAL 278 279 template <TypeCategory CAT, int KIND, bool IS_MAXVAL> struct MaxOrMinIdentity { 280 using Type = CppTypeFor<CAT, KIND>; 281 static constexpr Type Value() { 282 return IS_MAXVAL ? std::numeric_limits<Type>::lowest() 283 : std::numeric_limits<Type>::max(); 284 } 285 }; 286 287 // std::numeric_limits<> may not know int128_t 288 template <bool IS_MAXVAL> 289 struct MaxOrMinIdentity<TypeCategory::Integer, 16, IS_MAXVAL> { 290 using Type = CppTypeFor<TypeCategory::Integer, 16>; 291 static constexpr Type Value() { 292 return IS_MAXVAL ? Type{1} << 127 : ~Type{0} >> 1; 293 } 294 }; 295 296 template <TypeCategory CAT, int KIND, bool IS_MAXVAL> 297 class NumericExtremumAccumulator { 298 public: 299 using Type = CppTypeFor<CAT, KIND>; 300 explicit NumericExtremumAccumulator(const Descriptor &array) 301 : array_{array} {} 302 void Reinitialize() { 303 extremum_ = MaxOrMinIdentity<CAT, KIND, IS_MAXVAL>::Value(); 304 } 305 template <typename A> void GetResult(A *p, int /*zeroBasedDim*/ = -1) const { 306 *p = extremum_; 307 } 308 bool Accumulate(Type x) { 309 if constexpr (IS_MAXVAL) { 310 if (x > extremum_) { 311 extremum_ = x; 312 } 313 } else if (x < extremum_) { 314 extremum_ = x; 315 } 316 return true; 317 } 318 template <typename A> bool AccumulateAt(const SubscriptValue at[]) { 319 return Accumulate(*array_.Element<A>(at)); 320 } 321 322 private: 323 const Descriptor &array_; 324 Type extremum_{MaxOrMinIdentity<CAT, KIND, IS_MAXVAL>::Value()}; 325 }; 326 327 template <TypeCategory CAT, int KIND, bool IS_MAXVAL> 328 inline CppTypeFor<CAT, KIND> TotalNumericMaxOrMin(const Descriptor &x, 329 const char *source, int line, int dim, const Descriptor *mask, 330 const char *intrinsic) { 331 return GetTotalReduction<CAT, KIND>(x, source, line, dim, mask, 332 NumericExtremumAccumulator<CAT, KIND, IS_MAXVAL>{x}, intrinsic); 333 } 334 335 template <TypeCategory CAT, int KIND, bool IS_MAXVAL, 336 template <TypeCategory, int, bool> class ACCUMULATOR> 337 static void DoMaxOrMin(Descriptor &result, const Descriptor &x, int dim, 338 const Descriptor *mask, const char *intrinsic, Terminator &terminator) { 339 using Type = CppTypeFor<CAT, KIND>; 340 if (dim == 0 || x.rank() == 1) { 341 // Total reduction 342 result.Establish(x.type(), x.ElementBytes(), nullptr, 0, nullptr, 343 CFI_attribute_allocatable); 344 if (int stat{result.Allocate()}) { 345 terminator.Crash( 346 "%s: could not allocate memory for result; STAT=%d", intrinsic, stat); 347 } 348 ACCUMULATOR<CAT, KIND, IS_MAXVAL> accumulator{x}; 349 DoTotalReduction<Type>(x, dim, mask, accumulator, intrinsic, terminator); 350 accumulator.GetResult(result.OffsetElement<Type>()); 351 } else { 352 // Partial reduction 353 using Accumulator = ACCUMULATOR<CAT, KIND, IS_MAXVAL>; 354 Accumulator accumulator{x}; 355 PartialReduction<Accumulator, CAT, KIND>( 356 result, x, dim, mask, terminator, intrinsic, accumulator); 357 } 358 } 359 360 template <TypeCategory CAT, bool IS_MAXVAL> struct MaxOrMinHelper { 361 template <int KIND> struct Functor { 362 void operator()(Descriptor &result, const Descriptor &x, int dim, 363 const Descriptor *mask, const char *intrinsic, 364 Terminator &terminator) const { 365 DoMaxOrMin<CAT, KIND, IS_MAXVAL, NumericExtremumAccumulator>( 366 result, x, dim, mask, intrinsic, terminator); 367 } 368 }; 369 }; 370 371 template <bool IS_MAXVAL> 372 inline void NumericMaxOrMin(Descriptor &result, const Descriptor &x, int dim, 373 const char *source, int line, const Descriptor *mask, 374 const char *intrinsic) { 375 Terminator terminator{source, line}; 376 auto type{x.type().GetCategoryAndKind()}; 377 RUNTIME_CHECK(terminator, type); 378 switch (type->first) { 379 case TypeCategory::Integer: 380 ApplyIntegerKind< 381 MaxOrMinHelper<TypeCategory::Integer, IS_MAXVAL>::template Functor, 382 void>( 383 type->second, terminator, result, x, dim, mask, intrinsic, terminator); 384 break; 385 case TypeCategory::Real: 386 ApplyFloatingPointKind< 387 MaxOrMinHelper<TypeCategory::Real, IS_MAXVAL>::template Functor, void>( 388 type->second, terminator, result, x, dim, mask, intrinsic, terminator); 389 break; 390 default: 391 terminator.Crash("%s: bad type code %d", intrinsic, x.type().raw()); 392 } 393 } 394 395 template <TypeCategory, int KIND, bool IS_MAXVAL> 396 class CharacterExtremumAccumulator { 397 public: 398 using Type = CppTypeFor<TypeCategory::Character, KIND>; 399 explicit CharacterExtremumAccumulator(const Descriptor &array) 400 : array_{array}, charLen_{array_.ElementBytes() / KIND} {} 401 void Reinitialize() { extremum_ = nullptr; } 402 template <typename A> void GetResult(A *p, int /*zeroBasedDim*/ = -1) const { 403 static_assert(std::is_same_v<A, Type>); 404 if (extremum_) { 405 std::memcpy(p, extremum_, charLen_); 406 } else { 407 // empty array: result is all zero-valued characters 408 std::memset(p, 0, charLen_); 409 } 410 } 411 bool Accumulate(const Type *x) { 412 if (!extremum_) { 413 extremum_ = x; 414 } else { 415 int cmp{CharacterScalarCompare(x, extremum_, charLen_, charLen_)}; 416 if (IS_MAXVAL == (cmp > 0)) { 417 extremum_ = x; 418 } 419 } 420 return true; 421 } 422 template <typename A> bool AccumulateAt(const SubscriptValue at[]) { 423 return Accumulate(array_.Element<A>(at)); 424 } 425 426 private: 427 const Descriptor &array_; 428 std::size_t charLen_; 429 const Type *extremum_{nullptr}; 430 }; 431 432 template <bool IS_MAXVAL> struct CharacterMaxOrMinHelper { 433 template <int KIND> struct Functor { 434 void operator()(Descriptor &result, const Descriptor &x, int dim, 435 const Descriptor *mask, const char *intrinsic, 436 Terminator &terminator) const { 437 DoMaxOrMin<TypeCategory::Character, KIND, IS_MAXVAL, 438 CharacterExtremumAccumulator>( 439 result, x, dim, mask, intrinsic, terminator); 440 } 441 }; 442 }; 443 444 template <bool IS_MAXVAL> 445 inline void CharacterMaxOrMin(Descriptor &result, const Descriptor &x, int dim, 446 const char *source, int line, const Descriptor *mask, 447 const char *intrinsic) { 448 Terminator terminator{source, line}; 449 auto type{x.type().GetCategoryAndKind()}; 450 RUNTIME_CHECK(terminator, type && type->first == TypeCategory::Character); 451 ApplyCharacterKind<CharacterMaxOrMinHelper<IS_MAXVAL>::template Functor, 452 void>( 453 type->second, terminator, result, x, dim, mask, intrinsic, terminator); 454 } 455 456 extern "C" { 457 CppTypeFor<TypeCategory::Integer, 1> RTNAME(MaxvalInteger1)(const Descriptor &x, 458 const char *source, int line, int dim, const Descriptor *mask) { 459 return TotalNumericMaxOrMin<TypeCategory::Integer, 1, true>( 460 x, source, line, dim, mask, "MAXVAL"); 461 } 462 CppTypeFor<TypeCategory::Integer, 2> RTNAME(MaxvalInteger2)(const Descriptor &x, 463 const char *source, int line, int dim, const Descriptor *mask) { 464 return TotalNumericMaxOrMin<TypeCategory::Integer, 2, true>( 465 x, source, line, dim, mask, "MAXVAL"); 466 } 467 CppTypeFor<TypeCategory::Integer, 4> RTNAME(MaxvalInteger4)(const Descriptor &x, 468 const char *source, int line, int dim, const Descriptor *mask) { 469 return TotalNumericMaxOrMin<TypeCategory::Integer, 4, true>( 470 x, source, line, dim, mask, "MAXVAL"); 471 } 472 CppTypeFor<TypeCategory::Integer, 8> RTNAME(MaxvalInteger8)(const Descriptor &x, 473 const char *source, int line, int dim, const Descriptor *mask) { 474 return TotalNumericMaxOrMin<TypeCategory::Integer, 8, true>( 475 x, source, line, dim, mask, "MAXVAL"); 476 } 477 #ifdef __SIZEOF_INT128__ 478 CppTypeFor<TypeCategory::Integer, 16> RTNAME(MaxvalInteger16)( 479 const Descriptor &x, const char *source, int line, int dim, 480 const Descriptor *mask) { 481 return TotalNumericMaxOrMin<TypeCategory::Integer, 16, true>( 482 x, source, line, dim, mask, "MAXVAL"); 483 } 484 #endif 485 486 // TODO: REAL(2 & 3) 487 CppTypeFor<TypeCategory::Real, 4> RTNAME(MaxvalReal4)(const Descriptor &x, 488 const char *source, int line, int dim, const Descriptor *mask) { 489 return TotalNumericMaxOrMin<TypeCategory::Real, 4, true>( 490 x, source, line, dim, mask, "MAXVAL"); 491 } 492 CppTypeFor<TypeCategory::Real, 8> RTNAME(MaxvalReal8)(const Descriptor &x, 493 const char *source, int line, int dim, const Descriptor *mask) { 494 return TotalNumericMaxOrMin<TypeCategory::Real, 8, true>( 495 x, source, line, dim, mask, "MAXVAL"); 496 } 497 #if LONG_DOUBLE == 80 498 CppTypeFor<TypeCategory::Real, 10> RTNAME(MaxvalReal10)(const Descriptor &x, 499 const char *source, int line, int dim, const Descriptor *mask) { 500 return TotalNumericMaxOrMin<TypeCategory::Real, 10, true>( 501 x, source, line, dim, mask, "MAXVAL"); 502 } 503 #elif LONG_DOUBLE == 128 504 CppTypeFor<TypeCategory::Real, 16> RTNAME(MaxvalReal16)(const Descriptor &x, 505 const char *source, int line, int dim, const Descriptor *mask) { 506 return TotalNumericMaxOrMin<TypeCategory::Real, 16, true>( 507 x, source, line, dim, mask, "MAXVAL"); 508 } 509 #endif 510 511 void RTNAME(MaxvalCharacter)(Descriptor &result, const Descriptor &x, 512 const char *source, int line, const Descriptor *mask) { 513 CharacterMaxOrMin<true>(result, x, 0, source, line, mask, "MAXVAL"); 514 } 515 516 CppTypeFor<TypeCategory::Integer, 1> RTNAME(MinvalInteger1)(const Descriptor &x, 517 const char *source, int line, int dim, const Descriptor *mask) { 518 return TotalNumericMaxOrMin<TypeCategory::Integer, 1, false>( 519 x, source, line, dim, mask, "MINVAL"); 520 } 521 CppTypeFor<TypeCategory::Integer, 2> RTNAME(MinvalInteger2)(const Descriptor &x, 522 const char *source, int line, int dim, const Descriptor *mask) { 523 return TotalNumericMaxOrMin<TypeCategory::Integer, 2, false>( 524 x, source, line, dim, mask, "MINVAL"); 525 } 526 CppTypeFor<TypeCategory::Integer, 4> RTNAME(MinvalInteger4)(const Descriptor &x, 527 const char *source, int line, int dim, const Descriptor *mask) { 528 return TotalNumericMaxOrMin<TypeCategory::Integer, 4, false>( 529 x, source, line, dim, mask, "MINVAL"); 530 } 531 CppTypeFor<TypeCategory::Integer, 8> RTNAME(MinvalInteger8)(const Descriptor &x, 532 const char *source, int line, int dim, const Descriptor *mask) { 533 return TotalNumericMaxOrMin<TypeCategory::Integer, 8, false>( 534 x, source, line, dim, mask, "MINVAL"); 535 } 536 #ifdef __SIZEOF_INT128__ 537 CppTypeFor<TypeCategory::Integer, 16> RTNAME(MinvalInteger16)( 538 const Descriptor &x, const char *source, int line, int dim, 539 const Descriptor *mask) { 540 return TotalNumericMaxOrMin<TypeCategory::Integer, 16, false>( 541 x, source, line, dim, mask, "MINVAL"); 542 } 543 #endif 544 545 // TODO: REAL(2 & 3) 546 CppTypeFor<TypeCategory::Real, 4> RTNAME(MinvalReal4)(const Descriptor &x, 547 const char *source, int line, int dim, const Descriptor *mask) { 548 return TotalNumericMaxOrMin<TypeCategory::Real, 4, false>( 549 x, source, line, dim, mask, "MINVAL"); 550 } 551 CppTypeFor<TypeCategory::Real, 8> RTNAME(MinvalReal8)(const Descriptor &x, 552 const char *source, int line, int dim, const Descriptor *mask) { 553 return TotalNumericMaxOrMin<TypeCategory::Real, 8, false>( 554 x, source, line, dim, mask, "MINVAL"); 555 } 556 #if LONG_DOUBLE == 80 557 CppTypeFor<TypeCategory::Real, 10> RTNAME(MinvalReal10)(const Descriptor &x, 558 const char *source, int line, int dim, const Descriptor *mask) { 559 return TotalNumericMaxOrMin<TypeCategory::Real, 10, false>( 560 x, source, line, dim, mask, "MINVAL"); 561 } 562 #elif LONG_DOUBLE == 128 563 CppTypeFor<TypeCategory::Real, 16> RTNAME(MinvalReal16)(const Descriptor &x, 564 const char *source, int line, int dim, const Descriptor *mask) { 565 return TotalNumericMaxOrMin<TypeCategory::Real, 16, false>( 566 x, source, line, dim, mask, "MINVAL"); 567 } 568 #endif 569 570 void RTNAME(MinvalCharacter)(Descriptor &result, const Descriptor &x, 571 const char *source, int line, const Descriptor *mask) { 572 CharacterMaxOrMin<false>(result, x, 0, source, line, mask, "MINVAL"); 573 } 574 575 void RTNAME(MaxvalDim)(Descriptor &result, const Descriptor &x, int dim, 576 const char *source, int line, const Descriptor *mask) { 577 if (x.type().IsCharacter()) { 578 CharacterMaxOrMin<true>(result, x, dim, source, line, mask, "MAXVAL"); 579 } else { 580 NumericMaxOrMin<true>(result, x, dim, source, line, mask, "MAXVAL"); 581 } 582 } 583 void RTNAME(MinvalDim)(Descriptor &result, const Descriptor &x, int dim, 584 const char *source, int line, const Descriptor *mask) { 585 if (x.type().IsCharacter()) { 586 CharacterMaxOrMin<false>(result, x, dim, source, line, mask, "MINVAL"); 587 } else { 588 NumericMaxOrMin<false>(result, x, dim, source, line, mask, "MINVAL"); 589 } 590 } 591 } // extern "C" 592 } // namespace Fortran::runtime 593