Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
9466417
Skip refcounting where possible for common float ops
Fidget-Spinner May 23, 2025
ad03b1e
Add for common list ops
Fidget-Spinner May 23, 2025
7f90d0c
Fix test, rename
Fidget-Spinner May 23, 2025
a42b434
Remove list optimizations to minimize PR
Fidget-Spinner May 23, 2025
f456740
📜🤖 Added by blurb_it.
blurb-it[bot] May 23, 2025
16f9dee
Merge remote-tracking branch 'upstream/main' into decref_elimination_…
Fidget-Spinner May 27, 2025
5c429b6
Rename things to make things clearer
Fidget-Spinner May 27, 2025
1535133
Revert "Rename things to make things clearer"
Fidget-Spinner May 27, 2025
8f62067
Massive refactor from JitOptSymbol to JitRef
Fidget-Spinner May 28, 2025
a158835
refactor more
Fidget-Spinner May 28, 2025
e77f842
fix debug build
Fidget-Spinner May 28, 2025
01004c2
lint
Fidget-Spinner May 28, 2025
24f98d5
Merge remote-tracking branch 'upstream/main' into decref_elimination_…
Fidget-Spinner May 28, 2025
0189413
fix upstream
Fidget-Spinner May 28, 2025
4a386bf
reduce diff
Fidget-Spinner May 28, 2025
ac034a0
fix for FT
Fidget-Spinner May 28, 2025
b6e467e
fix failing tests
Fidget-Spinner May 28, 2025
3a3fa9d
Fix for disabled GIL
Fidget-Spinner May 29, 2025
ab1ad9c
fix on FT again
Fidget-Spinner May 29, 2025
5d82489
Try fix windows
Fidget-Spinner May 29, 2025
4d9a68e
Apply code review suggestions from Tomas
Fidget-Spinner Jun 4, 2025
2bbd47a
call the functions sym instead of ref
Fidget-Spinner Jun 4, 2025
2d779c4
rename jitref functions
Fidget-Spinner Jun 4, 2025
b74e160
Address review
Fidget-Spinner Jun 4, 2025
3ebcc20
Update comment
Fidget-Spinner Jun 4, 2025
673d5c8
Merge remote-tracking branch 'upstream/main' into decref_elimination_…
Fidget-Spinner Jun 17, 2025
914f1ff
Fix changes from upstream (no more casts)
Fidget-Spinner Jun 17, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Rename things to make things clearer
  • Loading branch information
Fidget-Spinner committed May 27, 2025
commit 5c429b60831de05ecb3ba21e9ec3dcee50de724f
18 changes: 8 additions & 10 deletions Include/internal/pycore_optimizer.h
Original file line number Diff line number Diff line change
Expand Up @@ -180,8 +180,8 @@ typedef enum _JitSymType {
JIT_SYM_TRUTHINESS_TAG = 9,
} JitSymType;

#define DONT_SKIP_REFCOUNT 0
#define SKIP_REFCOUNT 1
#define WE_MIGHT_BE_THE_ONLY_STRONG_REF 0
#define SOMEONE_ELSE_HAS_A_VALID_STRONG_REF 1

