Index: flang/cmake/modules/AddFlang.cmake =================================================================== --- flang/cmake/modules/AddFlang.cmake +++ flang/cmake/modules/AddFlang.cmake @@ -1,5 +1,6 @@ include(GNUInstallDirs) include(LLVMDistributionSupport) +include(CheckCXXSourceCompiles) macro(set_flang_windows_version_resource_properties name) if (DEFINED windows_resource_file) @@ -128,3 +129,16 @@ llvm_install_symlink(FLANG ${name} ${dest} ALWAYS_GENERATE) endmacro() +macro(check_f128_funcs) + check_cxx_source_compiles( + "#include + int main() { + __float128 max = ldexpf128(nextafterf128(1.0, 0.0), __FLT128_MAX_EXP__); + return 0; + } + " + HAVE_F128MATH_FUNCS) + if (HAVE_F128MATH_FUNCS) + add_compile_definitions(HAVE_F128MATH_FUNCS=1) + endif() +endmacro() Index: flang/runtime/CMakeLists.txt =================================================================== --- flang/runtime/CMakeLists.txt +++ flang/runtime/CMakeLists.txt @@ -62,6 +62,8 @@ message(FATAL_ERROR "None of strerror, strerror_r, strerror_s found.") endif() +check_f128_funcs() + configure_file(config.h.cmake config.h) # include_directories is used here instead of target_include_directories # because add_flang_library creates multiple objects (STATIC/SHARED, OBJECT) 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,26 @@ } }; +#if HAVE_F128MATH_FUNCS +// std::numeric_limits<> may not support __float128, +// so use macros defined in quadmath.h (if available). +// +// Note that HAVE_QUADMATH_H implies that __float128 is available, +// but it does not necessarily mean that __float128 is used for REAL(16). +// This specialization must engage only when +// CppTypeFor is __float128. +template +struct MaxOrMinIdentity, __float128>>> { + using Type = __float128; + static constexpr Type Value() { + __float128 max = ldexpf128(nextafterf128(1.0, 0.0), __FLT128_MAX_EXP__); + return IS_MAXVAL ? -max : max; + } +}; +#endif // HAVE_F128MATH_FUNCS + template class NumericExtremumAccumulator { public: Index: flang/unittests/Runtime/CMakeLists.txt =================================================================== --- flang/unittests/Runtime/CMakeLists.txt +++ flang/unittests/Runtime/CMakeLists.txt @@ -1,3 +1,5 @@ +check_f128_funcs() + add_flang_unittest(FlangRuntimeTests BufferTest.cpp CharacterTest.cpp 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 && HAVE_F128MATH_FUNCS) +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 && HAVE_F128MATH_FUNCS)