Skip to content

Commit 0f12c40

Browse files
committed
Reduce the fiddling with integers in super analysis
Also: - Add helpers for indent management; - Reformat with black.
1 parent 881357e commit 0f12c40

File tree

1 file changed

+82
-46
lines changed

1 file changed

+82
-46
lines changed

Tools/cases_generator/generate_cases.py

Lines changed: 82 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
"""
66

77
import argparse
8+
import contextlib
89
import os
910
import re
1011
import sys
@@ -51,9 +52,7 @@ def __init__(self, inst: parser.InstDef):
5152
]
5253
self.output_effects = self.outputs # For consistency/completeness
5354

54-
def write(
55-
self, f: typing.TextIO, indent: str, dedent: int = 0
56-
) -> None:
55+
def write(self, f: typing.TextIO, indent: str, dedent: int = 0) -> None:
5756
"""Write one instruction, sans prologue and epilogue."""
5857
if dedent < 0:
5958
indent += " " * -dedent # DO WE NEED THIS?
@@ -114,9 +113,7 @@ def write(
114113
if self.cache_offset:
115114
f.write(f"{indent} next_instr += {self.cache_offset};\n")
116115

117-
def write_body(
118-
self, f: typing.TextIO, ndent: str, dedent: int
119-
) -> None:
116+
def write_body(self, f: typing.TextIO, ndent: str, dedent: int) -> None:
120117
"""Write the instruction body."""
121118

122119
# Get lines of text with proper dedelt
@@ -180,7 +177,9 @@ def parse(self) -> None:
180177
if tkn.text == BEGIN_MARKER:
181178
break
182179
else:
183-
raise psr.make_syntax_error(f"Couldn't find {BEGIN_MARKER!r} in {psr.filename}")
180+
raise psr.make_syntax_error(
181+
f"Couldn't find {BEGIN_MARKER!r} in {psr.filename}"
182+
)
184183

185184
# Parse until end marker
186185
self.instrs = {}
@@ -292,7 +291,7 @@ def write_instructions(self, filename: str) -> None:
292291
n_instrs = 0
293292
for name, instr in self.instrs.items():
294293
if instr.kind != "inst":
295-
continue # ops are not real instructions
294+
continue # ops are not real instructions
296295
n_instrs += 1
297296
f.write(f"\n{indent}TARGET({name}) {{\n")
298297
if instr.predicted:
@@ -321,45 +320,80 @@ def write_instructions(self, filename: str) -> None:
321320
def write_super_macro(
322321
self, f: typing.TextIO, sup: parser.Super, indent: str = ""
323322
) -> None:
324-
f.write(f"\n{indent}TARGET({sup.name}) {{\n")
325-
components = [self.instrs[name] for name in sup.ops]
326-
lowest, highest = self.super_macro_analysis(sup.name, components)
327-
# TODO: Rename tmp variables _tmp_A, _tmp_B, etc.
328-
current = 0
329-
for i in range(lowest, current):
330-
f.write(f"{indent} PyObject *_tmp_{i - lowest + 1} = PEEK({-i});\n")
331-
for i in range(current, highest):
332-
f.write(f"{indent} PyObject *_tmp_{i - lowest + 1};\n")
333-
for i, instr in enumerate(components):
334-
if i > 0 and sup.kind == "super":
335-
f.write(f"{indent} NEXTOPARG();\n")
336-
f.write(f"{indent} next_instr++;\n")
337-
f.write(f"{indent} {{\n")
338-
for seffect in reversed(instr.input_effects):
339-
if seffect.name != "unused":
340-
f.write(f"{indent} PyObject *{seffect.name} = _tmp_{current - lowest};\n")
341-
current -= 1
342-
for oeffect in instr.output_effects:
343-
if oeffect.name != "unused":
344-
f.write(f"{indent} PyObject *{oeffect.name};\n")
345-
instr.write_body(f, indent, dedent=-4)
346-
for oeffect in instr.output_effects:
347-
if oeffect.name != "unused":
348-
f.write(f"{indent} _tmp_{current - lowest + 1} = {oeffect.name};\n")
349-
current += 1
350-
f.write(f" {indent}}}\n")
351-
if current > 0:
352-
f.write(f"{indent} STACK_GROW({current});\n")
353-
elif current < 0:
354-
f.write(f"{indent} STACK_SHRINK({-current});\n")
355-
for i in range(lowest, current):
356-
f.write(f"{indent} POKE({i - lowest + 1}, _tmp_{current - i});\n")
357-
f.write(f"{indent} DISPATCH();\n")
358-
f.write(f"{indent}}}\n")
323+
324+
# TODO: Make write() and block() methods of some Formatter class
325+
def write(arg: str) -> None:
326+
if arg:
327+
f.write(f"{indent}{arg}\n")
328+
else:
329+
f.write("\n")
330+
331+
@contextlib.contextmanager
332+
def block(head: str):
333+
if head:
334+
write(head + " {")
335+
else:
336+
write("{")
337+
nonlocal indent
338+
indent += " "
339+
yield
340+
indent = indent[:-4]
341+
write("}")
342+
343+
write("")
344+
with block(f"TARGET({sup.name})"):
345+
components = [self.instrs[name] for name in sup.ops]
346+
stack, nbelow = self.super_macro_analysis(sup.name, components)
347+
sp = nbelow
348+
349+
for i, var in enumerate(stack):
350+
if i < sp:
351+
write(f"PyObject *{var} = PEEK({sp - i});")
352+
else:
353+
write(f"PyObject *{var};")
354+
355+
for i, instr in enumerate(components):
356+
if i > 0 and sup.kind == "super":
357+
write(f"NEXTOPARG();")
358+
write(f"next_instr++;")
359+
360+
with block(""):
361+
instack = stack[sp - len(instr.input_effects) : sp]
362+
for var, ineffect in zip(instack, instr.input_effects):
363+
if ineffect.name != "unused":
364+
write(f"PyObject *{ineffect.name} = {var};")
365+
for outeffect in instr.output_effects:
366+
if outeffect.name != "unused":
367+
write(f"PyObject *{outeffect.name};")
368+
369+
instr.write_body(f, indent, dedent=-4)
370+
371+
sp -= len(instack)
372+
nout = len(instr.output_effects)
373+
sp += nout
374+
outstack = stack[sp - nout : sp]
375+
for var, outeffect in zip(outstack, instr.output_effects):
376+
if outeffect.name != "unused":
377+
write(f"{var} = {outeffect.name};")
378+
379+
if sp > nbelow:
380+
write(f"STACK_GROW({sp - nbelow});")
381+
elif sp < nbelow:
382+
write(f"STACK_SHRINK({nbelow - sp});")
383+
for i, var in enumerate(reversed(stack[:sp]), 1):
384+
write(f"POKE({i}, {var});")
385+
write(f"DISPATCH();")
359386

360387
# 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."""
388+
def super_macro_analysis(
389+
self, name: str, components: list[Instruction]
390+
) -> tuple[list[str], int]:
391+
"""Analyze a super-instruction or macro.
392+
393+
Print an error if there's a cache effect (which we don't support yet).
394+
395+
Return the list of variable names and the initial stack pointer.
396+
"""
363397
lowest = current = highest = 0
364398
for instr in components:
365399
if instr.cache_effects:
@@ -374,7 +408,9 @@ def super_macro_analysis(self, name: str, components: list[Instruction]) -> tupl
374408
highest = max(highest, current)
375409
# At this point, 'current' is the net stack effect,
376410
# and 'lowest' and 'highest' are the extremes.
377-
return lowest, highest
411+
# Note that 'lowest' may be negative.
412+
stack = [f"_tmp_{i+1}" for i in range(highest - lowest)]
413+
return stack, -lowest
378414

379415

380416
def always_exits(block: parser.Block) -> bool:

0 commit comments

Comments
 (0)