This is an archive of the discontinued LLVM Phabricator instance.

Use __builtin_clz to find leading 1 in generic sqrt (where possible)
ClosedPublic

Authored by cratonica on Feb 25 2022, 11:12 AM.

Details

Summary

__builtin_clz requires just a single instruction on x86 and arm, so this is a performance improvement.

Diff Detail

Event Timeline

cratonica created this revision.Feb 25 2022, 11:12 AM
cratonica requested review of this revision.Feb 25 2022, 11:12 AM
cratonica updated this revision to Diff 411468.

Fix some declaration ordering

Attempting to fix patch

lntue added inline comments.Feb 25 2022, 2:06 PM
libc/src/__support/FPUtil/generic/sqrt.h
65–66

Can you do a simple perf test to see if using clz for 64 bits is faster than binary search? Something like:

uint64_t hi_bits = static_cast<uint64_t>(mantissa >> 64);
int shift  = hi_bits ? (clz(hi_bits) - 15) : (clz(static_cast<uint64_t>(mantissa)) + 49);
exponent -= shift;
mantissa <<= shift;
cratonica added inline comments.Feb 25 2022, 3:22 PM
libc/src/__support/FPUtil/generic/sqrt.h
65–66
  1. Unfortunately there aren't any differential or performance tests for sqrt or sqrtl, so I'll need to add those first in a separate PR. It won't be too much work, just clone the ones for sqrtf.
  2. Also, I don't actually have a machine on which I can test 128-bit floats -- my machine uses the 80-bit x87 format, and aarch64 uses 64-bit for long double.
cratonica added inline comments.Feb 28 2022, 8:48 AM
libc/src/__support/FPUtil/generic/sqrt.h
65–66

Following up here:

re: #1: It seems as though we only have perf tests for the float32 variants of math functions due to the logarithmic increase in the domain required for 64-bit inputs. Trying to run an exhaustive performance test using float64 never completed even after an hour of waiting, and I can't imagine an exhaustive test for 128-bit inputs would complete even after days. So I'm going to write a one-off performance test that terminates after 2^24 iterations to test this, but I won't be checking it in

re: #2: The x87 8-bit variant uses a 64-bit mantissa, which means that __bulting_clzll is will still work after truncation, so this is trivial to implement (and I have confirmed a slight performance increase here using the method mentioned above). I was incorrect that aarch64 uses 64-bit floats for long double, and I have access to some hardware with an aarch64 Cortex-A53 that I can run these performance test on with the changes you mentioned. If performance is improved, then I will update the patch accordingly.

cratonica added inline comments.Feb 28 2022, 12:16 PM
libc/src/__support/FPUtil/generic/sqrt.h
65–66

Results for 128-bit floats (long double) from the aarch64 Cortex-A53 core in denormal range:

clz: 28894915309ns
binary search: 29253929397ns

So, just over a 1% performance improvement, which is in-line with what I'm seeing on the 32-bit float sqrtf function.

Therefore, I'm patching in that change (as well as the x87 80-bit specialization).

Add optimizations for x87 80-bit floats and aarch64 128-bit floats

lntue accepted this revision.Feb 28 2022, 1:20 PM

Thanks for doing the performance tests for all the data types!

This revision is now accepted and ready to land.Feb 28 2022, 1:20 PM

Thank you! As I don't have repo access (nor probably should I yet), please submit per https://llvm.org/docs/Phabricator.html#committing-someone-s-change-from-phabricator if you would (sivachandra did this for me on D117684).