typedef struct _jit_opt_known_class {
struct {
Expand Down Expand Up @@ -231,11 +231,9 @@ typedef struct {
typedef union _jit_opt_symbol {
struct {
uint8_t tag;
// Whether this object skips refcount on the stack
// (using the _PyStackRef API), or not.
// 0 - normal refcounting
// 1 - skip refcounting
int8_t skip_refcount;
// Whether this object has a strong reference
// being held to it by someone else.
int8_t strong_ref_held_by_someone_else;
};
JitOptKnownClass cls;
JitOptKnownValue value;
Expand Down Expand Up @@ -308,9 +306,9 @@ extern JitOptSymbol *_Py_uop_sym_tuple_getitem(JitOptContext *ctx, JitOptSymbol
extern int _Py_uop_sym_tuple_length(JitOptSymbol *sym);
extern JitOptSymbol *_Py_uop_sym_new_truthiness(JitOptContext *ctx, JitOptSymbol *value, bool truthy);

extern void _Py_uop_sym_set_dont_skip_refcount(JitOptContext *ctx, JitOptSymbol *sym);
extern bool _Py_uop_sym_is_skip_refcount(JitOptContext *ctx, JitOptSymbol *sym);
extern void _Py_uop_sym_set_skip_refcount(JitOptContext *ctx, JitOptSymbol *sym);
extern void _Py_uop_sym_set_strong_ref_might_be_this_sym(JitOptContext *ctx, JitOptSymbol *sym);
extern bool _Py_uop_sym_is_strong_ref_held_by_someone_else(JitOptContext *ctx, JitOptSymbol *sym);
extern void _Py_uop_sym_set_strong_ref_is_held_by_someone_else(JitOptContext *ctx, JitOptSymbol *sym);

extern void _Py_uop_abstractcontext_init(JitOptContext *ctx);
extern void _Py_uop_abstractcontext_fini(JitOptContext *ctx);
Expand Down
6 changes: 3 additions & 3 deletions Python/optimizer_analysis.c
Original file line number Diff line number Diff line change
Expand Up @@ -342,9 +342,9 @@ remove_globals(_PyInterpreterFrame *frame, _PyUOpInstruction *buffer,
#define sym_tuple_length _Py_uop_sym_tuple_length
#define sym_is_immortal _Py_uop_sym_is_immortal
#define sym_new_truthiness _Py_uop_sym_new_truthiness
#define sym_set_skip_refcount _Py_uop_sym_set_skip_refcount
#define sym_set_dont_skip_refcount _Py_uop_sym_set_dont_skip_refcount
#define sym_is_skip_refcount _Py_uop_sym_is_skip_refcount
#define sym_set_strong_ref_is_held_by_someone_else _Py_uop_sym_set_strong_ref_is_held_by_someone_else
#define sym_set_strong_ref_might_be_this_sym _Py_uop_sym_set_strong_ref_might_be_this_sym
#define sym_is_strong_ref_held_by_someone_else _Py_uop_sym_is_strong_ref_held_by_someone_else

static int
optimize_to_bool(
Expand Down
14 changes: 7 additions & 7 deletions Python/optimizer_bytecodes.c
Original file line number Diff line number Diff line change
Expand Up @@ -80,24 +80,24 @@ dummy_func(void) {
if (sym_is_null(value)) {
ctx->done = true;
}
sym_set_dont_skip_refcount(ctx, value);
sym_set_strong_ref_might_be_this_sym(ctx, value);
}

op(_LOAD_FAST, (-- value)) {
value = GETLOCAL(oparg);
sym_set_dont_skip_refcount(ctx, value);
sym_set_strong_ref_might_be_this_sym(ctx, value);
}

op(_LOAD_FAST_BORROW, (-- value)) {
value = GETLOCAL(oparg);
sym_set_skip_refcount(ctx, value);
sym_set_strong_ref_is_held_by_someone_else(ctx, value);
}

op(_LOAD_FAST_AND_CLEAR, (-- value)) {
value = GETLOCAL(oparg);
JitOptSymbol *temp = sym_new_null(ctx);
GETLOCAL(oparg) = temp;
sym_set_dont_skip_refcount(ctx, value);
sym_set_strong_ref_might_be_this_sym(ctx, value);
}

op(_STORE_FAST, (value --)) {
Expand Down Expand Up @@ -301,7 +301,7 @@ dummy_func(void) {
res = sym_new_type(ctx, &PyFloat_Type);
}
// TODO (gh-134584): Move this to the optimizer generator.
if (sym_is_skip_refcount(ctx, left) && sym_is_skip_refcount(ctx, right)) {
if (sym_is_strong_ref_held_by_someone_else(ctx, left) && sym_is_strong_ref_held_by_someone_else(ctx, right)) {
REPLACE_OP(this_instr, op_without_decref_inputs[opcode], oparg, 0);
}
}
Expand All @@ -325,7 +325,7 @@ dummy_func(void) {
res = sym_new_type(ctx, &PyFloat_Type);
}
// TODO (gh-134584): Move this to the optimizer generator.
Copy link
Member

Choose a reason for hiding this comment

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

I don't think we want to do this "automatically". What we do want to do is to move almost all the Py_DECREFs into a few ops like POP_TOP and "manually" optimize those few ops.

Copy link
Member Author

Choose a reason for hiding this comment

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

I put a comment and said to refactor this.

if (sym_is_skip_refcount(ctx, left) && sym_is_skip_refcount(ctx, right)) {
if (sym_is_strong_ref_held_by_someone_else(ctx, left) && sym_is_strong_ref_held_by_someone_else(ctx, right)) {
REPLACE_OP(this_instr, op_without_decref_inputs[opcode], oparg, 0);
}
}
Expand All @@ -349,7 +349,7 @@ dummy_func(void) {
res = sym_new_type(ctx, &PyFloat_Type);
}
// TODO (gh-134584): Move this to the optimizer generator.
if (sym_is_skip_refcount(ctx, left) && sym_is_skip_refcount(ctx, right)) {
if (sym_is_strong_ref_held_by_someone_else(ctx, left) && sym_is_strong_ref_held_by_someone_else(ctx, right)) {
REPLACE_OP(this_instr, op_without_decref_inputs[opcode], oparg, 0);
}
}
Expand Down
14 changes: 7 additions & 7 deletions Python/optimizer_cases.c.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

31 changes: 16 additions & 15 deletions Python/optimizer_symbols.c
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ sym_new(JitOptContext *ctx)
}
ctx->t_arena.ty_curr_number++;
self->tag = JIT_SYM_UNKNOWN_TAG;
self->skip_refcount = DONT_SKIP_REFCOUNT;
self->strong_ref_held_by_someone_else = WE_MIGHT_BE_THE_ONLY_STRONG_REF;
return self;
}

Expand All @@ -109,7 +109,7 @@ static void make_const(JitOptSymbol *sym, PyObject *val)
sym->value.value = Py_NewRef(val);
// Constants don't need to be refcounted, as they are always
// kept alive by co_consts.
sym->skip_refcount = SKIP_REFCOUNT;
sym->strong_ref_held_by_someone_else = SOMEONE_ELSE_HAS_A_VALID_STRONG_REF;
}

static inline void
Expand Down Expand Up @@ -386,22 +386,23 @@ _Py_uop_sym_set_non_null(JitOptContext *ctx, JitOptSymbol *sym)
}

void
_Py_uop_sym_set_skip_refcount(JitOptContext *ctx, JitOptSymbol *sym)
_Py_uop_sym_set_strong_ref_is_held_by_someone_else(JitOptContext *ctx, JitOptSymbol *sym)
{
sym->skip_refcount = SKIP_REFCOUNT;
sym->strong_ref_held_by_someone_else = SOMEONE_ELSE_HAS_A_VALID_STRONG_REF;
}

void
_Py_uop_sym_set_dont_skip_refcount(JitOptContext *ctx, JitOptSymbol *sym)
_Py_uop_sym_set_strong_ref_might_be_this_sym(JitOptContext *ctx, JitOptSymbol *sym)
{
sym->skip_refcount = DONT_SKIP_REFCOUNT;
sym->strong_ref_held_by_someone_else = WE_MIGHT_BE_THE_ONLY_STRONG_REF;
}

bool
_Py_uop_sym_is_skip_refcount(JitOptContext *ctx, JitOptSymbol *sym)
_Py_uop_sym_is_strong_ref_held_by_someone_else(JitOptContext *ctx, JitOptSymbol *sym)
{
assert(sym->skip_refcount == SKIP_REFCOUNT || sym->skip_refcount == DONT_SKIP_REFCOUNT);
return sym->skip_refcount == SKIP_REFCOUNT;
assert(sym->strong_ref_held_by_someone_else == SOMEONE_ELSE_HAS_A_VALID_STRONG_REF ||
sym->strong_ref_held_by_someone_else == WE_MIGHT_BE_THE_ONLY_STRONG_REF);
return sym->strong_ref_held_by_someone_else == SOMEONE_ELSE_HAS_A_VALID_STRONG_REF;
}


Expand Down Expand Up @@ -794,7 +795,7 @@ _Py_uop_symbols_test(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(ignored))
if (sym == NULL) {
goto fail;
}
TEST_PREDICATE(!_Py_uop_sym_is_skip_refcount(ctx, sym), "top is refcounted");
TEST_PREDICATE(!_Py_uop_sym_is_strong_ref_held_by_someone_else(ctx, sym), "top is refcounted");
TEST_PREDICATE(!_Py_uop_sym_is_null(sym), "top is NULL");
TEST_PREDICATE(!_Py_uop_sym_is_not_null(sym), "top is not NULL");
TEST_PREDICATE(!_Py_uop_sym_matches_type(sym, &PyLong_Type), "top matches a type");
Expand Down Expand Up @@ -843,7 +844,7 @@ _Py_uop_symbols_test(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(ignored))
goto fail;
}
_Py_uop_sym_set_const(ctx, sym, val_42);
TEST_PREDICATE(_Py_uop_sym_is_skip_refcount(ctx, sym), "42 isn't refcounted");
TEST_PREDICATE(_Py_uop_sym_is_strong_ref_held_by_someone_else(ctx, sym), "42 isn't refcounted");
TEST_PREDICATE(_Py_uop_sym_truthiness(ctx, sym) == 1, "bool(42) is not True");
TEST_PREDICATE(!_Py_uop_sym_is_null(sym), "42 is NULL");
TEST_PREDICATE(_Py_uop_sym_is_not_null(sym), "42 isn't not NULL");
Expand Down Expand Up @@ -876,12 +877,12 @@ _Py_uop_symbols_test(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(ignored))
if (sym == NULL) {
goto fail;
}
TEST_PREDICATE(!_Py_uop_sym_is_skip_refcount(ctx, sym), "type should be refcounted");
_Py_uop_sym_set_skip_refcount(ctx, sym);
TEST_PREDICATE(_Py_uop_sym_is_skip_refcount(ctx, sym), "type should not be refcounted");
TEST_PREDICATE(!_Py_uop_sym_is_strong_ref_held_by_someone_else(ctx, sym), "type should be refcounted");
_Py_uop_sym_set_strong_ref_is_held_by_someone_else(ctx, sym);
TEST_PREDICATE(_Py_uop_sym_is_strong_ref_held_by_someone_else(ctx, sym), "type should not be refcounted");

sym = _Py_uop_sym_new_const(ctx, Py_None);
TEST_PREDICATE(_Py_uop_sym_is_skip_refcount(ctx, sym), "None should not be refcounted");
TEST_PREDICATE(_Py_uop_sym_is_strong_ref_held_by_someone_else(ctx, sym), "None should not be refcounted");
TEST_PREDICATE(_Py_uop_sym_truthiness(ctx, sym) == 0, "bool(None) is not False");
sym = _Py_uop_sym_new_const(ctx, Py_False);
TEST_PREDICATE(_Py_uop_sym_truthiness(ctx, sym) == 0, "bool(False) is not False");
Expand Down
Loading