diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py index 2a1abe178e5d84..eadda8271bfb6c 100644 --- a/Lib/test/test_capi/test_opt.py +++ b/Lib/test/test_capi/test_opt.py @@ -4554,6 +4554,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 0708fed6c5c803..b08b64f47c88d9 100644 --- a/Python/optimizer_bytecodes.c +++ b/Python/optimizer_bytecodes.c @@ -710,6 +710,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 93b60f64e14ae1..4c6613e4e9fe5c 100644 --- a/Python/optimizer_cases.c.h +++ b/Python/optimizer_cases.c.h @@ -3167,8 +3167,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; }