Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
181d096
Add failing regression tests
reidenong Jan 13, 2026
e30a46b
Refine failing regression tests
reidenong Jan 15, 2026
eba715e
Add new predicate symbol and IS_OP constant narrowing
reidenong Jan 15, 2026
8834e12
Remove comment
reidenong Jan 16, 2026
d828f8c
Refactor predicate optimizer symbol
reidenong Jan 16, 2026
24ac326
Remove unnecessary checks in sym_set_const
reidenong Jan 16, 2026
8c95c5f
Merge branch 'main' into narrowing-to-constants-in-branches-with-is
reidenong Jan 16, 2026
d0a3ef7
Merge branch 'main' into narrowing-to-constants-in-branches-with-is
reidenong Jan 17, 2026
33b8920
Add predicate symbol tests
reidenong Jan 17, 2026
e9548a2
Merge branch 'main' into narrowing-to-constants-in-branches-with-is
reidenong Jan 18, 2026
156b0df
Add optimizer symbol unit tests
reidenong Jan 18, 2026
b84abc3
Add narrowing to constant unit test
reidenong Jan 19, 2026
222c3a7
Merge branch 'main' into narrowing-to-constants-in-branches-with-is
reidenong Jan 19, 2026
ceaf091
Remove unit test
reidenong Jan 19, 2026
fb0f8dc
Refine narrowing checks
reidenong Jan 19, 2026
4601243
Update symbol lattice diagram
reidenong Jan 19, 2026
142eff4
Change to `switch` in predicate narrowing
reidenong Jan 19, 2026
c6f4a6a
Refactor invert in predicate symbol to kind
reidenong Jan 19, 2026
d0f799f
Remove whitespace
reidenong Jan 19, 2026
d98015f
Merge branch 'main' into narrowing-to-constants-in-branches-with-is
reidenong Jan 19, 2026
21997bf
Fix typo
reidenong Jan 19, 2026
bfaa65b
Fix case default
reidenong Jan 19, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Include/internal/pycore_optimizer.h
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,8 @@ extern JitOptRef _Py_uop_sym_new_truthiness(JitOptContext *ctx, JitOptRef value,
extern bool _Py_uop_sym_is_compact_int(JitOptRef sym);
extern JitOptRef _Py_uop_sym_new_compact_int(JitOptContext *ctx);
extern void _Py_uop_sym_set_compact_int(JitOptContext *ctx, JitOptRef sym);
extern JitOptRef _Py_uop_sym_new_predicate(JitOptContext *ctx, JitOptRef lhs_ref, JitOptRef rhs_ref, JitOptPredicateKind kind);
extern void _Py_uop_sym_apply_predicate_narrowing(JitOptContext *ctx, JitOptRef sym, bool branch_is_true);

extern void _Py_uop_abstractcontext_init(JitOptContext *ctx);
extern void _Py_uop_abstractcontext_fini(JitOptContext *ctx);
Expand Down
14 changes: 14 additions & 0 deletions Include/internal/pycore_optimizer_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ typedef enum _JitSymType {
JIT_SYM_TUPLE_TAG = 8,
JIT_SYM_TRUTHINESS_TAG = 9,
JIT_SYM_COMPACT_INT = 10,
JIT_SYM_PREDICATE_TAG = 11,
} JitSymType;

typedef struct _jit_opt_known_class {
Expand Down Expand Up @@ -72,6 +73,18 @@ typedef struct {
uint16_t value;
} JitOptTruthiness;

typedef enum {
JIT_PRED_IS,
JIT_PRED_IS_NOT,
} JitOptPredicateKind;

typedef struct {
uint8_t tag;
uint8_t kind;
uint16_t lhs;
uint16_t rhs;
} JitOptPredicate;

typedef struct {
uint8_t tag;
} JitOptCompactInt;
Expand All @@ -84,6 +97,7 @@ typedef union _jit_opt_symbol {
JitOptTuple tuple;
JitOptTruthiness truthiness;
JitOptCompactInt compact;
JitOptPredicate predicate;
} JitOptSymbol;

// This mimics the _PyStackRef API
Expand Down
60 changes: 52 additions & 8 deletions Lib/test/test_capi/test_opt.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
import _opcode
import contextlib
import gc
import itertools
import os
import sys
import textwrap
import unittest
import gc
import os
import types
import unittest

import _opcode

from test.support import (script_helper, requires_specialization,
import_helper, Py_GIL_DISABLED, requires_jit_enabled,
reset_code)
from test.support import (
Py_GIL_DISABLED,
import_helper,
requires_jit_enabled,
requires_specialization,
reset_code,
script_helper,
)

_testinternalcapi = import_helper.import_module("_testinternalcapi")

Expand Down Expand Up @@ -3534,6 +3538,46 @@ def test_is_none(n):
self.assertIn("_POP_TOP_NOP", uops)
self.assertLessEqual(count_ops(ex, "_POP_TOP"), 2)

def test_is_true_narrows_to_constant(self):
def f(n):
def return_true():
return True

hits = 0
v = return_true()
for i in range(n):
if v is True:
hits += v + 1
return hits

res, ex = self._run_with_optimizer(f, TIER2_THRESHOLD)
self.assertEqual(res, TIER2_THRESHOLD * 2)
self.assertIsNotNone(ex)
uops = get_opnames(ex)

# v + 1 should be constant folded
self.assertNotIn("_BINARY_OP", uops)

def test_is_false_narrows_to_constant(self):
def f(n):
def return_false():
return False

hits = 0
v = return_false()
for i in range(n):
if v is False:
hits += v + 1
return hits

res, ex = self._run_with_optimizer(f, TIER2_THRESHOLD)
self.assertEqual(res, TIER2_THRESHOLD)
self.assertIsNotNone(ex)
uops = get_opnames(ex)

# v + 1 should be constant folded
self.assertNotIn("_BINARY_OP", uops)

def test_for_iter_gen_frame(self):
def f(n):
for i in range(n):
Expand Down
2 changes: 2 additions & 0 deletions Python/optimizer_analysis.c
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,8 @@ add_op(JitOptContext *ctx, _PyUOpInstruction *this_instr,
#define sym_is_compact_int _Py_uop_sym_is_compact_int
#define sym_new_compact_int _Py_uop_sym_new_compact_int
#define sym_new_truthiness _Py_uop_sym_new_truthiness
#define sym_new_predicate _Py_uop_sym_new_predicate
#define sym_apply_predicate_narrowing _Py_uop_sym_apply_predicate_narrowing

#define JUMP_TO_LABEL(label) goto label;

Expand Down
6 changes: 5 additions & 1 deletion Python/optimizer_bytecodes.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ typedef struct _Py_UOpsAbstractFrame _Py_UOpsAbstractFrame;
#define sym_new_compact_int _Py_uop_sym_new_compact_int
#define sym_is_compact_int _Py_uop_sym_is_compact_int
#define sym_new_truthiness _Py_uop_sym_new_truthiness
#define sym_new_predicate _Py_uop_sym_new_predicate
#define sym_apply_predicate_narrowing _Py_uop_sym_apply_predicate_narrowing

extern int
optimize_to_bool(
Expand Down Expand Up @@ -533,7 +535,7 @@ dummy_func(void) {
}

op(_IS_OP, (left, right -- b, l, r)) {
b = sym_new_type(ctx, &PyBool_Type);
b = sym_new_predicate(ctx, left, right, (oparg ? JIT_PRED_IS_NOT : JIT_PRED_IS));
l = left;
r = right;
}
Expand Down Expand Up @@ -1142,6 +1144,7 @@ dummy_func(void) {
assert(value != NULL);
eliminate_pop_guard(this_instr, ctx, value != Py_True);
}
sym_apply_predicate_narrowing(ctx, flag, true);
sym_set_const(flag, Py_True);
}

Expand Down Expand Up @@ -1187,6 +1190,7 @@ dummy_func(void) {
assert(value != NULL);
eliminate_pop_guard(this_instr, ctx, value != Py_False);
}
sym_apply_predicate_narrowing(ctx, flag, false);
sym_set_const(flag, Py_False);
}

Expand Down
4 changes: 3 additions & 1 deletion Python/optimizer_cases.c.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading