Skip to content

Commit a6965ff

Browse files
eendebakptclaude
andcommitted
Let compilers vectorize v_complement()
The two's complement of a digit vector is ~a + 1, and the +1 only carries through the trailing zero digits: they stay zero, the first nonzero digit is negated, and the digits above it are just inverted. Written that way no carry is passed between loop iterations, so the loop can be vectorized. v_complement() runs for every bitwise operation with a negative multi-digit operand, up to three times per operation. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
1 parent 7f52444 commit a6965ff

1 file changed

Lines changed: 13 additions & 7 deletions

File tree

‎Objects/longobject.c‎

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5552,14 +5552,20 @@ _PyLong_Lshift(PyObject *a, int64_t shiftby)
55525552
static void
55535553
v_complement(digit *z, digit *a, Py_ssize_t m)
55545554
{
5555-
Py_ssize_t i;
5556-
digit carry = 1;
5557-
for (i = 0; i < m; ++i) {
5558-
carry += a[i] ^ PyLong_MASK;
5559-
z[i] = carry & PyLong_MASK;
5560-
carry >>= PyLong_SHIFT;
5555+
Py_ssize_t i = 0;
5556+
5557+
/* -a is ~a + 1, and the +1 only carries through the trailing zero
5558+
digits: they stay zero, the first nonzero digit is negated, and the
5559+
digits above it are just inverted. No carry is passed between
5560+
iterations of the last loop, so it can be vectorized. */
5561+
while (i < m && a[i] == 0) {
5562+
z[i++] = 0;
5563+
}
5564+
assert(i < m);
5565+
z[i] = (0U - a[i]) & PyLong_MASK;
5566+
for (++i; i < m; ++i) {
5567+
z[i] = a[i] ^ PyLong_MASK;
55615568
}
5562-
assert(carry == 0);
55635569
}
55645570

55655571
/* Bitwise and/xor/or operations */

0 commit comments

Comments
 (0)