Skip to content

Commit 4cdb25f

Browse files
committed
Improve code generation for super/macro instructions
(But this needs to be cleaned up for maintainability.)
1 parent 2e0d2df commit 4cdb25f

File tree

2 files changed

+81
-27
lines changed

2 files changed

+81
-27
lines changed

Python/generated_cases.c.h

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

Tools/cases_generator/generate_cases.py

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -313,17 +313,41 @@ def write_instructions(self, filename: str) -> None:
313313
f.write(f"{indent} DISPATCH();\n")
314314
f.write(f"{indent}}}\n")
315315

316-
# Write super-instructions
316+
# Write super-instructions and macros
317+
# TODO: Cleanup the hacks
317318
for name, sup in self.supers.items():
318-
components = [self.instrs[name] for name in sup.ops]
319319
f.write(f"\n{indent}TARGET({sup.name}) {{\n")
320+
components = [self.instrs[name] for name in sup.ops]
321+
lowest, highest = self.super_macro_analysis(name, components)
322+
current = 0
323+
for i in range(lowest, current):
324+
f.write(f"{indent} PyObject *_tmp_{i - lowest + 1} = PEEK({-i});\n")
325+
for i in range(current, highest):
326+
f.write(f"{indent} PyObject *_tmp_{i - lowest + 1};\n")
320327
for i, instr in enumerate(components):
321328
if i > 0 and sup.kind == "super":
322329
f.write(f"{indent} NEXTOPARG();\n")
323330
f.write(f"{indent} next_instr++;\n")
324331
f.write(f"{indent} {{\n")
325-
instr.write(f, indent, dedent=-4)
332+
for seffect in reversed(instr.input_effects):
333+
if seffect.name != "unused":
334+
f.write(f"{indent} PyObject *{seffect.name} = _tmp_{current - lowest};\n")
335+
current -= 1
336+
for oeffect in instr.output_effects:
337+
if oeffect.name != "unused":
338+
f.write(f"{indent} PyObject *{oeffect.name};\n")
339+
instr.write_body(f, indent, dedent=-4)
340+
for oeffect in instr.output_effects:
341+
if oeffect.name != "unused":
342+
f.write(f"{indent} _tmp_{current - lowest + 1} = {oeffect.name};\n")
343+
current += 1
326344
f.write(f" {indent}}}\n")
345+
if current > 0:
346+
f.write(f"{indent} STACK_GROW({current});\n")
347+
elif current < 0:
348+
f.write(f"{indent} STACK_SHRINK({-current});\n")
349+
for i in range(lowest, current):
350+
f.write(f"{indent} POKE({i - lowest + 1}, _tmp_{current - i});\n")
327351
f.write(f"{indent} DISPATCH();\n")
328352
f.write(f"{indent}}}\n")
329353

@@ -333,6 +357,25 @@ def write_instructions(self, filename: str) -> None:
333357
file=sys.stderr,
334358
)
335359

360+
# TODO: Move this into analysis phase
361+
def super_macro_analysis(self, name: str, components: list[Instruction]) -> tuple[int, int]:
362+
"""Analyze a super-instruction or macro."""
363+
lowest = current = highest = 0
364+
for instr in components:
365+
if instr.cache_effects:
366+
print(
367+
f"Super-instruction {name!r} has cache effects in {instr.name!r}",
368+
file=sys.stderr,
369+
)
370+
self.errors += 1
371+
current -= len(instr.input_effects)
372+
lowest = min(lowest, current)
373+
current += len(instr.output_effects)
374+
highest = max(highest, current)
375+
# At this point, 'current' is the net stack effect,
376+
# and 'lowest' and 'highest' are the extremes.
377+
return lowest, highest
378+
336379

337380
def always_exits(block: parser.Block) -> bool:
338381
"""Determine whether a block always ends in a return/goto/etc."""

0 commit comments

Comments
 (0)