Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

<numeric> Optimize gcd to use builtins #665

Merged
merged 6 commits into from
Apr 11, 2020
Merged

Conversation

miscco
Copy link
Contributor

@miscco miscco commented Mar 31, 2020

Description

This fixes #298 by moving the meat of the bitscan implementation to the limits header.

This seems unfortunate but is the smallest common denominator of <numeric> and <bit>

Also we cannot go without limits anyway because the implementation needs it.

Checklist

Be sure you've read README.md and understand the scope of this repo.

If you're unsure about a box, leave it unchecked. A maintainer will help you.

  • Identifiers in product code changes are properly _Ugly as per
    https://eel.is/c++draft/lex.name#3.1 or there are no product code changes.
  • The STL builds successfully and all tests have passed (must be manually
    verified by an STL maintainer before automated testing is enabled on GitHub,
    leave this unchecked for initial submission).
  • These changes introduce no known ABI breaks (adding members, renaming
    members, adding virtual functions, changing whether a type is an aggregate
    or trivially copyable, etc.).
  • These changes were written from scratch using only this repository,
    the C++ Working Draft (including any cited standards), other WG21 papers
    (excluding reference implementations outside of proposed standard wording),
    and LWG issues as reference material. If they were derived from a project
    that's already listed in NOTICE.txt, that's fine, but please mention it.
    If they were derived from any other project (including Boost and libc++,
    which are not yet listed in NOTICE.txt), you must mention it here,
    so we can determine whether the license is compatible and what else needs
    to be done.

@miscco miscco requested a review from a team as a code owner March 31, 2020 20:29
@BillyONeal
Copy link
Member

Test failures look legit on this one :)

@miscco
Copy link
Contributor Author

miscco commented Apr 1, 2020

Hm I compiled for me, I will check again :(

@miscco
Copy link
Contributor Author

miscco commented Apr 1, 2020

Go home test you are drunk:

C:\agent_work\1\a\x86\out\inc\limits(1021,26): note: candidate template ignored: requirement '_Is_standard_unsigned_integer' was not satisfied [with _Ty = int]

So it seems that common_unsigned does funny things

@miscco
Copy link
Contributor Author

miscco commented Apr 1, 2020

The full error is:

In file included from C:\agent_work\1\s\llvm-project\libcxx\test\std\numerics\numeric.ops\numeric.ops.gcd\gcd.pass.cpp:16:
C:\agent_work\1\a\x86\out\inc\numeric(864,39): error: no matching function for call to '_Countl_zero'

return static_cast(_Countl_zero(~_Mask));
^~~~~~~~~~~~
C:\agent_work\1\a\x86\out\inc\numeric(898,39): note: in instantiation of function template specialization 'std::_Stl_bitscan_forward' requested here

const auto _Mx_trailing_zeroes = _Stl_bitscan_forward(_Mx_magnitude);

C:\agent_work\1\s\llvm-project\libcxx\test\std\numerics\numeric.ops\numeric.ops.gcd\gcd.pass.cpp(48,45): note: in instantiation of function template specialization 'std::gcd<signed char, signed char>' requested here

assert(static_cast<Output>(out) == std::gcd(value1, value2));

C:\agent_work\1\s\llvm-project\libcxx\test\std\numerics\numeric.ops\numeric.ops.gcd\gcd.pass.cpp(64,27): note: in instantiation of function template specialization 'test0<signed char, signed char, signed char>' requested here

        accumulate &= test0<S1, S2, Output>(TC.x, TC.y, TC.expect);

                      ^

C:\agent_work\1\s\llvm-project\libcxx\test\std\numerics\numeric.ops\numeric.ops.gcd\gcd.pass.cpp(100,19): note: in instantiation of function template specialization 'do_test<signed char, signed char>' requested here

static_assert(do_test<signed char>(), "");

              ^

C:\agent_work\1\a\x86\out\inc\limits(1021,26): note: candidate template ignored: requirement '_Is_standard_unsigned_integer' was not satisfied [with _Ty = int]

_NODISCARD constexpr int _Countl_zero(const _Ty _Val) noexcept {

So in the test the type is signed_char that is passed into make_unsigned_t to deduce _Common_unsigned. I guess that should make it a unsigned char which is the type of _Mx_magnitude.

So the type passed to _Countl_zero is unsigned char where does it get the int from?

@miscco
Copy link
Contributor Author

miscco commented Apr 1, 2020

It seems that for whatever reason the template argument deduction fails. if I specify _Countl_zero<_Unsigned> it works.

That however smells terribly like a compiler bug

@CaseyCarter CaseyCarter added the performance Must go faster label Apr 1, 2020
@miscco
Copy link
Contributor Author

miscco commented Apr 2, 2020

So tests are good, although I would like an opinion whether this is a compiler bug or just me not understanding C++.

The only thing I could com up with is that ~_Mask is changing the type but please tell me it doesnt

@miscco miscco closed this Apr 2, 2020
@miscco miscco reopened this Apr 2, 2020
stl/inc/numeric Outdated Show resolved Hide resolved
@AlexGuteniev
Copy link
Contributor

AlexGuteniev commented Apr 2, 2020

that ~_Mask is changing the type

Why not?

https://eel.is/c++draft/expr.unary.op#10

Integral promotions are performed. The type of the result is the type of the promoted operand.

https://eel.is/c++draft/conv.prom#2

A prvalue of type char16_­t, char32_­t, or wchar_­t ([basic.fundamental]) can be converted to a prvalue of the first of the following types that can represent all the values of its underlying type: int, unsigned int, long int, unsigned long int, long long int, or unsigned long long int.

("Can" here means the conversion exists as integral promotion. The key verb here is "are" above. Promotions are performed)

stl/inc/numeric Outdated Show resolved Hide resolved
Copy link
Member

@StephanTLavavej StephanTLavavej left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great, thank you! I tried my hardest, but the only issue I could find was a whitespace nitpick.

stl/inc/numeric Outdated Show resolved Hide resolved
Co-Authored-By: Stephan T. Lavavej <stl@nuwen.net>
@CaseyCarter CaseyCarter changed the title [numerics] Optimize gcd to use builtins <numeric> Optimize gcd to use builtins Apr 9, 2020
@CaseyCarter CaseyCarter self-assigned this Apr 9, 2020
@CaseyCarter CaseyCarter merged commit bda4230 into microsoft:master Apr 11, 2020
@CaseyCarter
Copy link
Member

Thanks for the performance enhancement! 🐎

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
performance Must go faster
Projects
None yet
Development

Successfully merging this pull request may close these issues.

<numeric>: Make gcd() faster with constexpr bitscan intrinsics
5 participants