8000 gh-136183: Deal with escapes in JIT optimizer's constant evaluator (G… · python/cpython@b330897 · GitHub
[go: up one dir, main page]

Skip to content

Commit b330897

Browse files
gh-136183: Deal with escapes in JIT optimizer's constant evaluator (GH-136184)
1 parent f41e9c7 commit b330897

File tree

6 files changed

+77
-7
lines changed

6 files changed

+77
-7
lines changed

.github/workflows/jit.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ on:
55
- '**jit**'
66
- 'Python/bytecodes.c'
77
- 'Python/optimizer*.c'
8+
- 'Python/executor_cases.c.h'
9+
- 'Python/optimizer_cases.c.h'
810
- '!Python/perf_jit_trampoline.c'
911
- '!**/*.md'
1012
- '!**/*.ini'
@@ -13,6 +15,8 @@ on:
1315
- '**jit**'
1416
- 'Python/bytecodes.c'
1517
- 'Python/optimizer*.c'
18+
- 'Python/executor_cases.c.h'
19+
- 'Python/optimizer_cases.c.h'
1620
- '!Python/perf_jit_trampoline.c'
1721
- '!**/*.md'
1822
- '!**/*.ini'

Lib/test/test_capi/test_opt.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2451,6 +2451,21 @@ def testfunc(n):
24512451
self.assertNotIn("_GUARD_TOS_FLOAT", uops)
24522452
self.assertNotIn("_GUARD_NOS_FLOAT", uops)
24532453

2454+
def test_binary_op_constant_evaluate(self):
2455+
def testfunc(n):
2456+
for _ in range(n):
2457+
2 ** 65
2458+
2459+
testfunc(TIER2_THRESHOLD)
2460+
2461+
ex = get_first_executor(testfunc)
2462+
self.assertIsNotNone(ex)
2463+
uops = get_opnames(ex)
2464+
2465+
# For now... until we constant propagate it away.
2466+
self.assertIn("_BINARY_OP", uops)
2467+
2468+
24542469
def global_identity(x):
24552470
return x
24562471

Lib/test/test_generated_cases.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2398,6 +2398,53 @@ def test_replace_opcode_uop_body_copied_in_complex(self):
23982398
"""
23992399
self.run_cases_test(input, input2, output)
24002400

2401+
def test_replace_opcode_escaping_uop_body_copied_in_complex(self):
2402+
input = """
2403+
pure op(OP, (foo -- res)) {
2404+
if (foo) {
2405+
res = ESCAPING_CODE(foo);
2406+
}
2407+
else {
2408+
res = 1;
2409+
}
2410+
}
2411+
"""
2412+
input2 = """
2413+
op(OP, (foo -- res)) {
2414+
REPLACE_OPCODE_IF_EVALUATES_PURE(foo);
2415+
res = sym_new_known(ctx, foo);
2416+
}
2417+
"""
2418+
output = """
2419+
case OP: {
2420+
JitOptRef foo;
2421+
JitOptRef res;
2422+
foo = stack_pointer[-1];
2423+
if (
2424+
sym_is_safe_const(ctx, foo)
2425+
) {
2426+
JitOptRef foo_sym = foo;
2427+
_PyStackRef foo = sym_get_const_as_stackref(ctx, foo_sym);
2428+
_PyStackRef res_stackref;
2429+
/* Start of uop copied from bytecodes for constant evaluation */
2430+
if (foo) {
2431+
res_stackref = ESCAPING_CODE(foo);
2432+
}
2433+
else {
2434+
res_stackref = 1;
2435+
}
2436+
/* End of uop copied from bytecodes for constant evaluation */
2437+
res = sym_new_const_steal(ctx, PyStackRef_AsPyObjectSteal(res_stackref));
2438+
stack_pointer[-1] = res;
2439+
break;
2440+
}
2441+
res = sym_new_known(ctx, foo);
2442+
stack_pointer[-1] = res;
2443+
break;
2444+
}
2445+
"""
2446+
self.run_cases_test(input, input2, output)
2447+
24012448
def test_replace_opocode_uop_reject_array_effects(self):
24022449
input = """
24032450
pure op(OP, (foo[2] -- res)) {

Python/optimizer_cases.c.h

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

Tools/cases_generator/generators_common.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -106,8 +106,9 @@ class Emitter:
106106
out: CWriter
107107
labels: dict[str, Label]
108108
_replacers: dict[str, ReplacementFunctionType]
109+
cannot_escape: bool
109110

110-
def __init__(self, out: CWriter, labels: dict[str, Label]):
111+
def __init__(self, out: CWriter, labels: dict[str, Label], cannot_escape: bool = False):
111112
self._replacers = {
112113
"EXIT_IF": self.exit_if,
113114
"DEOPT_IF": self.deopt_if,
@@ -127,6 +128,7 @@ def __init__(self, out: CWriter, labels: dict[str, Label]):
127128
}
128129
self.out = out
129130
self.labels = labels
131+
self.cannot_escape = cannot_escape
130132

131133
def dispatch(
132134
self,
@@ -238,7 +240,8 @@ def decref_inputs(
238240
next(tkn_iter)
239241
self._print_storage("DECREF_INPUTS", storage)
240242
try:
241-
storage.close_inputs(self.out)
243+
if not self.cannot_escape:
244+
storage.close_inputs(self.out)
242245
except StackError as ex:
243246
raise analysis_error(ex.args[0], tkn)
244247
except Exception as ex:
@@ -476,7 +479,7 @@ def emit_SimpleStmt(
476479
reachable = True
477480
tkn = stmt.contents[-1]
478481
try:
479-
if stmt in uop.properties.escaping_calls:
482+
if stmt in uop.properties.escaping_calls and not self.cannot_escape:
480483
escape = uop.properties.escaping_calls[stmt]
481484
if escape.kills is not None:
482485
self.stackref_kill(escape.kills, storage, True)
@@ -513,7 +516,7 @@ def emit_SimpleStmt(
513516
self.out.emit(tkn)
514517
else:
515518
self.out.emit(tkn)
516-
if stmt in uop.properties.escaping_calls:
519+
if stmt in uop.properties.escaping_calls and not self.cannot_escape:
517520
self.emit_reload(storage)
518521
return reachable, None, storage
519522
except StackError as ex:

Tools/cases_generator/optimizer_generator.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,7 @@ def __init__(self, out: CWriter, labels: dict[str, Label], original_uop: Uop, st
245245
outp.name: self.emit_stackref_override for outp in self.original_uop.stack.outputs
246246
}
247247
self._replacers = {**self._replacers, **overrides}
248+
self.cannot_escape = True
248249

249250
def emit_to_with_replacement(
250251
self,

0 commit comments

Comments
 (0)
0