From 16f6ab06e531354ada9907277bde44bc98ca3538 Mon Sep 17 00:00:00 2001 From: Sacul0457Deve <183588943+Sacul0457@users.noreply.github.com.> Date: Sun, 5 Apr 2026 22:07:05 +0800 Subject: [PATCH 1/5] optimize MATCH_SEQUENCE/MAPPING --- Lib/test/test_capi/test_opt.py | 35 ++++++++++++++++++++++++++++++++++ Python/optimizer_bytecodes.c | 16 ++++++++++++++++ Python/optimizer_cases.c.h | 16 ++++++++++++++-- 3 files changed, 65 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py index 56f90194b480a1..941140bf21fe4b 100644 --- a/Lib/test/test_capi/test_opt.py +++ b/Lib/test/test_capi/test_opt.py @@ -4684,6 +4684,41 @@ class A: self.assertIn("_MATCH_CLASS", uops) self.assertEqual(count_ops(ex, "_POP_TOP_NOP"), 4) + def test_match_mapping(self): + def testfunc(n): + x = {} + ret = 0 + for _ in range(n): + x["a"] = 1 + match x: + case {}: + ret += 1 + return ret + + res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD) + self.assertEqual(res, TIER2_THRESHOLD) + uops = get_opnames(ex) + + self.assertIn("_MATCH_MAPPING", uops) + self.assertNotIn("_GUARD_BIT_IS_SET_POP", uops) + + def test_match_sequence(self): + def testfunc(n): + ret = 0 + for _ in range(n): + x = 1, 2 + match x: + case a, b: + ret += 1 + return ret + + res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD) + self.assertEqual(res, TIER2_THRESHOLD) + uops = get_opnames(ex) + + self.assertIn("_MATCH_SEQUENCE", uops) + self.assertNotIn("_GUARD_BIT_IS_SET_POP", uops) + def test_dict_update(self): def testfunc(n): d = {1: 2, 3: 4} diff --git a/Python/optimizer_bytecodes.c b/Python/optimizer_bytecodes.c index f2645553513f3d..5500cccdcb1ec7 100644 --- a/Python/optimizer_bytecodes.c +++ b/Python/optimizer_bytecodes.c @@ -2071,6 +2071,22 @@ dummy_func(void) { n = names; } + op(_MATCH_MAPPING, (subject -- subject, res)) { + if (sym_has_type(subject)) { + PyTypeObject *type = sym_get_type(subject); + int match = type->tp_flags & Py_TPFLAGS_MAPPING; + res = match ? sym_new_const(ctx, Py_True) : sym_new_const(ctx, Py_False); + } + } + + op(_MATCH_SEQUENCE, (subject -- subject, res)) { + if (sym_has_type(subject)) { + PyTypeObject *type = sym_get_type(subject); + int match = type->tp_flags & Py_TPFLAGS_SEQUENCE; + res = match ? sym_new_const(ctx, Py_True) : sym_new_const(ctx, Py_False); + } + } + op(_DICT_UPDATE, (dict, unused[oparg - 1], update -- dict, unused[oparg - 1], upd)) { (void)dict; upd = update; diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h index fb3ec39a42eabc..86d582b7cb5b44 100644 --- a/Python/optimizer_cases.c.h +++ b/Python/optimizer_cases.c.h @@ -3176,8 +3176,14 @@ } case _MATCH_MAPPING: { + JitOptRef subject; JitOptRef res; - res = sym_new_not_null(ctx); + subject = stack_pointer[-1]; + if (sym_has_type(subject)) { + PyTypeObject *type = sym_get_type(subject); + int match = type->tp_flags & Py_TPFLAGS_MAPPING; + res = match ? sym_new_const(ctx, Py_True) : sym_new_const(ctx, Py_False); + } CHECK_STACK_BOUNDS(1); stack_pointer[0] = res; stack_pointer += 1; @@ -3186,8 +3192,14 @@ } case _MATCH_SEQUENCE: { + JitOptRef subject; JitOptRef res; - res = sym_new_not_null(ctx); + subject = stack_pointer[-1]; + if (sym_has_type(subject)) { + PyTypeObject *type = sym_get_type(subject); + int match = type->tp_flags & Py_TPFLAGS_SEQUENCE; + res = match ? sym_new_const(ctx, Py_True) : sym_new_const(ctx, Py_False); + } CHECK_STACK_BOUNDS(1); stack_pointer[0] = res; stack_pointer += 1; From c366767d70dfddf0d2f3f892152f9fb1c92e0b5e Mon Sep 17 00:00:00 2001 From: Sacul0457Deve <183588943+Sacul0457@users.noreply.github.com.> Date: Sun, 5 Apr 2026 22:19:23 +0800 Subject: [PATCH 2/5] add else case to set the type to PyBool_Type --- Python/optimizer_bytecodes.c | 6 ++++++ Python/optimizer_cases.c.h | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/Python/optimizer_bytecodes.c b/Python/optimizer_bytecodes.c index 5500cccdcb1ec7..03b875b625a031 100644 --- a/Python/optimizer_bytecodes.c +++ b/Python/optimizer_bytecodes.c @@ -2077,6 +2077,9 @@ dummy_func(void) { int match = type->tp_flags & Py_TPFLAGS_MAPPING; res = match ? sym_new_const(ctx, Py_True) : sym_new_const(ctx, Py_False); } + else { + res = sym_new_type(ctx, &PyBool_Type); + } } op(_MATCH_SEQUENCE, (subject -- subject, res)) { @@ -2085,6 +2088,9 @@ dummy_func(void) { int match = type->tp_flags & Py_TPFLAGS_SEQUENCE; res = match ? sym_new_const(ctx, Py_True) : sym_new_const(ctx, Py_False); } + else { + res = sym_new_type(ctx, &PyBool_Type); + } } op(_DICT_UPDATE, (dict, unused[oparg - 1], update -- dict, unused[oparg - 1], upd)) { diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h index 86d582b7cb5b44..e9ef7dce0a9147 100644 --- a/Python/optimizer_cases.c.h +++ b/Python/optimizer_cases.c.h @@ -3184,6 +3184,9 @@ int match = type->tp_flags & Py_TPFLAGS_MAPPING; res = match ? sym_new_const(ctx, Py_True) : sym_new_const(ctx, Py_False); } + else { + res = sym_new_type(ctx, &PyBool_Type); + } CHECK_STACK_BOUNDS(1); stack_pointer[0] = res; stack_pointer += 1; @@ -3200,6 +3203,9 @@ int match = type->tp_flags & Py_TPFLAGS_SEQUENCE; res = match ? sym_new_const(ctx, Py_True) : sym_new_const(ctx, Py_False); } + else { + res = sym_new_type(ctx, &PyBool_Type); + } CHECK_STACK_BOUNDS(1); stack_pointer[0] = res; stack_pointer += 1; From a405ca7533140bba912760804d551951871f57c4 Mon Sep 17 00:00:00 2001 From: Sacul0457Deve <183588943+Sacul0457@users.noreply.github.com.> Date: Tue, 7 Apr 2026 19:48:32 +0800 Subject: [PATCH 3/5] address review --- Python/optimizer_bytecodes.c | 12 ++++++------ Python/optimizer_cases.c.h | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Python/optimizer_bytecodes.c b/Python/optimizer_bytecodes.c index 03b875b625a031..42ee3537472da6 100644 --- a/Python/optimizer_bytecodes.c +++ b/Python/optimizer_bytecodes.c @@ -2072,10 +2072,10 @@ dummy_func(void) { } op(_MATCH_MAPPING, (subject -- subject, res)) { - if (sym_has_type(subject)) { - PyTypeObject *type = sym_get_type(subject); + PyTypeObject *type = sym_get_type(subject); + if (type != NULL) { int match = type->tp_flags & Py_TPFLAGS_MAPPING; - res = match ? sym_new_const(ctx, Py_True) : sym_new_const(ctx, Py_False); + res = sym_new_const(ctx, match ? Py_True : Py_False); } else { res = sym_new_type(ctx, &PyBool_Type); @@ -2083,10 +2083,10 @@ dummy_func(void) { } op(_MATCH_SEQUENCE, (subject -- subject, res)) { - if (sym_has_type(subject)) { - PyTypeObject *type = sym_get_type(subject); + PyTypeObject *type = sym_get_type(subject); + if (type != NULL) { int match = type->tp_flags & Py_TPFLAGS_SEQUENCE; - res = match ? sym_new_const(ctx, Py_True) : sym_new_const(ctx, Py_False); + res = sym_new_const(ctx, match ? Py_True : Py_False); } else { res = sym_new_type(ctx, &PyBool_Type); diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h index e9ef7dce0a9147..f955a701754863 100644 --- a/Python/optimizer_cases.c.h +++ b/Python/optimizer_cases.c.h @@ -3179,10 +3179,10 @@ JitOptRef subject; JitOptRef res; subject = stack_pointer[-1]; - if (sym_has_type(subject)) { - PyTypeObject *type = sym_get_type(subject); + PyTypeObject *type = sym_get_type(subject); + if (type != NULL) { int match = type->tp_flags & Py_TPFLAGS_MAPPING; - res = match ? sym_new_const(ctx, Py_True) : sym_new_const(ctx, Py_False); + res = sym_new_const(ctx, match ? Py_True : Py_False); } else { res = sym_new_type(ctx, &PyBool_Type); @@ -3198,10 +3198,10 @@ JitOptRef subject; JitOptRef res; subject = stack_pointer[-1]; - if (sym_has_type(subject)) { - PyTypeObject *type = sym_get_type(subject); + PyTypeObject *type = sym_get_type(subject); + if (type != NULL) { int match = type->tp_flags & Py_TPFLAGS_SEQUENCE; - res = match ? sym_new_const(ctx, Py_True) : sym_new_const(ctx, Py_False); + res = sym_new_const(ctx, match ? Py_True : Py_False); } else { res = sym_new_type(ctx, &PyBool_Type); From e1677703601820bde3083fdb45bf632f37ee6c84 Mon Sep 17 00:00:00 2001 From: Sacul0457Deve <183588943+Sacul0457@users.noreply.github.com.> Date: Thu, 21 May 2026 18:57:43 +0800 Subject: [PATCH 4/5] address review: use replace op instead --- Python/optimizer_bytecodes.c | 4 ++-- Python/optimizer_cases.c.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Python/optimizer_bytecodes.c b/Python/optimizer_bytecodes.c index 42ee3537472da6..1dd5608a096d32 100644 --- a/Python/optimizer_bytecodes.c +++ b/Python/optimizer_bytecodes.c @@ -2075,7 +2075,7 @@ dummy_func(void) { PyTypeObject *type = sym_get_type(subject); if (type != NULL) { int match = type->tp_flags & Py_TPFLAGS_MAPPING; - res = sym_new_const(ctx, match ? Py_True : Py_False); + REPLACE_OP(this_instr, _LOAD_COMMON_CONST, match? CONSTANT_TRUE : CONSTANT_FALSE, 0); } else { res = sym_new_type(ctx, &PyBool_Type); @@ -2086,7 +2086,7 @@ dummy_func(void) { PyTypeObject *type = sym_get_type(subject); if (type != NULL) { int match = type->tp_flags & Py_TPFLAGS_SEQUENCE; - res = sym_new_const(ctx, match ? Py_True : Py_False); + REPLACE_OP(this_instr, _LOAD_COMMON_CONST, match? CONSTANT_TRUE : CONSTANT_FALSE, 0); } else { res = sym_new_type(ctx, &PyBool_Type); diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h index f955a701754863..18a956f6701d45 100644 --- a/Python/optimizer_cases.c.h +++ b/Python/optimizer_cases.c.h @@ -3182,7 +3182,7 @@ PyTypeObject *type = sym_get_type(subject); if (type != NULL) { int match = type->tp_flags & Py_TPFLAGS_MAPPING; - res = sym_new_const(ctx, match ? Py_True : Py_False); + REPLACE_OP(this_instr, _LOAD_COMMON_CONST, match? CONSTANT_TRUE : CONSTANT_FALSE, 0); } else { res = sym_new_type(ctx, &PyBool_Type); @@ -3201,7 +3201,7 @@ PyTypeObject *type = sym_get_type(subject); if (type != NULL) { int match = type->tp_flags & Py_TPFLAGS_SEQUENCE; - res = sym_new_const(ctx, match ? Py_True : Py_False); + REPLACE_OP(this_instr, _LOAD_COMMON_CONST, match? CONSTANT_TRUE : CONSTANT_FALSE, 0); } else { res = sym_new_type(ctx, &PyBool_Type); From bd2a9d82516b46d876d4818735bc2e819add0f78 Mon Sep 17 00:00:00 2001 From: Sacul0457Deve <183588943+Sacul0457@users.noreply.github.com.> Date: Thu, 21 May 2026 19:23:03 +0800 Subject: [PATCH 5/5] use _LOAD_COMMON_CONSTANT and update tests --- Lib/test/test_capi/test_opt.py | 11 ++++------- Python/optimizer_bytecodes.c | 4 ++-- Python/optimizer_cases.c.h | 4 ++-- 3 files changed, 8 insertions(+), 11 deletions(-) diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py index ed83cb707a7e11..cc810d64ab33a9 100644 --- a/Lib/test/test_capi/test_opt.py +++ b/Lib/test/test_capi/test_opt.py @@ -5710,7 +5710,6 @@ class A: res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD) self.assertEqual(res, TIER2_THRESHOLD) uops = get_opnames(ex) - self.assertIn("_MATCH_CLASS", uops) self.assertEqual(count_ops(ex, "_POP_TOP_NOP"), 4) @@ -5728,9 +5727,8 @@ def testfunc(n): res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD) self.assertEqual(res, TIER2_THRESHOLD) uops = get_opnames(ex) - - self.assertIn("_MATCH_MAPPING", uops) - self.assertNotIn("_GUARD_BIT_IS_SET_POP", uops) + self.assertNotIn("_MATCH_MAPPING", uops) + self.assertIn("_LOAD_COMMON_CONSTANT", uops) def test_match_sequence(self): def testfunc(n): @@ -5745,9 +5743,8 @@ def testfunc(n): res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD) self.assertEqual(res, TIER2_THRESHOLD) uops = get_opnames(ex) - - self.assertIn("_MATCH_SEQUENCE", uops) - self.assertNotIn("_GUARD_BIT_IS_SET_POP", uops) + self.assertNotIn("_MATCH_SEQUENCE", uops) + self.assertIn("_LOAD_COMMON_CONSTANT", uops) def test_dict_update(self): def testfunc(n): diff --git a/Python/optimizer_bytecodes.c b/Python/optimizer_bytecodes.c index d777ef93cda6a2..ed76eed97dbcd3 100644 --- a/Python/optimizer_bytecodes.c +++ b/Python/optimizer_bytecodes.c @@ -2599,7 +2599,7 @@ dummy_func(void) { PyTypeObject *type = sym_get_type(subject); if (type != NULL) { int match = type->tp_flags & Py_TPFLAGS_MAPPING; - REPLACE_OP(this_instr, _LOAD_COMMON_CONST, match? CONSTANT_TRUE : CONSTANT_FALSE, 0); + REPLACE_OP(this_instr, _LOAD_COMMON_CONSTANT, match? CONSTANT_TRUE : CONSTANT_FALSE, 0); } else { res = sym_new_type(ctx, &PyBool_Type); @@ -2610,7 +2610,7 @@ dummy_func(void) { PyTypeObject *type = sym_get_type(subject); if (type != NULL) { int match = type->tp_flags & Py_TPFLAGS_SEQUENCE; - REPLACE_OP(this_instr, _LOAD_COMMON_CONST, match? CONSTANT_TRUE : CONSTANT_FALSE, 0); + REPLACE_OP(this_instr, _LOAD_COMMON_CONSTANT, match? CONSTANT_TRUE : CONSTANT_FALSE, 0); } else { res = sym_new_type(ctx, &PyBool_Type); diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h index dfd9bd1a77757d..e4407bfdf30486 100644 --- a/Python/optimizer_cases.c.h +++ b/Python/optimizer_cases.c.h @@ -3548,7 +3548,7 @@ PyTypeObject *type = sym_get_type(subject); if (type != NULL) { int match = type->tp_flags & Py_TPFLAGS_MAPPING; - REPLACE_OP(this_instr, _LOAD_COMMON_CONST, match? CONSTANT_TRUE : CONSTANT_FALSE, 0); + REPLACE_OP(this_instr, _LOAD_COMMON_CONSTANT, match? CONSTANT_TRUE : CONSTANT_FALSE, 0); } else { res = sym_new_type(ctx, &PyBool_Type); @@ -3567,7 +3567,7 @@ PyTypeObject *type = sym_get_type(subject); if (type != NULL) { int match = type->tp_flags & Py_TPFLAGS_SEQUENCE; - REPLACE_OP(this_instr, _LOAD_COMMON_CONST, match? CONSTANT_TRUE : CONSTANT_FALSE, 0); + REPLACE_OP(this_instr, _LOAD_COMMON_CONSTANT, match? CONSTANT_TRUE : CONSTANT_FALSE, 0); } else { res = sym_new_type(ctx, &PyBool_Type);