Skip to content

Commit 2aad6a0

Browse files
committed
[flang][msvc] Avoid a reinterpret_cast
The call to the binary->decimal formatter in real.cpp was cheating by using a reinterpret_cast<> to extract its binary value. Use a more principled and portable approach by extending the API of evaluate::Integer<> to include ToUInt<>()/ToSInt<>() member function templates that do the "right" thing. Retain ToUInt64()/ToSInt64() for compatibility. Differential revision: https://reviews.llvm.org/D89435
1 parent cf6fd40 commit 2aad6a0

File tree

2 files changed

+23
-13
lines changed

2 files changed

+23
-13
lines changed

flang/include/flang/Evaluate/integer.h

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -462,21 +462,30 @@ class Integer {
462462
return CompareUnsigned(y);
463463
}
464464

465-
constexpr std::uint64_t ToUInt64() const {
466-
std::uint64_t n{LEPart(0)};
467-
int filled{partBits};
468-
for (int j{1}; filled < 64 && j < parts; ++j, filled += partBits) {
469-
n |= std::uint64_t{LEPart(j)} << filled;
465+
template <typename UINT = std::uint64_t> constexpr UINT ToUInt() const {
466+
UINT n{LEPart(0)};
467+
std::size_t filled{partBits};
468+
constexpr std::size_t maxBits{CHAR_BIT * sizeof n};
469+
for (int j{1}; filled < maxBits && j < parts; ++j, filled += partBits) {
470+
n |= UINT{LEPart(j)} << filled;
470471
}
471472
return n;
472473
}
473474

474-
constexpr std::int64_t ToInt64() const {
475-
std::int64_t signExtended = ToUInt64();
476-
if constexpr (bits < 64) {
477-
signExtended |= -(signExtended >> (bits - 1)) << bits;
475+
template <typename SINT = std::int64_t, typename UINT = std::uint64_t>
476+
constexpr SINT ToSInt() const {
477+
SINT n = ToUInt<UINT>();
478+
constexpr std::size_t maxBits{CHAR_BIT * sizeof n};
479+
if constexpr (bits < maxBits) {
480+
n |= -(n >> (bits - 1)) << bits;
478481
}
479-
return signExtended;
482+
return n;
483+
}
484+
485+
constexpr std::uint64_t ToUInt64() const { return ToUInt<std::uint64_t>(); }
486+
487+
constexpr std::int64_t ToInt64() const {
488+
return ToSInt<std::int64_t, std::uint64_t>();
480489
}
481490

482491
// Ones'-complement (i.e., C's ~)

flang/lib/Evaluate/real.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -496,14 +496,15 @@ llvm::raw_ostream &Real<W, P>::AsFortran(
496496
}
497497
} else {
498498
using B = decimal::BinaryFloatingPointNumber<P>;
499-
const auto *value{reinterpret_cast<const B *>(this)};
500-
char buffer[24000]; // accommodate real*16
499+
B value{word_.template ToUInt<typename B::RawType>()};
500+
char buffer[common::MaxDecimalConversionDigits(P) +
501+
EXTRA_DECIMAL_CONVERSION_SPACE];
501502
decimal::DecimalConversionFlags flags{}; // default: exact representation
502503
if (minimal) {
503504
flags = decimal::Minimize;
504505
}
505506
auto result{decimal::ConvertToDecimal<P>(buffer, sizeof buffer, flags,
506-
static_cast<int>(sizeof buffer), decimal::RoundNearest, *value)};
507+
static_cast<int>(sizeof buffer), decimal::RoundNearest, value)};
507508
const char *p{result.str};
508509
if (DEREF(p) == '-' || *p == '+') {
509510
o << *p++;

0 commit comments

Comments
 (0)