5
5
"""
6
6
7
7
import argparse
8
+ import contextlib
8
9
import os
9
10
import re
10
11
import sys
@@ -51,9 +52,7 @@ def __init__(self, inst: parser.InstDef):
51
52
]
52
53
self .output_effects = self .outputs # For consistency/completeness
53
54
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 :
57
56
"""Write one instruction, sans prologue and epilogue."""
58
57
if dedent < 0 :
59
58
indent += " " * - dedent # DO WE NEED THIS?
@@ -114,9 +113,7 @@ def write(
114
113
if self .cache_offset :
115
114
f .write (f"{ indent } next_instr += { self .cache_offset } ;\n " )
116
115
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 :
120
117
"""Write the instruction body."""
121
118
122
119
# Get lines of text with proper dedelt
@@ -180,7 +177,9 @@ def parse(self) -> None:
180
177
if tkn .text == BEGIN_MARKER :
181
178
break
182
179
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
+ )
184
183
185
184
# Parse until end marker
186
185
self .instrs = {}
@@ -292,7 +291,7 @@ def write_instructions(self, filename: str) -> None:
292
291
n_instrs = 0
293
292
for name , instr in self .instrs .items ():
294
293
if instr .kind != "inst" :
295
- continue # ops are not real instructions
294
+ continue # ops are not real instructions
296
295
n_instrs += 1
297
296
f .write (f"\n { indent } TARGET({ name } ) {{\n " )
298
297
if instr .predicted :
@@ -321,45 +320,80 @@ def write_instructions(self, filename: str) -> None:
321
320
def write_super_macro (
322
321
self , f : typing .TextIO , sup : parser .Super , indent : str = ""
323
322
) -> 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();" )
359
386
360
387
# 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
+ """
363
397
lowest = current = highest = 0
364
398
for instr in components :
365
399
if instr .cache_effects :
@@ -374,7 +408,9 @@ def super_macro_analysis(self, name: str, components: list[Instruction]) -> tupl
374
408
highest = max (highest , current )
375
409
# At this point, 'current' is the net stack effect,
376
410
# 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
378
414
379
415
380
416
def always_exits (block : parser .Block ) -> bool :
0 commit comments