Skip to content

Commit

Permalink
[Support] Add saturating multiply-add support function
Browse files Browse the repository at this point in the history
Summary: Add SaturatingMultiplyAdd convenience function template since A + (X * Y) comes up frequently when doing weighted arithmetic.

Reviewers: davidxl, silvas

Subscribers: llvm-commits

Differential Revision: http://reviews.llvm.org/D15385

llvm-svn: 257532
  • Loading branch information
Nathan Slingerland committed Jan 12, 2016
1 parent b4f94aa commit 7bee316
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 54 deletions.
55 changes: 15 additions & 40 deletions llvm/include/llvm/ProfileData/SampleProf.h
Expand Up @@ -140,16 +140,9 @@ class SampleRecord {
/// around unsigned integers.
sampleprof_error addSamples(uint64_t S, uint64_t Weight = 1) {
bool Overflowed;
if (Weight > 1) {
S = SaturatingMultiply(S, Weight, &Overflowed);
if (Overflowed)
return sampleprof_error::counter_overflow;
}
NumSamples = SaturatingAdd(NumSamples, S, &Overflowed);
if (Overflowed)
return sampleprof_error::counter_overflow;

return sampleprof_error::success;
NumSamples = SaturatingMultiplyAdd(S, Weight, NumSamples, &Overflowed);
return Overflowed ? sampleprof_error::counter_overflow
: sampleprof_error::success;
}

/// Add called function \p F with samples \p S.
Expand All @@ -161,16 +154,10 @@ class SampleRecord {
uint64_t Weight = 1) {
uint64_t &TargetSamples = CallTargets[F];
bool Overflowed;
if (Weight > 1) {
S = SaturatingMultiply(S, Weight, &Overflowed);
if (Overflowed)
return sampleprof_error::counter_overflow;
}
TargetSamples = SaturatingAdd(TargetSamples, S, &Overflowed);
if (Overflowed)
return sampleprof_error::counter_overflow;

return sampleprof_error::success;
TargetSamples =
SaturatingMultiplyAdd(S, Weight, TargetSamples, &Overflowed);
return Overflowed ? sampleprof_error::counter_overflow
: sampleprof_error::success;
}

/// Return true if this sample record contains function calls.
Expand Down Expand Up @@ -215,29 +202,17 @@ class FunctionSamples {
void dump() const;
sampleprof_error addTotalSamples(uint64_t Num, uint64_t Weight = 1) {
bool Overflowed;
if (Weight > 1) {
Num = SaturatingMultiply(Num, Weight, &Overflowed);
if (Overflowed)
return sampleprof_error::counter_overflow;
}
TotalSamples = SaturatingAdd(TotalSamples, Num, &Overflowed);
if (Overflowed)
return sampleprof_error::counter_overflow;

return sampleprof_error::success;
TotalSamples =
SaturatingMultiplyAdd(Num, Weight, TotalSamples, &Overflowed);
return Overflowed ? sampleprof_error::counter_overflow
: sampleprof_error::success;
}
sampleprof_error addHeadSamples(uint64_t Num, uint64_t Weight = 1) {
bool Overflowed;
if (Weight > 1) {
Num = SaturatingMultiply(Num, Weight, &Overflowed);
if (Overflowed)
return sampleprof_error::counter_overflow;
}
TotalHeadSamples = SaturatingAdd(TotalHeadSamples, Num, &Overflowed);
if (Overflowed)
return sampleprof_error::counter_overflow;

return sampleprof_error::success;
TotalHeadSamples =
SaturatingMultiplyAdd(Num, Weight, TotalHeadSamples, &Overflowed);
return Overflowed ? sampleprof_error::counter_overflow
: sampleprof_error::success;
}
sampleprof_error addBodySamples(uint32_t LineOffset, uint32_t Discriminator,
uint64_t Num, uint64_t Weight = 1) {
Expand Down
19 changes: 19 additions & 0 deletions llvm/include/llvm/Support/MathExtras.h
Expand Up @@ -717,6 +717,25 @@ SaturatingMultiply(T X, T Y, bool *ResultOverflowed = nullptr) {
return Z;
}

/// \brief Multiply two unsigned integers, X and Y, and add the unsigned
/// integer, A to the product. Clamp the result to the maximum representable
/// value of T on overflow. ResultOverflowed indicates if the result is larger
/// than the maximum representable value of type T.
/// Note that this is purely a convenience function as there is no distinction
/// where overflow occurred in a 'fused' multiply-add for unsigned numbers.
template <typename T>
typename std::enable_if<std::is_unsigned<T>::value, T>::type
SaturatingMultiplyAdd(T X, T Y, T A, bool *ResultOverflowed = nullptr) {
bool Dummy;
bool &Overflowed = ResultOverflowed ? *ResultOverflowed : Dummy;

T Product = SaturatingMultiply(X, Y, &Overflowed);
if (Overflowed)
return Product;

return SaturatingAdd(A, Product, &Overflowed);
}

extern const float huge_valf;
} // End llvm namespace

Expand Down
17 changes: 3 additions & 14 deletions llvm/lib/ProfileData/InstrProf.cpp
Expand Up @@ -269,14 +269,8 @@ instrprof_error InstrProfValueSiteRecord::merge(InstrProfValueSiteRecord &Input,
while (I != IE && I->Value < J->Value)
++I;
if (I != IE && I->Value == J->Value) {
uint64_t JCount = J->Count;
bool Overflowed;
if (Weight > 1) {
JCount = SaturatingMultiply(JCount, Weight, &Overflowed);
if (Overflowed)
Result = instrprof_error::counter_overflow;
}
I->Count = SaturatingAdd(I->Count, JCount, &Overflowed);
I->Count = SaturatingMultiplyAdd(J->Count, Weight, I->Count, &Overflowed);
if (Overflowed)
Result = instrprof_error::counter_overflow;
++I;
Expand Down Expand Up @@ -328,13 +322,8 @@ instrprof_error InstrProfRecord::merge(InstrProfRecord &Other,

for (size_t I = 0, E = Other.Counts.size(); I < E; ++I) {
bool Overflowed;
uint64_t OtherCount = Other.Counts[I];
if (Weight > 1) {
OtherCount = SaturatingMultiply(OtherCount, Weight, &Overflowed);
if (Overflowed)
Result = instrprof_error::counter_overflow;
}
Counts[I] = SaturatingAdd(Counts[I], OtherCount, &Overflowed);
Counts[I] =
SaturatingMultiplyAdd(Other.Counts[I], Weight, Counts[I], &Overflowed);
if (Overflowed)
Result = instrprof_error::counter_overflow;
}
Expand Down
54 changes: 54 additions & 0 deletions llvm/unittests/Support/MathExtrasTest.cpp
Expand Up @@ -304,4 +304,58 @@ TEST(MathExtras, SaturatingMultiply) {
SaturatingMultiplyTestHelper<uint64_t>();
}

template<typename T>
void SaturatingMultiplyAddTestHelper()
{
const T Max = std::numeric_limits<T>::max();
bool ResultOverflowed;

// Test basic multiply-add.
EXPECT_EQ(T(16), SaturatingMultiplyAdd(T(2), T(3), T(10)));
EXPECT_EQ(T(16), SaturatingMultiplyAdd(T(2), T(3), T(10), &ResultOverflowed));
EXPECT_FALSE(ResultOverflowed);

// Test multiply overflows, add doesn't overflow
EXPECT_EQ(Max, SaturatingMultiplyAdd(Max, Max, T(0), &ResultOverflowed));
EXPECT_TRUE(ResultOverflowed);

// Test multiply doesn't overflow, add overflows
EXPECT_EQ(Max, SaturatingMultiplyAdd(T(1), T(1), Max, &ResultOverflowed));
EXPECT_TRUE(ResultOverflowed);

// Test multiply-add with Max as operand
EXPECT_EQ(Max, SaturatingMultiplyAdd(T(1), T(1), Max, &ResultOverflowed));
EXPECT_TRUE(ResultOverflowed);

EXPECT_EQ(Max, SaturatingMultiplyAdd(T(1), Max, T(1), &ResultOverflowed));
EXPECT_TRUE(ResultOverflowed);

EXPECT_EQ(Max, SaturatingMultiplyAdd(Max, Max, T(1), &ResultOverflowed));
EXPECT_TRUE(ResultOverflowed);

EXPECT_EQ(Max, SaturatingMultiplyAdd(Max, Max, Max, &ResultOverflowed));
EXPECT_TRUE(ResultOverflowed);

// Test multiply-add with 0 as operand
EXPECT_EQ(T(1), SaturatingMultiplyAdd(T(1), T(1), T(0), &ResultOverflowed));
EXPECT_FALSE(ResultOverflowed);

EXPECT_EQ(T(1), SaturatingMultiplyAdd(T(1), T(0), T(1), &ResultOverflowed));
EXPECT_FALSE(ResultOverflowed);

EXPECT_EQ(T(1), SaturatingMultiplyAdd(T(0), T(0), T(1), &ResultOverflowed));
EXPECT_FALSE(ResultOverflowed);

EXPECT_EQ(T(0), SaturatingMultiplyAdd(T(0), T(0), T(0), &ResultOverflowed));
EXPECT_FALSE(ResultOverflowed);

}

TEST(MathExtras, SaturatingMultiplyAdd) {
SaturatingMultiplyAddTestHelper<uint8_t>();
SaturatingMultiplyAddTestHelper<uint16_t>();
SaturatingMultiplyAddTestHelper<uint32_t>();
SaturatingMultiplyAddTestHelper<uint64_t>();
}

}

0 comments on commit 7bee316

Please sign in to comment.