Skip to content

Commit

Permalink
[flang][runtime] Fixed identity value for REAL(16) == __float128.
Browse files Browse the repository at this point in the history
std::numeric_limits<__float128>::max/lowest return 0.0, so recreate
value of FLT128_MAX ourselves to avoid using quadmath.h's FLT128_MAX
that is currently causes warnings with GCC -Wpedantic.

Differential Revision: https://reviews.llvm.org/D134496
  • Loading branch information
vzakhari committed Sep 28, 2022
1 parent b556726 commit 8985cfd
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 1 deletion.
41 changes: 40 additions & 1 deletion flang/runtime/extrema.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,8 @@ void RTNAME(MinlocDim)(Descriptor &result, const Descriptor &x, int kind,

// MAXVAL and MINVAL

template <TypeCategory CAT, int KIND, bool IS_MAXVAL> struct MaxOrMinIdentity {
template <TypeCategory CAT, int KIND, bool IS_MAXVAL, typename Enable = void>
struct MaxOrMinIdentity {
using Type = CppTypeFor<CAT, KIND>;
static constexpr Type Value() {
return IS_MAXVAL ? std::numeric_limits<Type>::lowest()
Expand All @@ -318,6 +319,44 @@ struct MaxOrMinIdentity<TypeCategory::Integer, 16, IS_MAXVAL> {
}
};

#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<TypeCategory::Real, 16> is __float128.
template <bool IS_MAXVAL>
struct MaxOrMinIdentity<TypeCategory::Real, 16, IS_MAXVAL,
typename std::enable_if_t<
std::is_same_v<CppTypeFor<TypeCategory::Real, 16>, __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<Type *>(data) = Type(1.0);
if (*reinterpret_cast<std::uint64_t *>(data) != 0 ||
*(reinterpret_cast<std::uint64_t *>(data) + 1) != 0x3FFF000000000000) {
Terminator terminator{__FILE__, __LINE__};
terminator.Crash("not yet implemented: no full support for __float128");
}

// Recreate FLT128_MAX.
*reinterpret_cast<std::uint64_t *>(data) = 0xFFFFFFFFFFFFFFFF;
*(reinterpret_cast<std::uint64_t *>(data) + 1) = 0x7FFEFFFFFFFFFFFF;
Type max = *reinterpret_cast<Type *>(data);
return IS_MAXVAL ? -max : max;
}
};
#endif // HAS_FLOAT128

template <TypeCategory CAT, int KIND, bool IS_MAXVAL>
class NumericExtremumAccumulator {
public:
Expand Down
17 changes: 17 additions & 0 deletions flang/unittests/Runtime/Reduction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -616,3 +616,20 @@ TEST(Reductions, DotProduct) {
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<TypeCategory::Real, 16>;
std::vector<int> shape{3};
// 1.0 2.0 3.0
std::vector<ElemType> rawMinData{1.0, 2.0, 3.0};
auto minArray{MakeArray<TypeCategory::Real, 16>(shape, rawMinData)};
EXPECT_EQ(RTNAME(MinvalReal16)(*minArray, __FILE__, __LINE__), 1.0);
// -1.0 -2.0 -3.0
std::vector<ElemType> rawMaxData{-1.0, -2.0, -3.0};
auto maxArray{MakeArray<TypeCategory::Real, 16>(shape, rawMaxData)};
EXPECT_EQ(RTNAME(MaxvalReal16)(*maxArray, __FILE__, __LINE__), -1.0);
}
#endif // LDBL_MANT_DIG == 113 || HAS_FLOAT128

0 comments on commit 8985cfd

Please sign in to comment.