This is an archive of the discontinued LLVM Phabricator instance.

[Support] Fix SaturatingMultiply<T>() to be correct (and fast), Re-enable Unit Tests
ClosedPublic

Authored by slingn on Nov 19 2015, 3:00 PM.

Details

Summary

This change fixes the SaturatingMultiply<T>() function template to not cause undefined behavior with T=uint16_t.
Thanks to Richard Smith's contribution, it also no longer requires an integer division.

Patch by Richard Smith.

Diff Detail

Repository
rL LLVM

Event Timeline

slingn updated this revision to Diff 40709.Nov 19 2015, 3:00 PM
slingn retitled this revision from to [Support] Fix SaturatingMultiply<T>() to never cause overflow, Re-enable Unit Tests.
slingn updated this object.
slingn added reviewers: davidxl, silvas.
slingn added a subscriber: llvm-commits.
davidxl edited edge metadata.Nov 19 2015, 3:14 PM

Is there a bug in UBSan?

integer division is expensive. I wonder if we can take some fast path to by pass it

T Upper = Max >> (sizeof(T)*4);
if (X <= Upper && Y <= Upper)

return X * Y;

// regular stuff

https://llvm.org/bugs/show_bug.cgi?id=25580

Apparently not a bug with UBSan - there was a valid problem with signed integer overflow due to up-conversion of integer types with the previous implementation.

ok makes sense.

davidxl accepted this revision.Nov 19 2015, 5:55 PM
davidxl edited edge metadata.

If you have time, finding a way to speed up the method will be welcome (such as the fast path suggestion).

This revision is now accepted and ready to land.Nov 19 2015, 5:55 PM
rsmith added a subscriber: rsmith.Nov 19 2015, 7:27 PM

See the patch I posted on the other thread for this issue -- that should
avoid the UB and the division in all cases.

slingn updated this revision to Diff 40803.Nov 20 2015, 10:48 AM
slingn edited edge metadata.

Updated with Richard Smith's patch for SaturatingMultiply().

slingn retitled this revision from [Support] Fix SaturatingMultiply<T>() to never cause overflow, Re-enable Unit Tests to [Support] Fix SaturatingMultiply<T>() to be correct (and fast), Re-enable Unit Tests.Nov 20 2015, 10:49 AM
slingn updated this object.

neat - count leading zeros instructions is very fast on intel platforms. The implementation completely removed the need for idiv.

rsmith added inline comments.Nov 20 2015, 11:39 AM
unittests/Support/MathExtrasTest.cpp
220 ↗(On Diff #40803)

It'd be useful to also test cases like ((1 << A) - 1) * ((1 << B) + K), for K in [-1, 0, 1] and A + B == numeric_limits<T>::digits, as those are interesting transition cases for the new algorithm (you get overflow iff A > B and K = 1). More generally, testcases where overflow almost happens or only just happens would be good here.

Also, coverage for 0 * Max and 0 * 0 would be good.

slingn updated this revision to Diff 40821.Nov 20 2015, 1:15 PM

Added unit tests based on rsmith's suggestions.

slingn marked an inline comment as done.Nov 20 2015, 1:16 PM
This revision was automatically updated to reflect the committed changes.