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

bpo-29782: Consolidate _Py_Bit_Length() #20739

Merged
merged 21 commits into from
Jun 15, 2020
Merged

Conversation

niklasf
Copy link
Contributor

@niklasf niklasf commented Jun 8, 2020

In GH-2866, _Py_Bit_Length() was added to pymath.h for lack of a better
location. GH-20518 added a more appropriate header file for bit utilities. It
also shows how to properly use intrinsics. This allows reconsidering bpo-29782.

  • Move the function to the new header.
  • Changed return type to match __builtin_clzl and reviewed usage.
  • Use intrinsics where available.
  • Pick a (mostly theoretical) fallback implementation suitable for
    inlining.

https://bugs.python.org/issue29782

Copy link
Member

@vstinner vstinner left a comment

Choose a reason for hiding this comment

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

Maybe add test_bit_length() to _testinternalcapi.c: see test_popcount().

Include/internal/pycore_bitutils.h Show resolved Hide resolved
Include/internal/pycore_bitutils.h Outdated Show resolved Hide resolved
Include/internal/pycore_bitutils.h Show resolved Hide resolved
Modules/mathmodule.c Outdated Show resolved Hide resolved
@vstinner
Copy link
Member

vstinner commented Jun 8, 2020

Previous rejected attempt: PR #594.

@vstinner
Copy link
Member

vstinner commented Jun 8, 2020

cc @mdickinson

Copy link
Member

@vstinner vstinner left a comment

Choose a reason for hiding this comment

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

I disliked PR #594 because it added #include <intrin.h> to a new *public header file: Include/pyintrinsics.h. This PR is different, all changes are made in the internal C API. We have way more freedom in the internal C API.

Modules/mathmodule.c Show resolved Hide resolved
@vstinner
Copy link
Member

vstinner commented Jun 8, 2020

The Windows build looks broken:

Run .\python.bat -m test.pythoninfo
Running Release|x64 interpreter...
##[error]Process completed with exit code 1.

@mdickinson mdickinson self-requested a review June 8, 2020 18:26
In pythonGH-2866, _Py_Bit_Length() was added to pymath.h for lack of a better
location. pythonGH-20518 added a more appropriate header file for bit utilities. It
also shows how to properly use intrinsics. This allows reconsidering bpo-29782.

* Move the function to the new header.
* Changed return type to match __builtin_clzl and reviewed usage.
* Use intrinsics where available.
* Pick a (mostly theoretical) fallback implementation suitable for
  inlining.
Include/internal/pycore_bitutils.h Outdated Show resolved Hide resolved
Modules/mathmodule.c Outdated Show resolved Hide resolved
niklasf and others added 2 commits June 8, 2020 22:03
Co-authored-by: Victor Stinner <vstinner@python.org>
Include/internal/pycore_bitutils.h Outdated Show resolved Hide resolved
Include/internal/pycore_bitutils.h Outdated Show resolved Hide resolved
@niklasf
Copy link
Contributor Author

niklasf commented Jun 8, 2020

Thanks for reviewing.

Also added unit tests as suggested (in addition to the existing test coverage). I briefly disabled the branch with clz (8e3ce66) to get a CI run with the fallback implementation. The current fallback is identical to the original (except for inlining).

Copy link
Member

@vstinner vstinner left a comment

Choose a reason for hiding this comment

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

Thanks for the many updates! The code now looks better! New review.

Include/internal/pycore_bitutils.h Show resolved Hide resolved
Modules/_testinternalcapi.c Outdated Show resolved Hide resolved
Modules/_testinternalcapi.c Outdated Show resolved Hide resolved
Objects/longobject.c Outdated Show resolved Hide resolved
Include/internal/pycore_bitutils.h Outdated Show resolved Hide resolved
@vstinner
Copy link
Member

vstinner commented Jun 8, 2020

Using gcc 10 -O3 -flto, I get the following machine code in test_bit_length():

# input = rax
# if (x != 0)
test   rax,rax
je     0x7fffeaa99978 <test_bit_length+504>

# return (int)sizeof(unsigned long) * 8 - __builtin_clzl(x);
# return 0x40 - bsr(rax) ^ 0x3f
bsr    rax,rax
mov    ecx,0x40
xor    rax,0x3f
mov    r9d,ecx
sub    r9d,eax
# result = r9d

x86 BSR (Bit Scan Reverse) instruction is used as expected.

Copy link
Member

@vstinner vstinner left a comment

Choose a reason for hiding this comment

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

LGTM!

@mdickinson: Do you want to review this PR as well?

@mdickinson
Copy link
Member

@mdickinson: Do you want to review this PR as well?

I'd very much like to take a look, but am short on available time. Can you give me until the weekend? If I've failed to review by the start of next week, go ahead and merge.

@vstinner
Copy link
Member

vstinner commented Jun 9, 2020

@mdickinson: this PR can wait one week :-)

static int
bit_length_digit(digit x)
{
Py_BUILD_ASSERT(PyLong_SHIFT <= sizeof(unsigned long) * 8);
Copy link
Member

Choose a reason for hiding this comment

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

It would be nice if C provided some standard way to get the width (in the sense of C99 §6.2.6.2p6) of an integer type, so that we didn't have to use sizeof(unsigned long) * 8, which could fail in the presence of padding bits. But as far as I know it doesn't. Related: https://stackoverflow.com/q/3957252/270986

Copy link
Member

@mdickinson mdickinson left a comment

Choose a reason for hiding this comment

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

LGTM!

@vstinner vstinner merged commit 794e7d1 into python:master Jun 15, 2020
@vstinner
Copy link
Member

Thanks @niklasf, I merged your PR.

I removed "(mostly theoretical)" from your commit message:

* Pick a (mostly theoretical) fallback implementation suitable for
  inlining.

We support other C compilers, like XLC.

arun-mani-j pushed a commit to arun-mani-j/cpython that referenced this pull request Jul 21, 2020
In pythonGH-2866, _Py_Bit_Length() was added to pymath.h for lack of a better
location. pythonGH-20518 added a more appropriate header file for bit utilities. It
also shows how to properly use intrinsics. This allows reconsidering bpo-29782.

* Move the function to the new header.
* Changed return type to match __builtin_clzl() and reviewed usage.
* Use intrinsics where available.
* Pick a fallback implementation suitable for inlining.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants