Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

GH-130415: Use boolean guards to narrow types to values in the JIT #130659

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 13 commits into from
Mar 2, 2025
Prev Previous commit
Next Next commit
Add "truth" symbols
  • Loading branch information
brandtbucher committed Feb 27, 2025
commit 7929a57172550232acbcf41fbaa59e7f09e5b4b1
14 changes: 11 additions & 3 deletions 14 Include/internal/pycore_optimizer.h
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ typedef enum _JitSymType {
JIT_SYM_KNOWN_CLASS_TAG = 6,
JIT_SYM_KNOWN_VALUE_TAG = 7,
JIT_SYM_TUPLE_TAG = 8,
JIT_SYM_TRUTH_TAG = 9,
} JitSymType;

typedef struct _jit_opt_known_class {
Expand All @@ -198,12 +199,19 @@ typedef struct _jit_opt_tuple {
uint16_t items[MAX_SYMBOLIC_TUPLE_SIZE];
} JitOptTuple;

typedef struct {
uint8_t tag;
bool not;
uint16_t value;
} JitOptTruth;

typedef union _jit_opt_symbol {
uint8_t tag;
JitOptKnownClass cls;
JitOptKnownValue value;
JitOptKnownVersion version;
JitOptTuple tuple;
JitOptTruth truth;
} JitOptSymbol;


Expand Down Expand Up @@ -245,8 +253,8 @@ typedef struct _JitOptContext {

extern bool _Py_uop_sym_is_null(JitOptSymbol *sym);
extern bool _Py_uop_sym_is_not_null(JitOptSymbol *sym);
extern bool _Py_uop_sym_is_const(JitOptSymbol *sym);
extern PyObject *_Py_uop_sym_get_const(JitOptSymbol *sym);
extern bool _Py_uop_sym_is_const(JitOptContext *ctx, JitOptSymbol *sym);
extern PyObject *_Py_uop_sym_get_const(JitOptContext *ctx, JitOptSymbol *sym);
extern JitOptSymbol *_Py_uop_sym_new_unknown(JitOptContext *ctx);
extern JitOptSymbol *_Py_uop_sym_new_not_null(JitOptContext *ctx);
extern JitOptSymbol *_Py_uop_sym_new_type(
Expand All @@ -262,7 +270,7 @@ extern void _Py_uop_sym_set_type(JitOptContext *ctx, JitOptSymbol *sym, PyTypeOb
extern bool _Py_uop_sym_set_type_version(JitOptContext *ctx, JitOptSymbol *sym, unsigned int version);
extern void _Py_uop_sym_set_const(JitOptContext *ctx, JitOptSymbol *sym, PyObject *const_val);
extern bool _Py_uop_sym_is_bottom(JitOptSymbol *sym);
extern int _Py_uop_sym_truthiness(JitOptSymbol *sym);
extern int _Py_uop_sym_truthiness(JitOptContext *ctx, JitOptSymbol *sym);
extern PyTypeObject *_Py_uop_sym_get_type(JitOptSymbol *sym);
extern bool _Py_uop_sym_is_immortal(JitOptSymbol *sym);
extern JitOptSymbol *_Py_uop_sym_new_tuple(JitOptContext *ctx, int size, JitOptSymbol **args);
Expand Down
2 changes: 1 addition & 1 deletion 2 Python/optimizer_analysis.c
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,7 @@ optimize_to_bool(
*result_ptr = value;
return 1;
}
int truthiness = sym_truthiness(value);
int truthiness = sym_truthiness(ctx, value);
if (truthiness >= 0) {
PyObject *load = truthiness ? Py_True : Py_False;
REPLACE_OP(this_instr, _POP_TOP_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)load);
Expand Down
109 changes: 56 additions & 53 deletions 109 Python/optimizer_bytecodes.c
Original file line number Diff line number Diff line change
Expand Up @@ -198,11 +198,11 @@ dummy_func(void) {
// Case C:
res = sym_new_type(ctx, &PyFloat_Type);
}
else if (!sym_is_const(right)) {
else if (!sym_is_const(ctx, right)) {
// Case A or B... can't know without the sign of the RHS:
res = sym_new_unknown(ctx);
}
else if (_PyLong_IsNegative((PyLongObject *)sym_get_const(right))) {
else if (_PyLong_IsNegative((PyLongObject *)sym_get_const(ctx, right))) {
// Case B:
res = sym_new_type(ctx, &PyFloat_Type);
}
Expand All @@ -223,13 +223,13 @@ dummy_func(void) {
}

op(_BINARY_OP_ADD_INT, (left, right -- res)) {
if (sym_is_const(left) && sym_is_const(right) &&
if (sym_is_const(ctx, left) && sym_is_const(ctx, right) &&
sym_matches_type(left, &PyLong_Type) && sym_matches_type(right, &PyLong_Type))
{
assert(PyLong_CheckExact(sym_get_const(left)));
assert(PyLong_CheckExact(sym_get_const(right)));
PyObject *temp = _PyLong_Add((PyLongObject *)sym_get_const(left),
(PyLongObject *)sym_get_const(right));
assert(PyLong_CheckExact(sym_get_const(ctx, left)));
assert(PyLong_CheckExact(sym_get_const(ctx, right)));
PyObject *temp = _PyLong_Add((PyLongObject *)sym_get_const(ctx, left),
(PyLongObject *)sym_get_const(ctx, right));
if (temp == NULL) {
goto error;
}
Expand All @@ -244,13 +244,13 @@ dummy_func(void) {
}

op(_BINARY_OP_SUBTRACT_INT, (left, right -- res)) {
if (sym_is_const(left) && sym_is_const(right) &&
if (sym_is_const(ctx, left) && sym_is_const(ctx, right) &&
sym_matches_type(left, &PyLong_Type) && sym_matches_type(right, &PyLong_Type))
{
assert(PyLong_CheckExact(sym_get_const(left)));
assert(PyLong_CheckExact(sym_get_const(right)));
PyObject *temp = _PyLong_Subtract((PyLongObject *)sym_get_const(left),
(PyLongObject *)sym_get_const(right));
assert(PyLong_CheckExact(sym_get_const(ctx, left)));
assert(PyLong_CheckExact(sym_get_const(ctx, right)));
PyObject *temp = _PyLong_Subtract((PyLongObject *)sym_get_const(ctx, left),
(PyLongObject *)sym_get_const(ctx, right));
if (temp == NULL) {
goto error;
}
Expand All @@ -265,13 +265,13 @@ dummy_func(void) {
}

op(_BINARY_OP_MULTIPLY_INT, (left, right -- res)) {
if (sym_is_const(left) && sym_is_const(right) &&
if (sym_is_const(ctx, left) && sym_is_const(ctx, right) &&
sym_matches_type(left, &PyLong_Type) && sym_matches_type(right, &PyLong_Type))
{
assert(PyLong_CheckExact(sym_get_const(left)));
assert(PyLong_CheckExact(sym_get_const(right)));
PyObject *temp = _PyLong_Multiply((PyLongObject *)sym_get_const(left),
(PyLongObject *)sym_get_const(right));
assert(PyLong_CheckExact(sym_get_const(ctx, left)));
assert(PyLong_CheckExact(sym_get_const(ctx, right)));
PyObject *temp = _PyLong_Multiply((PyLongObject *)sym_get_const(ctx, left),
(PyLongObject *)sym_get_const(ctx, right));
if (temp == NULL) {
goto error;
}
Expand All @@ -286,14 +286,14 @@ dummy_func(void) {
}

op(_BINARY_OP_ADD_FLOAT, (left, right -- res)) {
if (sym_is_const(left) && sym_is_const(right) &&
if (sym_is_const(ctx, left) && sym_is_const(ctx, right) &&
sym_matches_type(left, &PyFloat_Type) && sym_matches_type(right, &PyFloat_Type))
{
assert(PyFloat_CheckExact(sym_get_const(left)));
assert(PyFloat_CheckExact(sym_get_const(right)));
assert(PyFloat_CheckExact(sym_get_const(ctx, left)));
assert(PyFloat_CheckExact(sym_get_const(ctx, right)));
PyObject *temp = PyFloat_FromDouble(
PyFloat_AS_DOUBLE(sym_get_const(left)) +
PyFloat_AS_DOUBLE(sym_get_const(right)));
PyFloat_AS_DOUBLE(sym_get_const(ctx, left)) +
PyFloat_AS_DOUBLE(sym_get_const(ctx, right)));
if (temp == NULL) {
goto error;
}
Expand All @@ -308,14 +308,14 @@ dummy_func(void) {
}

op(_BINARY_OP_SUBTRACT_FLOAT, (left, right -- res)) {
if (sym_is_const(left) && sym_is_const(right) &&
if (sym_is_const(ctx, left) && sym_is_const(ctx, right) &&
sym_matches_type(left, &PyFloat_Type) && sym_matches_type(right, &PyFloat_Type))
{
assert(PyFloat_CheckExact(sym_get_const(left)));
assert(PyFloat_CheckExact(sym_get_const(right)));
assert(PyFloat_CheckExact(sym_get_const(ctx, left)));
assert(PyFloat_CheckExact(sym_get_const(ctx, right)));
PyObject *temp = PyFloat_FromDouble(
PyFloat_AS_DOUBLE(sym_get_const(left)) -
PyFloat_AS_DOUBLE(sym_get_const(right)));
PyFloat_AS_DOUBLE(sym_get_const(ctx, left)) -
PyFloat_AS_DOUBLE(sym_get_const(ctx, right)));
if (temp == NULL) {
goto error;
}
Expand All @@ -330,14 +330,14 @@ dummy_func(void) {
}

op(_BINARY_OP_MULTIPLY_FLOAT, (left, right -- res)) {
if (sym_is_const(left) && sym_is_const(right) &&
if (sym_is_const(ctx, left) && sym_is_const(ctx, right) &&
sym_matches_type(left, &PyFloat_Type) && sym_matches_type(right, &PyFloat_Type))
{
assert(PyFloat_CheckExact(sym_get_const(left)));
assert(PyFloat_CheckExact(sym_get_const(right)));
assert(PyFloat_CheckExact(sym_get_const(ctx, left)));
assert(PyFloat_CheckExact(sym_get_const(ctx, right)));
PyObject *temp = PyFloat_FromDouble(
PyFloat_AS_DOUBLE(sym_get_const(left)) *
PyFloat_AS_DOUBLE(sym_get_const(right)));
PyFloat_AS_DOUBLE(sym_get_const(ctx, left)) *
PyFloat_AS_DOUBLE(sym_get_const(ctx, right)));
if (temp == NULL) {
goto error;
}
Expand All @@ -352,9 +352,9 @@ dummy_func(void) {
}

op(_BINARY_OP_ADD_UNICODE, (left, right -- res)) {
if (sym_is_const(left) && sym_is_const(right) &&
if (sym_is_const(ctx, left) && sym_is_const(ctx, right) &&
sym_matches_type(left, &PyUnicode_Type) && sym_matches_type(right, &PyUnicode_Type)) {
PyObject *temp = PyUnicode_Concat(sym_get_const(left), sym_get_const(right));
PyObject *temp = PyUnicode_Concat(sym_get_const(ctx, left), sym_get_const(ctx, right));
if (temp == NULL) {
goto error;
}
Expand All @@ -368,9 +368,9 @@ dummy_func(void) {

op(_BINARY_OP_INPLACE_ADD_UNICODE, (left, right -- )) {
JitOptSymbol *res;
if (sym_is_const(left) && sym_is_const(right) &&
if (sym_is_const(ctx, left) && sym_is_const(ctx, right) &&
sym_matches_type(left, &PyUnicode_Type) && sym_matches_type(right, &PyUnicode_Type)) {
PyObject *temp = PyUnicode_Concat(sym_get_const(left), sym_get_const(right));
PyObject *temp = PyUnicode_Concat(sym_get_const(ctx, left), sym_get_const(ctx, right));
if (temp == NULL) {
goto error;
}
Expand Down Expand Up @@ -512,8 +512,8 @@ dummy_func(void) {
op(_CHECK_ATTR_MODULE_PUSH_KEYS, (dict_version/2, owner -- owner, mod_keys)) {
(void)dict_version;
mod_keys = sym_new_not_null(ctx);
if (sym_is_const(owner)) {
PyObject *cnst = sym_get_const(owner);
if (sym_is_const(ctx, owner)) {
PyObject *cnst = sym_get_const(ctx, owner);
if (PyModule_CheckExact(cnst)) {
PyModuleObject *mod = (PyModuleObject *)cnst;
PyObject *dict = mod->md_dict;
Expand Down Expand Up @@ -546,8 +546,8 @@ dummy_func(void) {
attr = NULL;
if (this_instr[-1].opcode == _NOP) {
// Preceding _CHECK_ATTR_MODULE_PUSH_KEYS was removed: mod is const and dict is watched.
assert(sym_is_const(owner));
PyModuleObject *mod = (PyModuleObject *)sym_get_const(owner);
assert(sym_is_const(ctx, owner));
PyModuleObject *mod = (PyModuleObject *)sym_get_const(ctx, owner);
assert(PyModule_CheckExact(mod));
PyObject *dict = mod->md_dict;
PyObject *res = convert_global_to_const(this_instr, dict);
Expand Down Expand Up @@ -614,19 +614,19 @@ dummy_func(void) {
}

op(_CHECK_FUNCTION_VERSION, (func_version/2, callable, self_or_null, unused[oparg] -- callable, self_or_null, unused[oparg])) {
if (sym_is_const(callable) && sym_matches_type(callable, &PyFunction_Type)) {
assert(PyFunction_Check(sym_get_const(callable)));
if (sym_is_const(ctx, callable) && sym_matches_type(callable, &PyFunction_Type)) {
assert(PyFunction_Check(sym_get_const(ctx, callable)));
REPLACE_OP(this_instr, _CHECK_FUNCTION_VERSION_INLINE, 0, func_version);
this_instr->operand1 = (uintptr_t)sym_get_const(callable);
this_instr->operand1 = (uintptr_t)sym_get_const(ctx, callable);
}
sym_set_type(callable, &PyFunction_Type);
}

op(_CHECK_FUNCTION_EXACT_ARGS, (callable, self_or_null, unused[oparg] -- callable, self_or_null, unused[oparg])) {
assert(sym_matches_type(callable, &PyFunction_Type));
if (sym_is_const(callable)) {
if (sym_is_const(ctx, callable)) {
if (sym_is_null(self_or_null) || sym_is_not_null(self_or_null)) {
PyFunctionObject *func = (PyFunctionObject *)sym_get_const(callable);
PyFunctionObject *func = (PyFunctionObject *)sym_get_const(ctx, callable);
PyCodeObject *co = (PyCodeObject *)func->func_code;
if (co->co_argcount == oparg + !sym_is_null(self_or_null)) {
REPLACE_OP(this_instr, _NOP, 0 ,0);
Expand Down Expand Up @@ -827,36 +827,39 @@ dummy_func(void) {
}

op(_GUARD_IS_TRUE_POP, (flag -- )) {
if (sym_is_const(flag)) {
PyObject *value = sym_get_const(flag);
if (sym_is_const(ctx, flag)) {
PyObject *value = sym_get_const(ctx, flag);
assert(value != NULL);
eliminate_pop_guard(this_instr, value != Py_True);
}
sym_set_const(flag, Py_True);
}

op(_GUARD_IS_FALSE_POP, (flag -- )) {
if (sym_is_const(flag)) {
PyObject *value = sym_get_const(flag);
if (sym_is_const(ctx, flag)) {
PyObject *value = sym_get_const(ctx, flag);
assert(value != NULL);
eliminate_pop_guard(this_instr, value != Py_False);
}
sym_set_const(flag, Py_False);
}

op(_GUARD_IS_NONE_POP, (flag -- )) {
if (sym_is_const(flag)) {
PyObject *value = sym_get_const(flag);
if (sym_is_const(ctx, flag)) {
PyObject *value = sym_get_const(ctx, flag);
assert(value != NULL);
eliminate_pop_guard(this_instr, !Py_IsNone(value));
}
else if (sym_has_type(flag)) {
assert(!sym_matches_type(flag, &_PyNone_Type));
eliminate_pop_guard(this_instr, true);
}
sym_set_const(flag, Py_None);
}

op(_GUARD_IS_NOT_NONE_POP, (flag -- )) {
if (sym_is_const(flag)) {
PyObject *value = sym_get_const(flag);
if (sym_is_const(ctx, flag)) {
PyObject *value = sym_get_const(ctx, flag);
assert(value != NULL);
eliminate_pop_guard(this_instr, Py_IsNone(value));
}
Expand Down
Loading
Morty Proxy This is a proxified and sanitized view of the page, visit original site.