diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py index 6d8ad8798de..f11413cc625 100644 --- a/Lib/test/test_capi/test_opt.py +++ b/Lib/test/test_capi/test_opt.py @@ -4662,6 +4662,24 @@ def return_true(): # v + 1 should be constant folded self.assertNotIn("_BINARY_OP", uops) + def test_is_none_narrows_to_constant(self): + def testfunc(n): + value = None + hits = 0 + for _ in range(n): + if value is None: + hits += 1 + return hits + + res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD) + self.assertEqual(res, TIER2_THRESHOLD) + self.assertIsNotNone(ex) + uops = get_opnames(ex) + + self.assertNotIn("_IS_NONE", uops) + self.assertIn("_GUARD_IS_NONE_POP", uops) + self.assertIn("_POP_TOP_NOP", uops) + def test_is_false_narrows_to_constant(self): def f(n): def return_false(): diff --git a/Python/optimizer_bytecodes.c b/Python/optimizer_bytecodes.c index 9b1a6964997..c7fe34bf785 100644 --- a/Python/optimizer_bytecodes.c +++ b/Python/optimizer_bytecodes.c @@ -724,6 +724,16 @@ dummy_func(void) { r = right; } + op(_IS_NONE, (value -- b)) { + if (sym_is_const(ctx, value)) { + PyObject *value_o = sym_get_const(ctx, value); + b = sym_new_const(ctx, Py_IsNone(value_o) ? Py_True : Py_False); + } + else { + b = sym_new_type(ctx, &PyBool_Type); + } + } + op(_CONTAINS_OP, (left, right -- b, l, r)) { b = sym_new_type(ctx, &PyBool_Type); l = left; diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h index e5c67b6cf0e..98287e7f841 100644 --- a/Python/optimizer_cases.c.h +++ b/Python/optimizer_cases.c.h @@ -3193,8 +3193,16 @@ /* _POP_JUMP_IF_TRUE is not a viable micro-op for tier 2 */ case _IS_NONE: { + JitOptRef value; JitOptRef b; - b = sym_new_not_null(ctx); + value = stack_pointer[-1]; + if (sym_is_const(ctx, value)) { + PyObject *value_o = sym_get_const(ctx, value); + b = sym_new_const(ctx, Py_IsNone(value_o) ? Py_True : Py_False); + } + else { + b = sym_new_type(ctx, &PyBool_Type); + } stack_pointer[-1] = b; break; }