Index: flang/runtime/extrema.cpp =================================================================== --- flang/runtime/extrema.cpp +++ flang/runtime/extrema.cpp @@ -301,7 +301,8 @@ // MAXVAL and MINVAL -template struct MaxOrMinIdentity { +template +struct MaxOrMinIdentity { using Type = CppTypeFor; static constexpr Type Value() { return IS_MAXVAL ? std::numeric_limits::lowest() @@ -318,6 +319,44 @@ } }; +#if HAS_FLOAT128 +// std::numeric_limits<> may not support __float128. +// +// Usage of GCC quadmath.h's FLT128_MAX is complicated by the fact that +// even GCC complains about 'Q' literal suffix under -Wpedantic. +// We just recreate FLT128_MAX ourselves. +// +// This specialization must engage only when +// CppTypeFor is __float128. +template +struct MaxOrMinIdentity, __float128>>> { + using Type = __float128; + static Type Value() { + // Create a buffer to store binary representation of __float128 constant. + constexpr std::size_t alignment = + std::max(alignof(Type), alignof(std::uint64_t)); + alignas(alignment) char data[sizeof(Type)]; + + // First, verify that our interpretation of __float128 format is correct, + // e.g. by checking at least one known constant. + *reinterpret_cast(data) = Type(1.0); + if (*reinterpret_cast(data) != 0 || + *(reinterpret_cast(data) + 1) != 0x3FFF000000000000) { + Terminator terminator{__FILE__, __LINE__}; + terminator.Crash("not yet implemented: no full support for __float128"); + } + + // Recreate FLT128_MAX. + *reinterpret_cast(data) = 0xFFFFFFFFFFFFFFFF; + *(reinterpret_cast(data) + 1) = 0x7FFEFFFFFFFFFFFF; + Type max = *reinterpret_cast(data); + return IS_MAXVAL ? -max : max; + } +}; +#endif // HAS_FLOAT128 + template class NumericExtremumAccumulator { public: Index: flang/unittests/Runtime/Reduction.cpp =================================================================== --- flang/unittests/Runtime/Reduction.cpp +++ flang/unittests/Runtime/Reduction.cpp @@ -616,3 +616,20 @@ EXPECT_FALSE(RTNAME(DotProductLogical)( *logicalVector2, *logicalVector1, __FILE__, __LINE__)); } + +#if LDBL_MANT_DIG == 113 || HAS_FLOAT128 +TEST(Reductions, ExtremaReal16) { + // The identity value for Min/Maxval for REAL(16) was mistakenly + // set to 0.0. + using ElemType = CppTypeFor; + std::vector shape{3}; + // 1.0 2.0 3.0 + std::vector rawMinData{1.0, 2.0, 3.0}; + auto minArray{MakeArray(shape, rawMinData)}; + EXPECT_EQ(RTNAME(MinvalReal16)(*minArray, __FILE__, __LINE__), 1.0); + // -1.0 -2.0 -3.0 + std::vector rawMaxData{-1.0, -2.0, -3.0}; + auto maxArray{MakeArray(shape, rawMaxData)}; + EXPECT_EQ(RTNAME(MaxvalReal16)(*maxArray, __FILE__, __LINE__), -1.0); +} +#endif // LDBL_MANT_DIG == 113 || HAS_FLOAT128