From ee6e90bfab9600b54cf7a83675356b8beeb3678b Mon Sep 17 00:00:00 2001 From: Manjusaka Date: Wed, 21 May 2025 13:56:53 +0800 Subject: [PATCH 1/3] gh-131798: JIT: replace `_LOAD_SMALL_INT` with `_LOAD_CONST_INLINE_BORROW` Signed-off-by: Manjusaka add news Signed-off-by: Manjusaka add tests Signed-off-by: Manjusaka fix review idea Signed-off-by: Manjusaka --- Lib/test/test_capi/test_opt.py | 11 +++++++++++ .../2025-05-21-13-57-26.gh-issue-131798.QwS5Bb.rst | 1 + Python/optimizer_bytecodes.c | 1 + Python/optimizer_cases.c.h | 1 + 4 files changed, 14 insertions(+) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2025-05-21-13-57-26.gh-issue-131798.QwS5Bb.rst diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py index 98b434313e4d2d..974611315cf92f 100644 --- a/Lib/test/test_capi/test_opt.py +++ b/Lib/test/test_capi/test_opt.py @@ -2156,6 +2156,17 @@ def testfunc(n): self.assertIn("_GUARD_TYPE_VERSION", uops) self.assertNotIn("_CHECK_ATTR_CLASS", uops) + def test_load_small_int(self): + def testfunc(n): + x = 0 + for i in range(n): + x += 1 + return x + res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD) + self.assertEqual(res, TIER2_THRESHOLD) + self.assertIsNotNone(ex) + uops = get_opnames(ex) + self.assertIn("_LOAD_CONST_INLINE_BORROW", uops) def global_identity(x): return x diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-21-13-57-26.gh-issue-131798.QwS5Bb.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-05-21-13-57-26.gh-issue-131798.QwS5Bb.rst new file mode 100644 index 00000000000000..f873bbfb4dcb68 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-05-21-13-57-26.gh-issue-131798.QwS5Bb.rst @@ -0,0 +1 @@ +JIT: replace ``_LOAD_SMALL_INT`` with ``_LOAD_CONST_INLINE_BORROW`` diff --git a/Python/optimizer_bytecodes.c b/Python/optimizer_bytecodes.c index f12cd7b968cffc..db68a81a937403 100644 --- a/Python/optimizer_bytecodes.c +++ b/Python/optimizer_bytecodes.c @@ -529,6 +529,7 @@ dummy_func(void) { op(_LOAD_SMALL_INT, (-- value)) { PyObject *val = PyLong_FromLong(this_instr->oparg); + REPLACE_OP(this_instr, _LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)val); value = sym_new_const(ctx, val); } diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h index 602f5e2cfaf77e..8e72623f02866c 100644 --- a/Python/optimizer_cases.c.h +++ b/Python/optimizer_cases.c.h @@ -80,6 +80,7 @@ case _LOAD_SMALL_INT: { JitOptSymbol *value; PyObject *val = PyLong_FromLong(this_instr->oparg); + REPLACE_OP(this_instr, _LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)val); value = sym_new_const(ctx, val); stack_pointer[0] = value; stack_pointer += 1; From f8483c1b70eaa18faef3e70fad72ea3cbd5ef8d8 Mon Sep 17 00:00:00 2001 From: Nadeshiko Manju Date: Thu, 22 May 2025 11:20:48 +0800 Subject: [PATCH 2/3] Update Lib/test/test_capi/test_opt.py Co-authored-by: Brandt Bucher --- Lib/test/test_capi/test_opt.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py index 974611315cf92f..712cb6022e2457 100644 --- a/Lib/test/test_capi/test_opt.py +++ b/Lib/test/test_capi/test_opt.py @@ -2166,7 +2166,7 @@ def testfunc(n): self.assertEqual(res, TIER2_THRESHOLD) self.assertIsNotNone(ex) uops = get_opnames(ex) - self.assertIn("_LOAD_CONST_INLINE_BORROW", uops) + self.assertNotIn("_LOAD_SMALL_INT", uops) def global_identity(x): return x From 91889256e8b4b5b97f391e78dce80dc76fad8af4 Mon Sep 17 00:00:00 2001 From: Manjusaka Date: Thu, 22 May 2025 11:22:59 +0800 Subject: [PATCH 3/3] fix review idea Signed-off-by: Manjusaka --- Lib/test/test_capi/test_opt.py | 1 + Python/optimizer_bytecodes.c | 4 +++- Python/optimizer_cases.c.h | 4 +++- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py index 712cb6022e2457..2b777acb1ec4fd 100644 --- a/Lib/test/test_capi/test_opt.py +++ b/Lib/test/test_capi/test_opt.py @@ -2167,6 +2167,7 @@ def testfunc(n): self.assertIsNotNone(ex) uops = get_opnames(ex) self.assertNotIn("_LOAD_SMALL_INT", uops) + self.assertIn("_LOAD_CONST_INLINE_BORROW", uops) def global_identity(x): return x diff --git a/Python/optimizer_bytecodes.c b/Python/optimizer_bytecodes.c index db68a81a937403..b9ebd8678e0f1e 100644 --- a/Python/optimizer_bytecodes.c +++ b/Python/optimizer_bytecodes.c @@ -528,7 +528,9 @@ dummy_func(void) { } op(_LOAD_SMALL_INT, (-- value)) { - PyObject *val = PyLong_FromLong(this_instr->oparg); + PyObject *val = PyLong_FromLong(oparg); + assert(val); + assert(_Py_IsImmortal(val)); REPLACE_OP(this_instr, _LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)val); value = sym_new_const(ctx, val); } diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h index 8e72623f02866c..0ba45e1f58fe08 100644 --- a/Python/optimizer_cases.c.h +++ b/Python/optimizer_cases.c.h @@ -79,7 +79,9 @@ case _LOAD_SMALL_INT: { JitOptSymbol *value; - PyObject *val = PyLong_FromLong(this_instr->oparg); + PyObject *val = PyLong_FromLong(oparg); + assert(val); + assert(_Py_IsImmortal(val)); REPLACE_OP(this_instr, _LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)val); value = sym_new_const(ctx, val); stack_pointer[0] = value;