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

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

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.