Skip to content

Commit 465efdf

Browse files
committed
optimized math
1 parent ca9e6a5 commit 465efdf

File tree

6 files changed

+43
-70
lines changed

6 files changed

+43
-70
lines changed

Include/internal/pycore_range.h

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,25 @@ extern "C" {
1010

1111
typedef struct {
1212
PyObject_HEAD
13-
long start;
14-
long step;
1513
long len;
14+
long end;
15+
long step;
1616
long stop;
1717
} _PyRangeIterObject;
1818

19-
extern long _PyRangeIter_GetLength(_PyRangeIterObject *r, long start);
19+
static inline long
20+
_PyRangeIter_GetLengthAndStart(_PyRangeIterObject *r, long *value)
21+
{
22+
long len = FT_ATOMIC_LOAD_LONG_RELAXED(r->len);
23+
*value = r->end - r->step * len;
24+
return len;
25+
}
26+
27+
static inline void
28+
_PyRangeIter_SetLength(_PyRangeIterObject *r, long len)
29+
{
30+
FT_ATOMIC_STORE_LONG_RELAXED(r->len, len);
31+
}
2032

2133
#ifdef __cplusplus
2234
}

Objects/rangeobject.c

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -830,13 +830,10 @@ static PyObject *
830830
rangeiter_next(PyObject *op)
831831
{
832832
_PyRangeIterObject *r = (_PyRangeIterObject*)op;
833-
long start = FT_ATOMIC_LOAD_LONG_RELAXED(r->start);
834-
long len = _PyRangeIter_GetLength(r, start);
833+
long start;
834+
long len = _PyRangeIter_GetLengthAndStart(r, &start);
835835
if (len > 0) {
836-
#ifndef Py_GIL_DISABLED
837-
r->len = len - 1;
838-
#endif
839-
FT_ATOMIC_STORE_LONG_RELAXED(r->start, start + r->step);
836+
_PyRangeIter_SetLength(r, len - 1);
840837
return PyLong_FromLong(start);
841838
}
842839
return NULL;
@@ -846,8 +843,9 @@ static PyObject *
846843
rangeiter_len(PyObject *op, PyObject *Py_UNUSED(ignored))
847844
{
848845
_PyRangeIterObject *r = (_PyRangeIterObject*)op;
849-
long start = FT_ATOMIC_LOAD_LONG_RELAXED(r->start);
850-
return PyLong_FromLong(_PyRangeIter_GetLength(r, start));
846+
long start;
847+
long len = _PyRangeIter_GetLengthAndStart(r, &start);
848+
return PyLong_FromLong(len);
851849
}
852850

853851
PyDoc_STRVAR(length_hint_doc,
@@ -861,7 +859,9 @@ rangeiter_reduce(PyObject *op, PyObject *Py_UNUSED(ignored))
861859
PyObject *range;
862860

863861
/* create a range object for pickling */
864-
start = PyLong_FromLong(FT_ATOMIC_LOAD_LONG_RELAXED(r->start));
862+
long lstart;
863+
(void)_PyRangeIter_GetLengthAndStart(r, &lstart);
864+
start = PyLong_FromLong(lstart);
865865
if (start == NULL)
866866
goto err;
867867
stop = PyLong_FromLong(r->stop);
@@ -892,14 +892,13 @@ rangeiter_setstate(PyObject *op, PyObject *state)
892892
if (index == -1 && PyErr_Occurred())
893893
return NULL;
894894
/* silently clip the index value */
895-
long start = FT_ATOMIC_LOAD_LONG_RELAXED(r->start);
896-
long len = _PyRangeIter_GetLength(r, start);
895+
long start;
896+
long len = _PyRangeIter_GetLengthAndStart(r, &start);
897897
if (index < 0)
898898
index = 0;
899899
else if (index > len)
900900
index = len; /* exhausted iterator */
901-
r->len = len - index;
902-
FT_ATOMIC_STORE_LONG_RELAXED(r->start, start + index * r->step);
901+
_PyRangeIter_SetLength(r, len - index);
903902
Py_RETURN_NONE;
904903
}
905904

@@ -983,9 +982,9 @@ fast_range_iter(long start, long stop, long step, long len)
983982
_PyRangeIterObject *it = PyObject_New(_PyRangeIterObject, &PyRangeIter_Type);
984983
if (it == NULL)
985984
return NULL;
986-
it->start = start;
987-
it->step = step;
988985
it->len = len;
986+
it->end = start + step * len;
987+
it->step = step;
989988
it->stop = stop;
990989
return (PyObject *)it;
991990
}

