8000 Allow range starts other than zero · faster-cpython/cpython@108908b · GitHub
[go: up one dir, main page]

Skip to content

Commit 108908b

Browse files
committed
Allow range starts other than zero
1 parent 76f1814 commit 108908b

File tree

9 files changed

+54
-11
lines changed

9 files changed

+54
-11
lines changed

Include/internal/pycore_range.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ typedef struct {
1717

1818
// Does this range have start == 0, step == 1 and step in compact int range?
1919
int _PyRange_IsSimpleCompact(PyObject *range);
20+
Py_ssize_t _PyRange_GetStartIfCompact(PyObject *range);
2021
Py_ssize_t _PyRange_GetStopIfCompact(PyObject *range);
2122

2223
#ifdef __cplusplus

Include/internal/pycore_stackref.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,14 @@ PyStackRef_IsTaggedInt(_PyStackRef ref)
101101
return (ref.index & 1) == 1;
102102
}
103103

104+
static inline bool
105+
PyStackRef_TaggedIntLessThan(_PyStackRef a, _PyStackRef b)
106+
{
107+
assert(PyStackRef_IsTaggedInt(a));
108+
assert(PyStackRef_IsTaggedInt(b));
109+
return ((uintptr_t)a.bits) < ((uintptr_t)b.bits);
110+
}
111+
104112
static inline PyObject * 8000
105113
_PyStackRef_AsPyObjectBorrow(_PyStackRef ref, const char *filename, int linenumber)
106114
{
@@ -274,6 +282,14 @@ PyStackRef_IncrementTaggedIntNoOverflow(_PyStackRef ref)
274282
return (_PyStackRef){ .bits = ref.bits + 4 };
275283
}
276284

285+
static inline bool
286+
PyStackRef_TaggedIntLessThan(_PyStackRef a, _PyStackRef b)
287+
{
288+
assert(PyStackRef_IsTaggedInt(a));
289+
assert(PyStackRef_IsTaggedInt(b));
290+
return ((uintptr_t)a.bits) < ((uintptr_t)b.bits);
291+
}
292+
277293
#define PyStackRef_IsDeferredOrTaggedInt(ref) (((ref).bits & Py_TAG_REFCNT) != 0)
278294

279295
extern _PyStackRef PyStackRef_BoxInt(_PyStackRef i);

Objects/rangeobject.c

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -160,20 +160,29 @@ int
160160
_PyRange_IsSimpleCompact(PyObject *range) {
161161
assert(PyRange_Check(range));
162162
rangeobject *r = (rangeobject*)range;
163-
if (r->start == _PyLong_GetZero() && r->step == _PyLong_GetOne() &&
164-
_PyLong_IsNonNegativeCompact((PyLongObject *)r->stop)
163+
if (_PyLong_IsCompact((PyLongObject *)r->start) &&
164+
_PyLong_IsCompact((PyLongObject *)r->stop) &&
165+
r->step == _PyLong_GetOne()
165166
) {
166167
return 1;
167168
}
168169
return 0;
169170
}
170171

172+
Py_ssize_t
173+
_PyRange_GetStartIfCompact(PyObject *range) {
174+
assert(PyRange_Check(range));
175+
rangeobject *r = (rangeobject*)range;
176+
assert(_PyLong_IsCompact((PyLongObject *)r->start));
177+
return _PyLong_CompactValue((PyLongObject *)r->start);
178+
}
179+
171180
Py_ssize_t
172181
_PyRange_GetStopIfCompact(PyObject *range) {
173182
assert(PyRange_Check(range));
174183
rangeobject *r = (rangeobject*)range;
175-
assert(_PyLong_IsNonNegativeCompact((PyLongObject *)r->stop));
176-
return _PyLong_GetNonNegativeCompactValue((PyLongObject *)r->stop);
184+
assert(_PyLong_IsCompact((PyLongObject *)r->stop));
185+
return _PyLong_CompactValue((PyLongObject *)r->stop);
177186
}
178187

179188
PyDoc_STRVAR(range_doc,

Python/bytecodes.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3080,10 +3080,11 @@ dummy_func(
30803080
else {
30813081
PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iterable);
30823082
if (tp == &PyRange_Type && _PyRange_IsSimpleCompact(iter_o)) {
3083+
Py_ssize_t start = _PyRange_GetStartIfCompact(iter_o);
30833084
Py_ssize_t stop = _PyRange_GetStopIfCompact(iter_o);
30843085
PyStackRef_CLOSE(iterable);
30853086
iter = PyStackRef_TagInt(stop);
3086-
index_or_null = PyStackRef_TagInt(0);
3087+
index_or_null = PyStackRef_TagInt(start);
30873088
}
30883089
else {
30893090
iter_o = PyObject_GetIter(iter_o);
@@ -3423,7 +3424,7 @@ dummy_func(
34233424
}
34243425

34253426
replaced op(_ITER_JUMP_RANGE, (iter, null_or_index -- iter, null_or_index)) {
3426-
if (PyStackRef_Is(iter, null_or_index)) {
3427+
if (!PyStackRef_TaggedIntLessThan(null_or_index, iter)) {
34273428
// Jump over END_FOR instruction.
34283429
JUMPBY(oparg + 1);
34293430
DISPATCH();
@@ -3432,7 +3433,7 @@ dummy_func(
34323433

34333434
// Only used by Tier 2
34343435
op(_GUARD_NOT_EXHAUSTED_RANGE, (iter, null_or_index -- iter, null_or_index)) {
3435-
EXIT_IF(PyStackRef_Is(iter, null_or_index));
3436+
EXIT_IF(!PyStackRef_TaggedIntLessThan(null_or_index, iter));
34363437
}
34373438

34383439
op(_ITER_NEXT_RANGE, (iter, null_or_index -- iter, null_or_index, next)) {

Python/executor_cases.c.h

Lines changed: 5 additions & 2 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: 5 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Python/specialize.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2912,6 +2912,7 @@ _Py_Specialize_ForIter(_PyStackRef iter, _PyStackRef null_or_index, _Py_CODEUNIT
29122912

29132913
if (PyStackRef_IsNull(null_or_index)) {
29142914
#ifdef Py_GIL_DISABLED
2915+
PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter);
29152916
// Only specialize for uniquely referenced iterators, so that we know
29162917
// they're only referenced by this one thread. This is more limiting
29172918
// than we need (even `it = iter(mylist); for item in it:` won't get

Python/stackrefs.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,14 @@ _PyStackRef PyStackRef_TagInt(intptr_t i)
202202
return (_PyStackRef){ .index = (i << 1) + 1 };
203203
}
204204

205+
bool
206+
PyStackRef_TaggedIntLessThan(_PyStackRef a, _PyStackRef b)
207+
{
208+
assert(PyStackRef_IsTaggedInt(a));
209+
assert(PyStackRef_IsTaggedInt(b));
210+
return a.bits < b.bits;
211+
}
212+
205213
intptr_t
206214
PyStackRef_UntagInt(_PyStackRef i)
207215
{

Tools/cases_generator/analyzer.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -685,6 +685,7 @@ def has_error_without_pop(op: parser.CodeDef) -> bool:
685685
"_PyRange_GetStopIfCompact",
686686
"PyStackRef_BoxInt",
687687
"PyStackRef_TYPE",
688+
"PyStackRef_TaggedIntLessThan",
688689
)
689690

690691

0 commit comments

Comments
 (0)
0