Skip to content

Commit 5992238

Browse files
authored
gh-146381: Constant-fold frozendict subscript lookups via REPLACE_OPCODE_IF_EVALUATES_PURE (gh-146490)
1 parent a933e9c commit 5992238

File tree

4 files changed

+86
-1
lines changed

4 files changed

+86
-1
lines changed

Lib/test/test_capi/test_opt.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@
2020
#For test of issue 136154
2121
GLOBAL_136154 = 42
2222

23+
# For frozendict JIT tests
24+
FROZEN_DICT_CONST = frozendict(x=1, y=2)
25+
26+
2327
@contextlib.contextmanager
2428
def clear_executors(func):
2529
# Clear executors in func before and after running a block
@@ -4155,6 +4159,35 @@ def testfunc(n):
41554159
self.assertLessEqual(count_ops(ex, "_POP_TOP_INT"), 1)
41564160
self.assertIn("_POP_TOP_NOP", uops)
41574161

4162+
def test_binary_subscr_frozendict_lowering(self):
4163+
def testfunc(n):
4164+
x = 0
4165+
for _ in range(n):
4166+
x += FROZEN_DICT_CONST['x']
4167+
return x
4168+
4169+
res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD)
4170+
self.assertEqual(res, TIER2_THRESHOLD)
4171+
self.assertIsNotNone(ex)
4172+
uops = get_opnames(ex)
4173+
self.assertIn("_INSERT_2_LOAD_CONST_INLINE_BORROW", uops)
4174+
self.assertNotIn("_BINARY_OP_SUBSCR_DICT", uops)
4175+
4176+
def test_binary_subscr_frozendict_const_fold(self):
4177+
def testfunc(n):
4178+
x = 0
4179+
for _ in range(n):
4180+
if FROZEN_DICT_CONST['x'] == 1:
4181+
x += 1
4182+
return x
4183+
4184+
res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD)
4185+
self.assertEqual(res, TIER2_THRESHOLD)
4186+
self.assertIsNotNone(ex)
4187+
uops = get_opnames(ex)
4188+
# lookup result is folded to constant 1, so comparison is optimized away
4189+
self.assertNotIn("_COMPARE_OP_INT", uops)
4190+
41584191
def test_binary_subscr_list_slice(self):
41594192
def testfunc(n):
41604193
x = 0

Python/optimizer_bytecodes.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -485,6 +485,9 @@ dummy_func(void) {
485485
res = sym_new_not_null(ctx);
486486
ds = dict_st;
487487
ss = sub_st;
488+
if (sym_matches_type(dict_st, &PyFrozenDict_Type)) {
489+
REPLACE_OPCODE_IF_EVALUATES_PURE(dict_st, sub_st, res);
490+
}
488491
}
489492

490493
op(_BINARY_OP_SUBSCR_LIST_SLICE, (list_st, sub_st -- res, ls, ss)) {

Python/optimizer_cases.c.h

Lines changed: 48 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Python/optimizer_symbols.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,8 @@ _Py_uop_sym_is_safe_const(JitOptContext *ctx, JitOptRef sym)
282282
return (typ == &PyUnicode_Type) ||
283283
(typ == &PyFloat_Type) ||
284284
(typ == &_PyNone_Type) ||
285-
(typ == &PyBool_Type);
285+
(typ == &PyBool_Type) ||
286+
(typ == &PyFrozenDict_Type);
286287
}
287288

288289
void

0 commit comments

Comments
 (0)