https://github.com/python/cpython/commit/5e74d920c80f4bf4d44d84838aed81423c42b9dd
commit: 5e74d920c80f4bf4d44d84838aed81423c42b9dd
branch: main
author: Neko Asakura <[email protected]>
committer: Fidget-Spinner <[email protected]>
date: 2026-04-13T20:56:29+08:00
summary:
gh-148285: Allow recording uops after specializing uops (GH-148482)
files:
M Lib/test/test_generated_cases.py
M Tools/cases_generator/analyzer.py
diff --git a/Lib/test/test_generated_cases.py b/Lib/test/test_generated_cases.py
index 57991b5b6b859c..bb831fa984c34b 100644
--- a/Lib/test/test_generated_cases.py
+++ b/Lib/test/test_generated_cases.py
@@ -1890,6 +1890,64 @@ def test_reassigning_dead_inputs(self):
"""
self.run_cases_test(input, output)
+ def test_recording_after_specializing_with_cache(self):
+ input = """
+ specializing op(SPEC, (counter/1 --)) {
+ spam;
+ }
+
+ tier2 op(REC, (--)) {
+ RECORD_VALUE(0);
+ }
+
+ op(BODY, (--)) {
+ ham;
+ }
+
+ macro(OP) = SPEC + unused/2 + REC + BODY;
+ """
+ output = """
+ TARGET(OP) {
+ #if _Py_TAIL_CALL_INTERP
+ int opcode = OP;
+ (void)(opcode);
+ #endif
+ _Py_CODEUNIT* const this_instr = next_instr;
+ (void)this_instr;
+ frame->instr_ptr = next_instr;
+ next_instr += 4;
+ INSTRUCTION_STATS(OP);
+ // SPEC
+ {
+ uint16_t counter = read_u16(&this_instr[1].cache);
+ (void)counter;
+ spam;
+ }
+ /* Skip 2 cache entries */
+ // BODY
+ {
+ ham;
+ }
+ DISPATCH();
+ }
+ """
+ self.run_cases_test(input, output)
+
+ def test_recording_after_non_specializing(self):
+ input = """
+ op(REGULAR, (--)) {
+ spam;
+ }
+
+ tier2 op(REC, (--)) {
+ RECORD_VALUE(0);
+ }
+
+ macro(OP) = REGULAR + REC;
+ """
+ with self.assertRaisesRegex(SyntaxError, "Recording uop"):
+ self.run_cases_test(input, "")
+
class TestGeneratedAbstractCases(unittest.TestCase):
def setUp(self) -> None:
diff --git a/Tools/cases_generator/analyzer.py
b/Tools/cases_generator/analyzer.py
index 6ba9c43ef1f0c3..100de4c7250907 100644
--- a/Tools/cases_generator/analyzer.py
+++ b/Tools/cases_generator/analyzer.py
@@ -1132,7 +1132,9 @@ def add_macro(
macro: parser.Macro, instructions: dict[str, Instruction], uops: dict[str,
Uop]
) -> None:
parts: list[Part] = []
- first = True
+ # Track the last non-specializing uop seen, so that recording uops
+ # can follow specializing ones without triggering the position check.
+ prev_uop: Uop | None = None
for part in macro.uops:
match part:
case parser.OpName():
@@ -1144,12 +1146,14 @@ def add_macro(
f"No Uop named {part.name}", macro.tokens[0]
)
uop = uops[part.name]
- if uop.properties.records_value and not first:
+ if uop.properties.records_value and prev_uop is not None:
raise analysis_error(
- f"Recording uop {part.name} must be first in
macro",
+ f"Recording uop {part.name} is not allowed "
+ f"after non-specializing uops in macro",
macro.tokens[0])
parts.append(uop)
- first = False
+ if "specializing" not in uop.annotations:
+ prev_uop = uop
case parser.CacheEffect():
parts.append(Skip(part.size))
case _:
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]