gh-157742: Let compilers vectorize the int shift loops - #157751
eendebakpt wants to merge 3 commits into
Conversation
Both loops passed a carry from one iteration to the next, which prevents vectorization. The carry into a digit is just the bits shifted out of its neighbour, so build each output digit from two input digits instead. x_divrem() normalizes with three such passes, which dominate its cost when the quotient is short. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
long_lshift1() and the non-negative case of long_rshift1() had their own copies of the carried loop. Call the now vectorizable helpers instead. Negative right shifts keep their loop: it also propagates a rounding carry. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
Just curious, have you checked the assembly code to see which SIMD instructions are getting used? Maybe we can do even better with some more rearrangement? |
I did not check this. From my AI: with GCC 14 at the default The loop is versioned with a runtime overlap check, the tail is done with one 2-digit vector step and then scalar code. That is 10 instructions per 4 digits, where the old scalar loop needed about 6 per digit. |
|
There is a similar issue/PR for aarch64 with similar approches (using double digits) IIRC |
I think that is #156443. It touches the same code, but is different, |
v_lshift()andv_rshift()pass a carry from one loop iteration to the next, which prevents vectorization. The carry into a digit is just the bits shifted out of its neighbour, so each output digit can be built from two input digits instead, with nothing carried.These helpers do the normalization in
x_divrem()(three passes that dominatewhen the quotient is short) and the scaling in true division.
pidigitsBenchmark script
Note: when disabling vectorization I get a 20% slowdown. I think that is ok, since modern cpu's/compilers can do this, if not we could modify the PR to gate the change behind some macro.
Generated with Claude Code