Skip to content

gh-130480: Move duplicate LOAD_SMALL_INT optimization from codegen to CFG #130481

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 5 commits into from
Mar 14, 2025

Conversation

WolframAlph
Copy link
Contributor

@WolframAlph WolframAlph commented Feb 23, 2025

if (maybe_instr_make_load_smallint(inst, constant, consts, const_cache)) {
assert(inst->i_opcode == LOAD_SMALL_INT);
}
Py_DECREF(constant);
Copy link
Contributor Author

@WolframAlph WolframAlph Feb 23, 2025

Choose a reason for hiding this comment

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

For small ints this is effectively no-op as they are immortal, but it helps readability because get_const_value returns new reference.

@markshannon
Copy link
Member

Overall, I think this change isn't worthwhile. It doesn't seem to simplify the code at all, but it will slow down the compiler by introducing extra values into the constant array, which then need removing again.

@WolframAlph
Copy link
Contributor Author

@markshannon are we ok with having this logic in 2 places then? Also what is your take on #130016?

@markshannon
Copy link
Member

What logic in two places?
Codegen emits unoptimized instructions, the cfg optimize optimizes them. I don't see any change to that in this PR.

@WolframAlph
Copy link
Contributor Author

@markshannon this:

cpython/Python/flowgraph.c

Lines 1414 to 1422 in 8058390

if (PyLong_CheckExact(newconst)) {
int overflow;
long val = PyLong_AsLongAndOverflow(newconst, &overflow);
if (!overflow && _PY_IS_SMALL_INT(val)) {
assert(_Py_IsImmortal(newconst));
INSTR_SET_OP1(instr, LOAD_SMALL_INT, (int)val);
return SUCCESS;
}
}

&&

cpython/Python/codegen.c

Lines 284 to 291 in 8058390

if (PyLong_CheckExact(o)) {
int overflow;
long val = PyLong_AsLongAndOverflow(o, &overflow);
if (!overflow && _PY_IS_SMALL_INT(val)) {
ADDOP_I(c, loc, LOAD_SMALL_INT, val);
return SUCCESS;
}
}

@WolframAlph WolframAlph changed the title gh-130480: Move LOAD_SMALL_INT optimization from codegen to CFG gh-130480: Move duplicate LOAD_SMALL_INT optimization from codegen to CFG Mar 13, 2025
@WolframAlph
Copy link
Contributor Author

@iritkatriel can I ask you to review?

@@ -1584,7 +1587,8 @@ async def async_def():
Stack size: \\d+
Flags: OPTIMIZED, NEWLOCALS, COROUTINE
Constants:
0: None
0: 1
1: None
Copy link
Member

Choose a reason for hiding this comment

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

Why are the constants [1, None]? I thought we always have None in index 0 when there is no docstring.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

LOAD_CONST 0 (1) is added as the first constant, LOAD_CONST 1 (None) is added as the second constant by _PyCodegen_AddReturnAtEnd. Currently there is 1 slot that is always preserved for constant (in case it is docstring) at index 0. 1 is used constant, so it makes to the final co_consts list, and we have 2 elements in it. Since 1 came first (therefore has lower index), it is first in the final co_consts.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

There is #130016 that addresses unused docstring slot which causes confusion.

@iritkatriel iritkatriel added skip news interpreter-core (Objects, Python, Grammar, and Parser dirs) labels Mar 14, 2025
/* Does not steal reference to "newconst" */
static bool
maybe_instr_make_load_smallint(cfg_instr *instr, PyObject *newconst,
PyObject *consts, PyObject *const_cache)
{
if (PyLong_CheckExact(newconst)) {
int overflow;
long val = PyLong_AsLongAndOverflow(newconst, &overflow);
Copy link
Member

Choose a reason for hiding this comment

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

The return value of PyLong_AsLongAndOverflow needs to be checked for error. Does this mean that maybe_instr_make_load_smallint should also return int, with -1 for error?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The return value of PyLong_AsLongAndOverflow needs to be checked for error

I think it was not checked before due to PyLong_CheckExact guard, but I agree we should check it anyway. This is by the way not the only place where this pattern occurs, for example:

else if (PyLong_CheckExact(obj)) {
int long_overflow;
value = PyLong_AsLongAndOverflow(obj, &long_overflow);
if (long_overflow)
goto overflow;
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

@WolframAlph WolframAlph requested a review from iritkatriel March 14, 2025 19:07
Comment on lines +2066 to +2068
if (res < 0) {
return ERROR;
}
Copy link
Member

Choose a reason for hiding this comment

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

RETURN_IF_ERROR(res);

Copy link
Contributor Author

@WolframAlph WolframAlph Mar 14, 2025

Choose a reason for hiding this comment

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

maybe_instr_make_load_smallint does not return SUCCESS nor ERROR explicitly, so I am not sure we should do it like this.

Copy link
Member

Choose a reason for hiding this comment

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

ok.

@iritkatriel iritkatriel merged commit 55815a6 into python:main Mar 14, 2025
41 checks passed
plashchynski pushed a commit to plashchynski/cpython that referenced this pull request Mar 17, 2025
seehwan pushed a commit to seehwan/cpython that referenced this pull request Apr 16, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
interpreter-core (Objects, Python, Grammar, and Parser dirs) skip news
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants