From 5cf39383da201784a40eb47cfd289cbe98972145 Mon Sep 17 00:00:00 2001 From: "Duncan P. N. Exon Smith" Date: Fri, 20 Jun 2014 02:31:03 +0000 Subject: [PATCH] Support: Write ScaledNumbers::getAdjusted() git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@211336 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/Analysis/BlockFrequencyInfoImpl.h | 24 ++++++++---------- include/llvm/Support/ScaledNumber.h | 35 ++++++++++++++++++++++++++ unittests/Support/ScaledNumberTest.cpp | 23 +++++++++++++++++ 3 files changed, 68 insertions(+), 14 deletions(-) diff --git a/include/llvm/Analysis/BlockFrequencyInfoImpl.h b/include/llvm/Analysis/BlockFrequencyInfoImpl.h index 7ad76e5350e..264aff37258 100644 --- a/include/llvm/Analysis/BlockFrequencyInfoImpl.h +++ b/include/llvm/Analysis/BlockFrequencyInfoImpl.h @@ -327,20 +327,16 @@ private: return countLeadingZeros32(Digits) + Width - 32; } - static UnsignedFloat adjustToWidth(uint64_t N, int32_t S) { - assert(S >= MinExponent); - assert(S <= MaxExponent); - if (Width == 64 || N <= DigitsLimits::max()) - return UnsignedFloat(N, S); - - // Shift right. - int Shift = 64 - Width - countLeadingZeros64(N); - DigitsType Shifted = N >> Shift; - - // Round. - assert(S + Shift <= MaxExponent); - return getRounded(UnsignedFloat(Shifted, S + Shift), - N & UINT64_C(1) << (Shift - 1)); + /// \brief Adjust a number to width, rounding up if necessary. + /// + /// Should only be called for \c Shift close to zero. + /// + /// \pre Shift >= MinExponent && Shift + 64 <= MaxExponent. + static UnsignedFloat adjustToWidth(uint64_t N, int32_t Shift) { + assert(Shift >= MinExponent && "Shift should be close to 0"); + assert(Shift <= MaxExponent - 64 && "Shift should be close to 0"); + auto Adjusted = ScaledNumbers::getAdjusted(N, Shift); + return Adjusted; } static UnsignedFloat getRounded(UnsignedFloat P, bool Round) { diff --git a/include/llvm/Support/ScaledNumber.h b/include/llvm/Support/ScaledNumber.h index afdc7dc1888..54b5386c5ac 100644 --- a/include/llvm/Support/ScaledNumber.h +++ b/include/llvm/Support/ScaledNumber.h @@ -22,6 +22,8 @@ #ifndef LLVM_SUPPORT_SCALEDNUMBER_H #define LLVM_SUPPORT_SCALEDNUMBER_H +#include "llvm/Support/MathExtras.h" + #include #include #include @@ -50,6 +52,39 @@ inline std::pair getRounded(DigitsT Digits, int16_t Scale, return std::make_pair(DigitsT(1) << (getWidth() - 1), Scale + 1); return std::make_pair(Digits, Scale); } + +/// \brief Adjust a 64-bit scaled number down to the appropriate width. +/// +/// Adjust a soft float with 64-bits of digits down, keeping as much +/// information as possible, and rounding up on half. +/// +/// \pre Adding 1 to \c Scale will not overflow INT16_MAX. +template +inline std::pair getAdjusted(uint64_t Digits, + int16_t Scale = 0) { + static_assert(!std::numeric_limits::is_signed, "expected unsigned"); + + const int Width = getWidth(); + if (Width == 64 || Digits <= std::numeric_limits::max()) + return std::make_pair(Digits, Scale); + + // Shift right and round. + int Shift = 64 - Width - countLeadingZeros(Digits); + return getRounded(Digits >> Shift, Scale + Shift, + Digits & (UINT64_C(1) << (Shift - 1))); +} + +/// \brief Convenience helper for adjusting to 32 bits. +inline std::pair getAdjusted32(uint64_t Digits, + int16_t Scale = 0) { + return getAdjusted(Digits, Scale); +} + +/// \brief Convenience helper for adjusting to 64 bits. +inline std::pair getAdjusted64(uint64_t Digits, + int16_t Scale = 0) { + return getAdjusted(Digits, Scale); +} } } diff --git a/unittests/Support/ScaledNumberTest.cpp b/unittests/Support/ScaledNumberTest.cpp index 1fa54ff81d7..dac24051a62 100644 --- a/unittests/Support/ScaledNumberTest.cpp +++ b/unittests/Support/ScaledNumberTest.cpp @@ -57,4 +57,27 @@ TEST(ScaledNumberHelpersTest, getRounded) { EXPECT_EQ(getRounded(UINT64_MAX, 0, true), SP64(UINT64_C(1) << 63, 1)); } + +TEST(FloatsTest, getAdjusted) { + const uint64_t Max32In64 = UINT32_MAX; + EXPECT_EQ(getAdjusted32(0), SP32(0, 0)); + EXPECT_EQ(getAdjusted32(0, 5), SP32(0, 5)); + EXPECT_EQ(getAdjusted32(UINT32_MAX), SP32(UINT32_MAX, 0)); + EXPECT_EQ(getAdjusted32(Max32In64 << 1), SP32(UINT32_MAX, 1)); + EXPECT_EQ(getAdjusted32(Max32In64 << 1, 1), SP32(UINT32_MAX, 2)); + EXPECT_EQ(getAdjusted32(Max32In64 << 31), SP32(UINT32_MAX, 31)); + EXPECT_EQ(getAdjusted32(Max32In64 << 32), SP32(UINT32_MAX, 32)); + EXPECT_EQ(getAdjusted32(Max32In64 + 1), SP32(1u << 31, 1)); + EXPECT_EQ(getAdjusted32(UINT64_MAX), SP32(1u << 31, 33)); + + EXPECT_EQ(getAdjusted64(0), SP64(0, 0)); + EXPECT_EQ(getAdjusted64(0, 5), SP64(0, 5)); + EXPECT_EQ(getAdjusted64(UINT32_MAX), SP64(UINT32_MAX, 0)); + EXPECT_EQ(getAdjusted64(Max32In64 << 1), SP64(Max32In64 << 1, 0)); + EXPECT_EQ(getAdjusted64(Max32In64 << 1, 1), SP64(Max32In64 << 1, 1)); + EXPECT_EQ(getAdjusted64(Max32In64 << 31), SP64(Max32In64 << 31, 0)); + EXPECT_EQ(getAdjusted64(Max32In64 << 32), SP64(Max32In64 << 32, 0)); + EXPECT_EQ(getAdjusted64(Max32In64 + 1), SP64(Max32In64 + 1, 0)); + EXPECT_EQ(getAdjusted64(UINT64_MAX), SP64(UINT64_MAX, 0)); +} } -- 2.11.0