From 9696b6755e78ecd44d84a5cfe65922df166e8669 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Tue, 27 Feb 2024 13:42:01 -0800 Subject: [PATCH 01/14] Reorganize flag bits --- Include/internal/pycore_optimizer.h | 1 + Python/optimizer_symbols.c | 47 ++++++++++++++--------------- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/Include/internal/pycore_optimizer.h b/Include/internal/pycore_optimizer.h index 425bd693fac53d..e7da68d13f2247 100644 --- a/Include/internal/pycore_optimizer.h +++ b/Include/internal/pycore_optimizer.h @@ -27,6 +27,7 @@ extern PyTypeObject _PyUOpExecutor_Type; extern PyTypeObject _PyUOpOptimizer_Type; /* Symbols */ +/* See explanation in optimizer_symbols.c */ struct _Py_UopsSymbol { int flags; diff --git a/Python/optimizer_symbols.c b/Python/optimizer_symbols.c index 794d73733f85a7..981831f249df4a 100644 --- a/Python/optimizer_symbols.c +++ b/Python/optimizer_symbols.c @@ -10,11 +10,26 @@ #include #include +/* Symbols + ======= + + See the diagram at + https://github.com/faster-cpython/ideas/blob/main/3.13/redundancy_eliminator.md + + We represent the nodes in the diagram as follows + (the flag bits are only defined in optimizer_symbols.c): + - Top: no flag bits, typ and const_val are NULL. + - NULL: IS_NULL flag set, type and const_val NULL. + - Not NULL: NOT_NULL flag set, type and const_val NULL. + - None/not None: not used. (None could be represented as any other constant.) + - Known type: NOT_NULL flag set and typ set; const_val is NULL. + - Known constant: NOT_NULL flag set, type set, const_val set. + - Bottom: IS_NULL and NOT_NULL flags set, type and const_val NULL. + */ + // Flags for below. -#define KNOWN 1 << 0 -#define TRUE_CONST 1 << 1 -#define IS_NULL 1 << 2 -#define NOT_NULL 1 << 3 +#define IS_NULL 1 << 0 +#define NOT_NULL 1 << 1 #ifdef Py_DEBUG static inline int get_lltrace(void) { @@ -59,35 +74,27 @@ sym_set_flag(_Py_UopsSymbol *sym, int flag) sym->flags |= flag; } -static inline bool -sym_has_flag(_Py_UopsSymbol *sym, int flag) -{ - return (sym->flags & flag) != 0; -} - bool _Py_uop_sym_is_not_null(_Py_UopsSymbol *sym) { - return (sym->flags & (IS_NULL | NOT_NULL)) == NOT_NULL; + return sym->flags == NOT_NULL; } bool _Py_uop_sym_is_null(_Py_UopsSymbol *sym) { - return (sym->flags & (IS_NULL | NOT_NULL)) == IS_NULL; + return sym->flags == IS_NULL; } bool _Py_uop_sym_is_const(_Py_UopsSymbol *sym) { - return (sym->flags & TRUE_CONST) != 0; + return sym->const_val != NULL; } PyObject * _Py_uop_sym_get_const(_Py_UopsSymbol *sym) { - assert(_Py_uop_sym_is_const(sym)); - assert(sym->const_val); return sym->const_val; } @@ -96,7 +103,6 @@ _Py_uop_sym_set_type(_Py_UopsSymbol *sym, PyTypeObject *tp) { assert(PyType_Check(tp)); sym->typ = tp; - sym_set_flag(sym, KNOWN); sym_set_flag(sym, NOT_NULL); } @@ -104,7 +110,6 @@ void _Py_uop_sym_set_null(_Py_UopsSymbol *sym) { sym_set_flag(sym, IS_NULL); - sym_set_flag(sym, KNOWN); } @@ -121,7 +126,6 @@ _Py_uop_sym_new_not_null(_Py_UOpsContext *ctx) if (res == NULL) { return NULL; } - sym_set_flag(res, KNOWN); sym_set_flag(res, NOT_NULL); return res; } @@ -148,8 +152,6 @@ _Py_uop_sym_new_const(_Py_UOpsContext *ctx, PyObject *const_val) return NULL; } _Py_uop_sym_set_type(temp, Py_TYPE(const_val)); - sym_set_flag(temp, TRUE_CONST); - sym_set_flag(temp, KNOWN); sym_set_flag(temp, NOT_NULL); return temp; } @@ -168,10 +170,7 @@ _Py_uop_sym_new_null(_Py_UOpsContext *ctx) bool _Py_uop_sym_matches_type(_Py_UopsSymbol *sym, PyTypeObject *typ) { - assert(typ == NULL || PyType_Check(typ)); - if (!sym_has_flag(sym, KNOWN)) { - return false; - } + assert(typ != NULL && PyType_Check(typ)); return sym->typ == typ; } From cd120a4ffe3fa0536acb343dd19b7565aecd3779 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Tue, 27 Feb 2024 13:53:13 -0800 Subject: [PATCH 02/14] Fix top/bottom tests (bottom has all properties off) --- Python/optimizer_symbols.c | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/Python/optimizer_symbols.c b/Python/optimizer_symbols.c index 981831f249df4a..46181d3d689ce9 100644 --- a/Python/optimizer_symbols.c +++ b/Python/optimizer_symbols.c @@ -112,6 +112,12 @@ _Py_uop_sym_set_null(_Py_UopsSymbol *sym) sym_set_flag(sym, IS_NULL); } +void +_Py_uop_sym_set_non_null(_Py_UopsSymbol *sym) +{ + sym_set_flag(sym, NOT_NULL); +} + _Py_UopsSymbol * _Py_uop_sym_new_unknown(_Py_UOpsContext *ctx) @@ -276,15 +282,14 @@ do { \ } \ } while (0) -/* static _Py_UopsSymbol * -make_contradiction(_Py_UOpsContext *ctx) +make_bottom(_Py_UOpsContext *ctx) { _Py_UopsSymbol *sym = _Py_uop_sym_new_unknown(ctx); _Py_uop_sym_set_null(sym); - _Py_uop_sym_set_type(sym, &PyLong_Type); + _Py_uop_sym_set_non_null(sym); return sym; -}*/ +} PyObject * _Py_uop_symbols_test(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(ignored)) @@ -297,15 +302,16 @@ _Py_uop_symbols_test(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(ignored)) if (top == NULL) { return NULL; } - TEST_PREDICATE(!_Py_uop_sym_is_null(top), "unknown is NULL"); - TEST_PREDICATE(!_Py_uop_sym_is_not_null(top), "unknown is not NULL"); - TEST_PREDICATE(!_Py_uop_sym_is_const(top), "unknown is a constant"); - // TEST_PREDICATE(_Py_uop_sym_get_const(top) == NULL, "unknown as constant is not NULL"); - - // _Py_UopsSymbol *contradiction = make_contradiction(ctx); - // TEST_PREDICATE(_Py_uop_sym_is_null(contradiction), "contradiction is NULL is not true"); - // TEST_PREDICATE(_Py_uop_sym_is_not_null(contradiction), "contradiction is not NULL is not true"); - // TEST_PREDICATE(_Py_uop_sym_is_const(contradiction), "contradiction is a constant is not true"); + TEST_PREDICATE(!_Py_uop_sym_is_null(top), "top is NULL"); + TEST_PREDICATE(!_Py_uop_sym_is_not_null(top), "top is not NULL"); + TEST_PREDICATE(!_Py_uop_sym_is_const(top), "top is a constant"); + TEST_PREDICATE(_Py_uop_sym_get_const(top) == NULL, "top as constant is not NULL"); + + _Py_UopsSymbol *bottom = make_bottom(ctx); + TEST_PREDICATE(!_Py_uop_sym_is_null(bottom), "bottom is NULL is not false"); + TEST_PREDICATE(!_Py_uop_sym_is_not_null(bottom), "bottom is not NULL is not false"); + TEST_PREDICATE(!_Py_uop_sym_is_const(bottom), "bottom is a constant is not false"); + TEST_PREDICATE(_Py_uop_sym_get_const(bottom) == NULL, "bottom as constant is not NULL"); _Py_UopsSymbol *int_type = _Py_uop_sym_new_type(ctx, &PyLong_Type); TEST_PREDICATE(_Py_uop_sym_matches_type(int_type, &PyLong_Type), "inconsistent type"); From ffdf02943d986f246c37a27bdddabc4d8f5e3373 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Tue, 27 Feb 2024 13:55:36 -0800 Subject: [PATCH 03/14] Add _Py_uop_sym_set_non_null in various places --- Include/internal/pycore_optimizer.h | 1 + Python/optimizer_analysis.c | 1 + Python/optimizer_bytecodes.c | 1 + 3 files changed, 3 insertions(+) diff --git a/Include/internal/pycore_optimizer.h b/Include/internal/pycore_optimizer.h index e7da68d13f2247..472ede84d594d5 100644 --- a/Include/internal/pycore_optimizer.h +++ b/Include/internal/pycore_optimizer.h @@ -93,6 +93,7 @@ extern _Py_UopsSymbol *_Py_uop_sym_new_const(_Py_UOpsContext *ctx, PyObject *con extern _Py_UopsSymbol *_Py_uop_sym_new_null(_Py_UOpsContext *ctx); extern bool _Py_uop_sym_matches_type(_Py_UopsSymbol *sym, PyTypeObject *typ); extern void _Py_uop_sym_set_null(_Py_UopsSymbol *sym); +extern void _Py_uop_sym_set_non_null(_Py_UopsSymbol *sym); extern void _Py_uop_sym_set_type(_Py_UopsSymbol *sym, PyTypeObject *tp); extern int _Py_uop_abstractcontext_init(_Py_UOpsContext *ctx); diff --git a/Python/optimizer_analysis.c b/Python/optimizer_analysis.c index b29a00c941e996..b99dc1fabf4fa4 100644 --- a/Python/optimizer_analysis.c +++ b/Python/optimizer_analysis.c @@ -294,6 +294,7 @@ remove_globals(_PyInterpreterFrame *frame, _PyUOpInstruction *buffer, #define sym_new_null _Py_uop_sym_new_null #define sym_matches_type _Py_uop_sym_matches_type #define sym_set_null _Py_uop_sym_set_null +#define sym_set_non_null _Py_uop_sym_set_non_null #define sym_set_type _Py_uop_sym_set_type #define frame_new _Py_uop_frame_new #define frame_pop _Py_uop_frame_pop diff --git a/Python/optimizer_bytecodes.c b/Python/optimizer_bytecodes.c index 68737389c66b67..5babd9344e0e5f 100644 --- a/Python/optimizer_bytecodes.c +++ b/Python/optimizer_bytecodes.c @@ -22,6 +22,7 @@ typedef struct _Py_UOpsAbstractFrame _Py_UOpsAbstractFrame; #define sym_new_null _Py_uop_sym_new_null #define sym_matches_type _Py_uop_sym_matches_type #define sym_set_null _Py_uop_sym_set_null +#define sym_set_non_null _Py_uop_sym_set_non_null #define sym_set_type _Py_uop_sym_set_type #define frame_new _Py_uop_frame_new #define frame_pop _Py_uop_frame_pop From 7d44eed0c37ab94868c63e674ac3f1bf356b7247 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Tue, 27 Feb 2024 13:59:56 -0800 Subject: [PATCH 04/14] Rename arg of _Py_uop_sym_set_type to typ --- Include/internal/pycore_optimizer.h | 2 +- Python/optimizer_symbols.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Include/internal/pycore_optimizer.h b/Include/internal/pycore_optimizer.h index 472ede84d594d5..1b1a4a84f1d5a4 100644 --- a/Include/internal/pycore_optimizer.h +++ b/Include/internal/pycore_optimizer.h @@ -94,7 +94,7 @@ extern _Py_UopsSymbol *_Py_uop_sym_new_null(_Py_UOpsContext *ctx); extern bool _Py_uop_sym_matches_type(_Py_UopsSymbol *sym, PyTypeObject *typ); extern void _Py_uop_sym_set_null(_Py_UopsSymbol *sym); extern void _Py_uop_sym_set_non_null(_Py_UopsSymbol *sym); -extern void _Py_uop_sym_set_type(_Py_UopsSymbol *sym, PyTypeObject *tp); +extern void _Py_uop_sym_set_type(_Py_UopsSymbol *sym, PyTypeObject *typ); extern int _Py_uop_abstractcontext_init(_Py_UOpsContext *ctx); extern void _Py_uop_abstractcontext_fini(_Py_UOpsContext *ctx); diff --git a/Python/optimizer_symbols.c b/Python/optimizer_symbols.c index 46181d3d689ce9..ddc70d08ab0b51 100644 --- a/Python/optimizer_symbols.c +++ b/Python/optimizer_symbols.c @@ -99,10 +99,10 @@ _Py_uop_sym_get_const(_Py_UopsSymbol *sym) } void -_Py_uop_sym_set_type(_Py_UopsSymbol *sym, PyTypeObject *tp) +_Py_uop_sym_set_type(_Py_UopsSymbol *sym, PyTypeObject *typ) { - assert(PyType_Check(tp)); - sym->typ = tp; + assert(typ != NULL && PyType_Check(typ)); + sym->typ = typ; sym_set_flag(sym, NOT_NULL); } From ac83bb6d5ebdd658883f514f6db7d35986173a3e Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Tue, 27 Feb 2024 14:01:49 -0800 Subject: [PATCH 05/14] Explain members of Symbol type --- Include/internal/pycore_optimizer.h | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Include/internal/pycore_optimizer.h b/Include/internal/pycore_optimizer.h index 1b1a4a84f1d5a4..aeefe8d2ac7cca 100644 --- a/Include/internal/pycore_optimizer.h +++ b/Include/internal/pycore_optimizer.h @@ -30,10 +30,9 @@ extern PyTypeObject _PyUOpOptimizer_Type; /* See explanation in optimizer_symbols.c */ struct _Py_UopsSymbol { - int flags; - PyTypeObject *typ; - // constant propagated value (might be NULL) - PyObject *const_val; + int flags; // 0 bits: Top; 2 or more bits: Bottom + PyTypeObject *typ; // Borrowed reference + PyObject *const_val; // Owned reference (!) }; // Holds locals, stack, locals, stack ... co_consts (in that order) From c6c7c662c4a47d7ac44f1a767331809c4b588677 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Tue, 27 Feb 2024 15:59:28 -0800 Subject: [PATCH 06/14] sym_set_type() may result in bottom --- Python/optimizer_symbols.c | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/Python/optimizer_symbols.c b/Python/optimizer_symbols.c index ddc70d08ab0b51..c84b2fd5e6f149 100644 --- a/Python/optimizer_symbols.c +++ b/Python/optimizer_symbols.c @@ -74,6 +74,20 @@ sym_set_flag(_Py_UopsSymbol *sym, int flag) sym->flags |= flag; } +static inline void +_Py_uop_sym_set_bottom(_Py_UopsSymbol *sym) +{ + sym_set_flag(sym, IS_NULL | NOT_NULL); + sym->typ = NULL; + Py_CLEAR(sym->const_val); +} + +static inline bool +_Py_uop_sym_is_bottom(_Py_UopsSymbol *sym) +{ + return (sym->flags & IS_NULL) && (sym->flags & NOT_NULL); +} + bool _Py_uop_sym_is_not_null(_Py_UopsSymbol *sym) { @@ -102,8 +116,15 @@ void _Py_uop_sym_set_type(_Py_UopsSymbol *sym, PyTypeObject *typ) { assert(typ != NULL && PyType_Check(typ)); - sym->typ = typ; + if (sym->flags & IS_NULL || + (sym->typ != NULL && sym->typ != typ)) + { + _Py_uop_sym_set_bottom(sym); + return; + } + // May be a no-op sym_set_flag(sym, NOT_NULL); + sym->typ = typ; } void @@ -177,6 +198,9 @@ bool _Py_uop_sym_matches_type(_Py_UopsSymbol *sym, PyTypeObject *typ) { assert(typ != NULL && PyType_Check(typ)); + if (_Py_uop_sym_is_bottom(sym)) { + return false; + } return sym->typ == typ; } @@ -318,7 +342,7 @@ _Py_uop_symbols_test(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(ignored)) _Py_uop_sym_set_type(int_type, &PyLong_Type); TEST_PREDICATE(_Py_uop_sym_matches_type(int_type, &PyLong_Type), "inconsistent type"); _Py_uop_sym_set_type(int_type, &PyFloat_Type); - // TEST_PREDICATE(_Py_uop_sym_matches_type(int_type, &PyLong_Type), "(int and float) doesn't match int"); + TEST_PREDICATE(!_Py_uop_sym_matches_type(int_type, &PyLong_Type), "(int and float) matches int"); _Py_uop_abstractcontext_fini(ctx); Py_RETURN_NONE; From 0cda7a8b63f37865c536c7f42a80ea5dfc18a339 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Tue, 27 Feb 2024 16:12:49 -0800 Subject: [PATCH 07/14] Add more tests --- Python/optimizer_symbols.c | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/Python/optimizer_symbols.c b/Python/optimizer_symbols.c index c84b2fd5e6f149..a94eee5a1349de 100644 --- a/Python/optimizer_symbols.c +++ b/Python/optimizer_symbols.c @@ -328,24 +328,43 @@ _Py_uop_symbols_test(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(ignored)) } TEST_PREDICATE(!_Py_uop_sym_is_null(top), "top is NULL"); TEST_PREDICATE(!_Py_uop_sym_is_not_null(top), "top is not NULL"); + TEST_PREDICATE(!_Py_uop_sym_matches_type(top, &PyLong_Type), "top matches a type"); TEST_PREDICATE(!_Py_uop_sym_is_const(top), "top is a constant"); TEST_PREDICATE(_Py_uop_sym_get_const(top) == NULL, "top as constant is not NULL"); + TEST_PREDICATE(!_Py_uop_sym_is_bottom(top), "top is bottom"); _Py_UopsSymbol *bottom = make_bottom(ctx); + if (bottom == NULL) { + return NULL; + } TEST_PREDICATE(!_Py_uop_sym_is_null(bottom), "bottom is NULL is not false"); TEST_PREDICATE(!_Py_uop_sym_is_not_null(bottom), "bottom is not NULL is not false"); + TEST_PREDICATE(!_Py_uop_sym_matches_type(bottom, &PyLong_Type), "bottom matches a type"); TEST_PREDICATE(!_Py_uop_sym_is_const(bottom), "bottom is a constant is not false"); TEST_PREDICATE(_Py_uop_sym_get_const(bottom) == NULL, "bottom as constant is not NULL"); + TEST_PREDICATE(_Py_uop_sym_is_bottom(bottom), "bottom isn't bottom"); _Py_UopsSymbol *int_type = _Py_uop_sym_new_type(ctx, &PyLong_Type); + if (int_type == NULL) { + return NULL; + } + TEST_PREDICATE(!_Py_uop_sym_is_null(int_type), "int_type is NULL"); + TEST_PREDICATE(_Py_uop_sym_is_not_null(int_type), "int_type isn't not NULL"); TEST_PREDICATE(_Py_uop_sym_matches_type(int_type, &PyLong_Type), "inconsistent type"); - _Py_uop_sym_set_type(int_type, &PyLong_Type); + TEST_PREDICATE(!_Py_uop_sym_matches_type(int_type, &PyFloat_Type), "int matches float"); + TEST_PREDICATE(!_Py_uop_sym_is_const(int_type), "int_type is a constant"); + TEST_PREDICATE(_Py_uop_sym_get_const(int_type) == NULL, "int_type as constant is not NULL"); + + _Py_uop_sym_set_type(int_type, &PyLong_Type); // Should be a no-op TEST_PREDICATE(_Py_uop_sym_matches_type(int_type, &PyLong_Type), "inconsistent type"); - _Py_uop_sym_set_type(int_type, &PyFloat_Type); + + _Py_uop_sym_set_type(int_type, &PyFloat_Type); // Should make it bottom TEST_PREDICATE(!_Py_uop_sym_matches_type(int_type, &PyLong_Type), "(int and float) matches int"); + TEST_PREDICATE(_Py_uop_sym_is_bottom(int_type), "(int and float) isn't bottom"); _Py_uop_abstractcontext_fini(ctx); Py_RETURN_NONE; + fail: _Py_uop_abstractcontext_fini(ctx); return NULL; From 5b0c8626871327f8d7f893f38e555fd7a02afe25 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Tue, 27 Feb 2024 16:46:02 -0800 Subject: [PATCH 08/14] Add sym_set_const and its tests --- Include/internal/pycore_optimizer.h | 1 + Python/optimizer_symbols.c | 154 ++++++++++++++++++++-------- 2 files changed, 113 insertions(+), 42 deletions(-) diff --git a/Include/internal/pycore_optimizer.h b/Include/internal/pycore_optimizer.h index aeefe8d2ac7cca..265eae4e290c38 100644 --- a/Include/internal/pycore_optimizer.h +++ b/Include/internal/pycore_optimizer.h @@ -94,6 +94,7 @@ extern bool _Py_uop_sym_matches_type(_Py_UopsSymbol *sym, PyTypeObject *typ); extern void _Py_uop_sym_set_null(_Py_UopsSymbol *sym); extern void _Py_uop_sym_set_non_null(_Py_UopsSymbol *sym); extern void _Py_uop_sym_set_type(_Py_UopsSymbol *sym, PyTypeObject *typ); +extern void _Py_uop_sym_set_const(_Py_UopsSymbol *sym, PyObject *const_val); extern int _Py_uop_abstractcontext_init(_Py_UOpsContext *ctx); extern void _Py_uop_abstractcontext_fini(_Py_UOpsContext *ctx); diff --git a/Python/optimizer_symbols.c b/Python/optimizer_symbols.c index a94eee5a1349de..bc9560bf7802f9 100644 --- a/Python/optimizer_symbols.c +++ b/Python/optimizer_symbols.c @@ -75,7 +75,7 @@ sym_set_flag(_Py_UopsSymbol *sym, int flag) } static inline void -_Py_uop_sym_set_bottom(_Py_UopsSymbol *sym) +set_bottom(_Py_UopsSymbol *sym) { sym_set_flag(sym, IS_NULL | NOT_NULL); sym->typ = NULL; @@ -116,17 +116,46 @@ void _Py_uop_sym_set_type(_Py_UopsSymbol *sym, PyTypeObject *typ) { assert(typ != NULL && PyType_Check(typ)); - if (sym->flags & IS_NULL || - (sym->typ != NULL && sym->typ != typ)) - { - _Py_uop_sym_set_bottom(sym); + if (sym->flags & IS_NULL) { + set_bottom(sym); + return; + } + if (sym->typ != NULL) { + if (sym->typ != typ) { + set_bottom(sym); + } + return; + } + sym_set_flag(sym, NOT_NULL); + sym->typ = typ; +} + +void +_Py_uop_sym_set_const(_Py_UopsSymbol *sym, PyObject *const_val) +{ + assert(const_val != NULL); + if (sym->flags & IS_NULL) { + set_bottom(sym); + return; + } + PyTypeObject *typ = Py_TYPE(const_val); + if (sym->typ != NULL && sym->typ != typ) { + set_bottom(sym); + return; + } + if (sym->const_val != NULL) { + if (sym->const_val != const_val) { + // TODO: What if they're equal? + set_bottom(sym); + } return; } - // May be a no-op sym_set_flag(sym, NOT_NULL); sym->typ = typ; + sym->const_val = Py_NewRef(const_val); } + void _Py_uop_sym_set_null(_Py_UopsSymbol *sym) { @@ -322,45 +351,86 @@ _Py_uop_symbols_test(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(ignored)) _Py_UOpsContext *ctx = &context; _Py_uop_abstractcontext_init(ctx); - _Py_UopsSymbol *top = _Py_uop_sym_new_unknown(ctx); - if (top == NULL) { - return NULL; + _Py_UopsSymbol *sym = _Py_uop_sym_new_unknown(ctx); + if (sym == NULL) { + goto fail; } - TEST_PREDICATE(!_Py_uop_sym_is_null(top), "top is NULL"); - TEST_PREDICATE(!_Py_uop_sym_is_not_null(top), "top is not NULL"); - TEST_PREDICATE(!_Py_uop_sym_matches_type(top, &PyLong_Type), "top matches a type"); - TEST_PREDICATE(!_Py_uop_sym_is_const(top), "top is a constant"); - TEST_PREDICATE(_Py_uop_sym_get_const(top) == NULL, "top as constant is not NULL"); - TEST_PREDICATE(!_Py_uop_sym_is_bottom(top), "top is bottom"); - - _Py_UopsSymbol *bottom = make_bottom(ctx); - if (bottom == NULL) { - return NULL; + 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"); + TEST_PREDICATE(!_Py_uop_sym_is_const(sym), "top is a constant"); + TEST_PREDICATE(_Py_uop_sym_get_const(sym) == NULL, "top as constant is not NULL"); + TEST_PREDICATE(!_Py_uop_sym_is_bottom(sym), "top is bottom"); + + sym = make_bottom(ctx); + if (sym == NULL) { + goto fail; } - TEST_PREDICATE(!_Py_uop_sym_is_null(bottom), "bottom is NULL is not false"); - TEST_PREDICATE(!_Py_uop_sym_is_not_null(bottom), "bottom is not NULL is not false"); - TEST_PREDICATE(!_Py_uop_sym_matches_type(bottom, &PyLong_Type), "bottom matches a type"); - TEST_PREDICATE(!_Py_uop_sym_is_const(bottom), "bottom is a constant is not false"); - TEST_PREDICATE(_Py_uop_sym_get_const(bottom) == NULL, "bottom as constant is not NULL"); - TEST_PREDICATE(_Py_uop_sym_is_bottom(bottom), "bottom isn't bottom"); - - _Py_UopsSymbol *int_type = _Py_uop_sym_new_type(ctx, &PyLong_Type); - if (int_type == NULL) { - return NULL; + TEST_PREDICATE(!_Py_uop_sym_is_null(sym), "bottom is NULL is not false"); + TEST_PREDICATE(!_Py_uop_sym_is_not_null(sym), "bottom is not NULL is not false"); + TEST_PREDICATE(!_Py_uop_sym_matches_type(sym, &PyLong_Type), "bottom matches a type"); + TEST_PREDICATE(!_Py_uop_sym_is_const(sym), "bottom is a constant is not false"); + TEST_PREDICATE(_Py_uop_sym_get_const(sym) == NULL, "bottom as constant is not NULL"); + TEST_PREDICATE(_Py_uop_sym_is_bottom(sym), "bottom isn't bottom"); + + sym = _Py_uop_sym_new_type(ctx, &PyLong_Type); + if (sym == NULL) { + goto fail; + } + TEST_PREDICATE(!_Py_uop_sym_is_null(sym), "int_type is NULL"); + TEST_PREDICATE(_Py_uop_sym_is_not_null(sym), "int_type isn't not NULL"); + TEST_PREDICATE(_Py_uop_sym_matches_type(sym, &PyLong_Type), "inconsistent type"); + TEST_PREDICATE(!_Py_uop_sym_matches_type(sym, &PyFloat_Type), "int matches float"); + TEST_PREDICATE(!_Py_uop_sym_is_const(sym), "int_type is a constant"); + TEST_PREDICATE(_Py_uop_sym_get_const(sym) == NULL, "int_type as constant is not NULL"); + + _Py_uop_sym_set_type(sym, &PyLong_Type); // Should be a no-op + TEST_PREDICATE(_Py_uop_sym_matches_type(sym, &PyLong_Type), "inconsistent type"); + + _Py_uop_sym_set_type(sym, &PyFloat_Type); // Should make it bottom + TEST_PREDICATE(!_Py_uop_sym_matches_type(sym, &PyLong_Type), "(int and float) matches int"); + TEST_PREDICATE(_Py_uop_sym_is_bottom(sym), "(int and float) isn't bottom"); + + PyObject *val_42 = PyLong_FromLong(42); + assert(val_42 != NULL); + assert(_Py_IsImmortal(val_42)); + + PyObject *val_43 = PyLong_FromLong(43); + assert(val_43 != NULL); + assert(_Py_IsImmortal(val_43)); + + sym = _Py_uop_sym_new_type(ctx, &PyLong_Type); + if (sym == NULL) { + goto fail; + } + _Py_uop_sym_set_const(sym, val_42); + TEST_PREDICATE(!_Py_uop_sym_is_null(sym), "int_val is NULL"); + TEST_PREDICATE(_Py_uop_sym_is_not_null(sym), "int_val isn't not NULL"); + TEST_PREDICATE(_Py_uop_sym_matches_type(sym, &PyLong_Type), "inconsistent type"); + TEST_PREDICATE(!_Py_uop_sym_matches_type(sym, &PyFloat_Type), "int matches float"); + TEST_PREDICATE(_Py_uop_sym_is_const(sym), "int_val is not a constant"); + TEST_PREDICATE(_Py_uop_sym_get_const(sym) != NULL, "int_val as constant is NULL"); + TEST_PREDICATE(_Py_uop_sym_get_const(sym) == val_42, "int_val as constant isn't val_42"); + + _Py_uop_sym_set_type(sym, &PyLong_Type); // Should be a no-op + TEST_PREDICATE(_Py_uop_sym_matches_type(sym, &PyLong_Type), "inconsistent type"); + TEST_PREDICATE(_Py_uop_sym_get_const(sym) == val_42, "int_val as constant isn't val_42"); + + _Py_uop_sym_set_type(sym, &PyFloat_Type); // Should make it bottom + TEST_PREDICATE(!_Py_uop_sym_matches_type(sym, &PyLong_Type), "(42 and float) matches int"); + TEST_PREDICATE(_Py_uop_sym_get_const(sym) == NULL, "(42 and float) as constant isn't NULL"); + TEST_PREDICATE(_Py_uop_sym_is_bottom(sym), "(42 and float) isn't bottom"); + + // Another int_val, to test contradiction by setting const + sym = _Py_uop_sym_new_type(ctx, &PyLong_Type); + if (sym == NULL) { + goto fail; } - TEST_PREDICATE(!_Py_uop_sym_is_null(int_type), "int_type is NULL"); - TEST_PREDICATE(_Py_uop_sym_is_not_null(int_type), "int_type isn't not NULL"); - TEST_PREDICATE(_Py_uop_sym_matches_type(int_type, &PyLong_Type), "inconsistent type"); - TEST_PREDICATE(!_Py_uop_sym_matches_type(int_type, &PyFloat_Type), "int matches float"); - TEST_PREDICATE(!_Py_uop_sym_is_const(int_type), "int_type is a constant"); - TEST_PREDICATE(_Py_uop_sym_get_const(int_type) == NULL, "int_type as constant is not NULL"); - - _Py_uop_sym_set_type(int_type, &PyLong_Type); // Should be a no-op - TEST_PREDICATE(_Py_uop_sym_matches_type(int_type, &PyLong_Type), "inconsistent type"); - - _Py_uop_sym_set_type(int_type, &PyFloat_Type); // Should make it bottom - TEST_PREDICATE(!_Py_uop_sym_matches_type(int_type, &PyLong_Type), "(int and float) matches int"); - TEST_PREDICATE(_Py_uop_sym_is_bottom(int_type), "(int and float) isn't bottom"); + _Py_uop_sym_set_const(sym, val_42); + _Py_uop_sym_set_const(sym, val_43); // Should make it bottom + TEST_PREDICATE(!_Py_uop_sym_matches_type(sym, &PyLong_Type), "(42 and 43) matches int"); + TEST_PREDICATE(_Py_uop_sym_get_const(sym) == NULL, "(42 and 43) as constant isn't NULL"); + TEST_PREDICATE(_Py_uop_sym_is_bottom(sym), "(42 and 43) isn't bottom"); _Py_uop_abstractcontext_fini(ctx); Py_RETURN_NONE; From 785bafbebd957e015b0a4c464de47d773683960b Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Tue, 27 Feb 2024 16:52:24 -0800 Subject: [PATCH 09/14] Simplify sym_new signature --- Python/optimizer_symbols.c | 29 +++++++++++------------------ 1 file changed, 11 insertions(+), 18 deletions(-) diff --git a/Python/optimizer_symbols.c b/Python/optimizer_symbols.c index bc9560bf7802f9..38353918e2ffb4 100644 --- a/Python/optimizer_symbols.c +++ b/Python/optimizer_symbols.c @@ -46,9 +46,8 @@ static inline int get_lltrace(void) { #define DPRINTF(level, ...) #endif -// Takes a borrowed reference to const_val, turns that into a strong reference. static _Py_UopsSymbol * -sym_new(_Py_UOpsContext *ctx, PyObject *const_val) +sym_new(_Py_UOpsContext *ctx) { _Py_UopsSymbol *self = &ctx->t_arena.arena[ctx->t_arena.ty_curr_number]; if (ctx->t_arena.ty_curr_number >= ctx->t_arena.ty_max_number) { @@ -57,13 +56,9 @@ sym_new(_Py_UOpsContext *ctx, PyObject *const_val) return NULL; } ctx->t_arena.ty_curr_number++; - self->const_val = NULL; - self->typ = NULL; self->flags = 0; - - if (const_val != NULL) { - self->const_val = Py_NewRef(const_val); - } + self->typ = NULL; + self->const_val = NULL; return self; } @@ -172,7 +167,7 @@ _Py_uop_sym_set_non_null(_Py_UopsSymbol *sym) _Py_UopsSymbol * _Py_uop_sym_new_unknown(_Py_UOpsContext *ctx) { - return sym_new(ctx, NULL); + return sym_new(ctx); } _Py_UopsSymbol * @@ -187,10 +182,9 @@ _Py_uop_sym_new_not_null(_Py_UOpsContext *ctx) } _Py_UopsSymbol * -_Py_uop_sym_new_type(_Py_UOpsContext *ctx, - PyTypeObject *typ) +_Py_uop_sym_new_type(_Py_UOpsContext *ctx, PyTypeObject *typ) { - _Py_UopsSymbol *res = sym_new(ctx,NULL); + _Py_UopsSymbol *res = sym_new(ctx); if (res == NULL) { return NULL; } @@ -198,18 +192,17 @@ _Py_uop_sym_new_type(_Py_UOpsContext *ctx, return res; } -// Takes a borrowed reference to const_val. +// Adds a new reference to const_val, owned by the symbol. _Py_UopsSymbol * _Py_uop_sym_new_const(_Py_UOpsContext *ctx, PyObject *const_val) { assert(const_val != NULL); - _Py_UopsSymbol *temp = sym_new(ctx, const_val); - if (temp == NULL) { + _Py_UopsSymbol *res = sym_new(ctx); + if (res == NULL) { return NULL; } - _Py_uop_sym_set_type(temp, Py_TYPE(const_val)); - sym_set_flag(temp, NOT_NULL); - return temp; + _Py_uop_sym_set_const(res, const_val); + return res; } _Py_UopsSymbol * From 17a8d67d3beec0c1ccb1a0e5feca31a21277bdad Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Tue, 27 Feb 2024 16:59:43 -0800 Subject: [PATCH 10/14] Incorporate assertions into sym_is_bottom() --- Python/optimizer_symbols.c | 45 +++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/Python/optimizer_symbols.c b/Python/optimizer_symbols.c index 38353918e2ffb4..0c634b9a2a0dd3 100644 --- a/Python/optimizer_symbols.c +++ b/Python/optimizer_symbols.c @@ -80,7 +80,13 @@ set_bottom(_Py_UopsSymbol *sym) static inline bool _Py_uop_sym_is_bottom(_Py_UopsSymbol *sym) { - return (sym->flags & IS_NULL) && (sym->flags & NOT_NULL); + if ((sym->flags & IS_NULL) && (sym->flags & NOT_NULL)) { + assert(sym->flags == (IS_NULL | NOT_NULL)); + assert(sym->typ == NULL); + assert(sym->const_val == NULL); + return true; + } + return false; } bool @@ -344,6 +350,7 @@ _Py_uop_symbols_test(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(ignored)) _Py_UOpsContext *ctx = &context; _Py_uop_abstractcontext_init(ctx); + // Use a single 'sym' variable so copy-pasting tests is easier. _Py_UopsSymbol *sym = _Py_uop_sym_new_unknown(ctx); if (sym == NULL) { goto fail; @@ -370,18 +377,17 @@ _Py_uop_symbols_test(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(ignored)) if (sym == NULL) { goto fail; } - TEST_PREDICATE(!_Py_uop_sym_is_null(sym), "int_type is NULL"); - TEST_PREDICATE(_Py_uop_sym_is_not_null(sym), "int_type isn't not NULL"); - TEST_PREDICATE(_Py_uop_sym_matches_type(sym, &PyLong_Type), "inconsistent type"); + TEST_PREDICATE(!_Py_uop_sym_is_null(sym), "int is NULL"); + TEST_PREDICATE(_Py_uop_sym_is_not_null(sym), "int isn't not NULL"); + TEST_PREDICATE(_Py_uop_sym_matches_type(sym, &PyLong_Type), "int isn't int"); TEST_PREDICATE(!_Py_uop_sym_matches_type(sym, &PyFloat_Type), "int matches float"); - TEST_PREDICATE(!_Py_uop_sym_is_const(sym), "int_type is a constant"); - TEST_PREDICATE(_Py_uop_sym_get_const(sym) == NULL, "int_type as constant is not NULL"); + TEST_PREDICATE(!_Py_uop_sym_is_const(sym), "int is a constant"); + TEST_PREDICATE(_Py_uop_sym_get_const(sym) == NULL, "int as constant is not NULL"); _Py_uop_sym_set_type(sym, &PyLong_Type); // Should be a no-op - TEST_PREDICATE(_Py_uop_sym_matches_type(sym, &PyLong_Type), "inconsistent type"); + TEST_PREDICATE(_Py_uop_sym_matches_type(sym, &PyLong_Type), "(int and int) isn't int"); _Py_uop_sym_set_type(sym, &PyFloat_Type); // Should make it bottom - TEST_PREDICATE(!_Py_uop_sym_matches_type(sym, &PyLong_Type), "(int and float) matches int"); TEST_PREDICATE(_Py_uop_sym_is_bottom(sym), "(int and float) isn't bottom"); PyObject *val_42 = PyLong_FromLong(42); @@ -397,32 +403,27 @@ _Py_uop_symbols_test(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(ignored)) goto fail; } _Py_uop_sym_set_const(sym, val_42); - TEST_PREDICATE(!_Py_uop_sym_is_null(sym), "int_val is NULL"); - TEST_PREDICATE(_Py_uop_sym_is_not_null(sym), "int_val isn't not NULL"); - TEST_PREDICATE(_Py_uop_sym_matches_type(sym, &PyLong_Type), "inconsistent type"); - TEST_PREDICATE(!_Py_uop_sym_matches_type(sym, &PyFloat_Type), "int matches float"); - TEST_PREDICATE(_Py_uop_sym_is_const(sym), "int_val is not a constant"); - TEST_PREDICATE(_Py_uop_sym_get_const(sym) != NULL, "int_val as constant is NULL"); - TEST_PREDICATE(_Py_uop_sym_get_const(sym) == val_42, "int_val as constant isn't val_42"); + 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"); + TEST_PREDICATE(_Py_uop_sym_matches_type(sym, &PyLong_Type), "42 isn't an int"); + TEST_PREDICATE(!_Py_uop_sym_matches_type(sym, &PyFloat_Type), "42 matches float"); + TEST_PREDICATE(_Py_uop_sym_is_const(sym), "42 is not a constant"); + TEST_PREDICATE(_Py_uop_sym_get_const(sym) != NULL, "42 as constant is NULL"); + TEST_PREDICATE(_Py_uop_sym_get_const(sym) == val_42, "42 as constant isn't 42"); _Py_uop_sym_set_type(sym, &PyLong_Type); // Should be a no-op - TEST_PREDICATE(_Py_uop_sym_matches_type(sym, &PyLong_Type), "inconsistent type"); - TEST_PREDICATE(_Py_uop_sym_get_const(sym) == val_42, "int_val as constant isn't val_42"); + TEST_PREDICATE(_Py_uop_sym_matches_type(sym, &PyLong_Type), "(42 and 42) isn't an int"); + TEST_PREDICATE(_Py_uop_sym_get_const(sym) == val_42, "(42 and 42) as constant isn't 42"); _Py_uop_sym_set_type(sym, &PyFloat_Type); // Should make it bottom - TEST_PREDICATE(!_Py_uop_sym_matches_type(sym, &PyLong_Type), "(42 and float) matches int"); - TEST_PREDICATE(_Py_uop_sym_get_const(sym) == NULL, "(42 and float) as constant isn't NULL"); TEST_PREDICATE(_Py_uop_sym_is_bottom(sym), "(42 and float) isn't bottom"); - // Another int_val, to test contradiction by setting const sym = _Py_uop_sym_new_type(ctx, &PyLong_Type); if (sym == NULL) { goto fail; } _Py_uop_sym_set_const(sym, val_42); _Py_uop_sym_set_const(sym, val_43); // Should make it bottom - TEST_PREDICATE(!_Py_uop_sym_matches_type(sym, &PyLong_Type), "(42 and 43) matches int"); - TEST_PREDICATE(_Py_uop_sym_get_const(sym) == NULL, "(42 and 43) as constant isn't NULL"); TEST_PREDICATE(_Py_uop_sym_is_bottom(sym), "(42 and 43) isn't bottom"); _Py_uop_abstractcontext_fini(ctx); From bc3903932b8d0ba3a44944ba8c9cc31aaee43144 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Tue, 27 Feb 2024 19:36:00 -0800 Subject: [PATCH 11/14] Fix set_bottom name; add sym_set_const macro --- Python/optimizer_analysis.c | 1 + Python/optimizer_bytecodes.c | 1 + Python/optimizer_symbols.c | 12 ++++++------ 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/Python/optimizer_analysis.c b/Python/optimizer_analysis.c index b99dc1fabf4fa4..8e408ffbb1c2b5 100644 --- a/Python/optimizer_analysis.c +++ b/Python/optimizer_analysis.c @@ -296,6 +296,7 @@ remove_globals(_PyInterpreterFrame *frame, _PyUOpInstruction *buffer, #define sym_set_null _Py_uop_sym_set_null #define sym_set_non_null _Py_uop_sym_set_non_null #define sym_set_type _Py_uop_sym_set_type +#define sym_set_const _Py_uop_sym_set_const #define frame_new _Py_uop_frame_new #define frame_pop _Py_uop_frame_pop diff --git a/Python/optimizer_bytecodes.c b/Python/optimizer_bytecodes.c index 5babd9344e0e5f..b65e90bf980e5a 100644 --- a/Python/optimizer_bytecodes.c +++ b/Python/optimizer_bytecodes.c @@ -24,6 +24,7 @@ typedef struct _Py_UOpsAbstractFrame _Py_UOpsAbstractFrame; #define sym_set_null _Py_uop_sym_set_null #define sym_set_non_null _Py_uop_sym_set_non_null #define sym_set_type _Py_uop_sym_set_type +#define sym_set_const _Py_uop_sym_set_const #define frame_new _Py_uop_frame_new #define frame_pop _Py_uop_frame_pop diff --git a/Python/optimizer_symbols.c b/Python/optimizer_symbols.c index 0c634b9a2a0dd3..d6cf0dc6dfd980 100644 --- a/Python/optimizer_symbols.c +++ b/Python/optimizer_symbols.c @@ -70,7 +70,7 @@ sym_set_flag(_Py_UopsSymbol *sym, int flag) } static inline void -set_bottom(_Py_UopsSymbol *sym) +sym_set_bottom(_Py_UopsSymbol *sym) { sym_set_flag(sym, IS_NULL | NOT_NULL); sym->typ = NULL; @@ -118,12 +118,12 @@ _Py_uop_sym_set_type(_Py_UopsSymbol *sym, PyTypeObject *typ) { assert(typ != NULL && PyType_Check(typ)); if (sym->flags & IS_NULL) { - set_bottom(sym); + sym_set_bottom(sym); return; } if (sym->typ != NULL) { if (sym->typ != typ) { - set_bottom(sym); + sym_set_bottom(sym); } return; } @@ -136,18 +136,18 @@ _Py_uop_sym_set_const(_Py_UopsSymbol *sym, PyObject *const_val) { assert(const_val != NULL); if (sym->flags & IS_NULL) { - set_bottom(sym); + sym_set_bottom(sym); return; } PyTypeObject *typ = Py_TYPE(const_val); if (sym->typ != NULL && sym->typ != typ) { - set_bottom(sym); + sym_set_bottom(sym); return; } if (sym->const_val != NULL) { if (sym->const_val != const_val) { // TODO: What if they're equal? - set_bottom(sym); + sym_set_bottom(sym); } return; } From c355bc6356893733ccbf1345bf21c66b6a35250c Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Wed, 28 Feb 2024 08:51:20 -0800 Subject: [PATCH 12/14] Simplification and decrefs from code review --- Python/optimizer_symbols.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Python/optimizer_symbols.c b/Python/optimizer_symbols.c index d6cf0dc6dfd980..97b68dc434843f 100644 --- a/Python/optimizer_symbols.c +++ b/Python/optimizer_symbols.c @@ -140,7 +140,7 @@ _Py_uop_sym_set_const(_Py_UopsSymbol *sym, PyObject *const_val) return; } PyTypeObject *typ = Py_TYPE(const_val); - if (sym->typ != NULL && sym->typ != typ) { + if (sym->typ != typ) { sym_set_bottom(sym); return; } @@ -427,9 +427,13 @@ _Py_uop_symbols_test(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(ignored)) TEST_PREDICATE(_Py_uop_sym_is_bottom(sym), "(42 and 43) isn't bottom"); _Py_uop_abstractcontext_fini(ctx); + Py_DECREF(val_42); + Py_DECREF(val_43); Py_RETURN_NONE; fail: _Py_uop_abstractcontext_fini(ctx); + Py_DECREF(val_42); + Py_DECREF(val_43); return NULL; } From 761d2b180035505366d8ae45ebc97b28607ba954 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Wed, 28 Feb 2024 08:57:57 -0800 Subject: [PATCH 13/14] Declare val_42/43 earlier. --- Python/optimizer_symbols.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Python/optimizer_symbols.c b/Python/optimizer_symbols.c index 97b68dc434843f..f0b4535bf0a150 100644 --- a/Python/optimizer_symbols.c +++ b/Python/optimizer_symbols.c @@ -349,6 +349,8 @@ _Py_uop_symbols_test(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(ignored)) _Py_UOpsContext context; _Py_UOpsContext *ctx = &context; _Py_uop_abstractcontext_init(ctx); + PyObject *val_42 = NULL; + PyObject *val_43 = NULL; // Use a single 'sym' variable so copy-pasting tests is easier. _Py_UopsSymbol *sym = _Py_uop_sym_new_unknown(ctx); @@ -390,11 +392,11 @@ _Py_uop_symbols_test(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(ignored)) _Py_uop_sym_set_type(sym, &PyFloat_Type); // Should make it bottom TEST_PREDICATE(_Py_uop_sym_is_bottom(sym), "(int and float) isn't bottom"); - PyObject *val_42 = PyLong_FromLong(42); + val_42 = PyLong_FromLong(42); assert(val_42 != NULL); assert(_Py_IsImmortal(val_42)); - PyObject *val_43 = PyLong_FromLong(43); + val_43 = PyLong_FromLong(43); assert(val_43 != NULL); assert(_Py_IsImmortal(val_43)); @@ -433,7 +435,7 @@ _Py_uop_symbols_test(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(ignored)) fail: _Py_uop_abstractcontext_fini(ctx); - Py_DECREF(val_42); - Py_DECREF(val_43); + Py_XDECREF(val_42); + Py_XDECREF(val_43); return NULL; } From b0509ce79405748556b78946a4c81f235dd91c03 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Wed, 28 Feb 2024 09:12:17 -0800 Subject: [PATCH 14/14] Fix bug -- if sym->typ is NULL, don't cry bottom --- Python/optimizer_symbols.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Python/optimizer_symbols.c b/Python/optimizer_symbols.c index f0b4535bf0a150..158ee67d19f50e 100644 --- a/Python/optimizer_symbols.c +++ b/Python/optimizer_symbols.c @@ -140,7 +140,7 @@ _Py_uop_sym_set_const(_Py_UopsSymbol *sym, PyObject *const_val) return; } PyTypeObject *typ = Py_TYPE(const_val); - if (sym->typ != typ) { + if (sym->typ != NULL && sym->typ != typ) { sym_set_bottom(sym); return; }