Python/bytecodes.c

Lines changed: 6 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3284,25 +3284,14 @@ dummy_func(
32843284
_PyRangeIterObject *r = (_PyRangeIterObject *)PyStackRef_AsPyObjectBorrow(iter);
32853285
assert(Py_TYPE(r) == &PyRangeIter_Type);
32863286
STAT_INC(FOR_ITER, hit);
3287-
#ifdef Py_GIL_DISABLED
3288-
long value = FT_ATOMIC_LOAD_LONG_RELAXED(r->start);
3289-
long len = _PyRangeIter_GetLength(r, value);
3287+
long value;
3288+
long len = _PyRangeIter_GetLengthAndStart(r, &value);
32903289
if (len <= 0) {
32913290
// Jump over END_FOR instruction.
32923291
JUMPBY(oparg + 1);
32933292
DISPATCH();
32943293
}
3295-
FT_ATOMIC_STORE_LONG_RELAXED(r->start, value + r->step);
3296-
#else // the code above will work for GIL build but below is faster
3297-
if (r->len <= 0) {
3298-
// Jump over END_FOR instruction.
3299-
JUMPBY(oparg + 1);
3300-
DISPATCH();
3301-
}
3302-
long value = r->start;
3303-
r->start = value + r->step;
3304-
r->len--;
3305-
#endif
3294+
_PyRangeIter_SetLength(r, len - 1);
33063295
PyObject *res = PyLong_FromLong(value);
33073296
ERROR_IF(res == NULL, error);
33083297
next = PyStackRef_FromPyObjectSteal(res);
@@ -3312,17 +3301,10 @@ dummy_func(
33123301
op(_ITER_NEXT_RANGE_TIER_TWO, (iter -- iter, next)) {
33133302
_PyRangeIterObject *r = (_PyRangeIterObject *)PyStackRef_AsPyObjectBorrow(iter);
33143303
assert(Py_TYPE(r) == &PyRangeIter_Type);
3315-
#ifdef Py_GIL_DISABLED
3316-
long value = FT_ATOMIC_LOAD_LONG_RELAXED(r->start);
3317-
long len = _PyRangeIter_GetLength(r, value);
3304+
long value;
3305+
long len = _PyRangeIter_GetLengthAndStart(r, &value);
33183306
EXIT_IF(len <= 0);
3319-
FT_ATOMIC_STORE_LONG_RELAXED(r->start, value + r->step);
3320-
#else // the code above will work for GIL build but below is faster
3321-
EXIT_IF(r->len <= 0);
3322-
long value = r->start;
3323-
r->start = value + r->step;
3324-
r->len--;
3325-
#endif
3307+
_PyRangeIter_SetLength(r, len - 1);
33263308
PyObject *res = PyLong_FromLong(value);
33273309
ERROR_IF(res == NULL, error);
33283310
next = PyStackRef_FromPyObjectSteal(res);

Python/executor_cases.c.h

Lines changed: 3 additions & 13 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Python/generated_cases.c.h

Lines changed: 3 additions & 14 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Tools/cases_generator/analyzer.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -674,7 +674,8 @@ def has_error_without_pop(op: parser.CodeDef) -> bool:
674674
"JUMP_TO_LABEL",
675675
"restart_backoff_counter",
676676
"_Py_ReachedRecursionLimit",
677-
"_PyRangeIter_GetLength",
677+
"_PyRangeIter_GetLengthAndStart",
678+
"_PyRangeIter_SetLength",
678679
)
679680

680681
def find_stmt_start(node: parser.CodeDef, idx: int) -> lexer.Token:

0 commit comments

Comments
 (0)