Skip to content

GH-132554: Fix tier2 FOR_ITER implementation and optimizations #135137

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

Merged
merged 4 commits into from
Jun 5, 2025

Conversation

markshannon
Copy link
Member

@markshannon markshannon commented Jun 4, 2025

When adding virtual iterators, the tier 1 and tier 2 implementations of FOR_ITER diverged. I've already fixed a problem where the instrumented FOR_ITER differed from the normal one.

To prevent these problems happening again, this PR factors out the majority of FOR_ITER into a helper function for the 3 versions of FOR_ITER to share.

I've also added PyStackRef_ERROR to distinguish between errors and no result and remove the need for an additional out parameter for the helper function.

Also fixes a bug in the code generator where there are three or more output values, one is an unchanged input, one is a changed input and one is undefined.

@Fidget-Spinner
Copy link
Member

Can you check out the Windows JIT failures please? I'll review the PR after that.

@@ -353,7 +353,8 @@ PyAPI_FUNC(_PyStackRef) _PyFloat_FromDouble_ConsumeInputs(_PyStackRef left, _PyS
extern int _PyRunRemoteDebugger(PyThreadState *tstate);
#endif

_PyStackRef _PyForIter_NextWithIndex(PyObject *seq, _PyStackRef index);
_PyStackRef
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
_PyStackRef
PyAPI_FUNC(_PyStackRef)

op(_GET_ITER, (iterable -- iter, index_or_null)) {
if (sym_matches_type(iterable, &PyTuple_Type) || sym_matches_type(iterable, &PyList_Type)) {
iter = iterable;
index_or_null = sym_new_type(ctx, &PyLong_Type);
Copy link
Member

Choose a reason for hiding this comment

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

Hm, this is sort of weird. We don't have a symbol for "unboxed int" in the JIT, but it really doesn't feel correct to type this as int. Maybe leave as unknown and we can update our lattice with unboxed C types later? It's not like this information is being used yet, anyways.

Suggested change
index_or_null = sym_new_type(ctx, &PyLong_Type);
index_or_null = sym_new_unknown(ctx);

}
next = PyStackRef_FromPyObjectSteal(next_o);
JUMPBY(oparg + 1);
Copy link
Member

Choose a reason for hiding this comment

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

Can you add back the comment that this is skipping the END_FOR?

Suggested change
JUMPBY(oparg + 1);
// Jump forward by oparg, then skip the following END_FOR:
JUMPBY(oparg + 1);

}
JUMPBY(oparg + 1);
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
JUMPBY(oparg + 1);
// Jump forward by oparg, then skip the following END_FOR:
JUMPBY(oparg + 1);

Python/ceval.c Outdated
_PyErr_Clear(tstate);
}
else {
return PyStackRef_ERROR;
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
return PyStackRef_ERROR;
return PyStackRef_ERROR;

@brandtbucher
Copy link
Member

Confirmed that this fixed the pprint benchmarks locally. Just kicked off new benchmarks now.

@brandtbucher
Copy link
Member

27% slower... ;)

@markshannon markshannon merged commit b90ecea into python:main Jun 5, 2025
67 checks passed
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.

3 participants