Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit fbfab4f

Browse files
authored
GH-120024: Refactor code generators to uses classes for emitting code. (GH-122730)
1 parent ce0d66c commit fbfab4f

File tree

4 files changed

+272
-274
lines changed

4 files changed

+272
-274
lines changed

Tools/cases_generator/generators_common.py

Lines changed: 150 additions & 148 deletions
Original file line numberDiff line numberDiff line change
@@ -57,169 +57,171 @@ def emit_to(out: CWriter, tkn_iter: Iterator[Token], end: str) -> None:
5757
parens -= 1
5858
out.emit(tkn)
5959

60+
ReplacementFunctionType = Callable[
61+
[Token, Iterator[Token], Uop, Stack, Instruction | None], None
62+
]
6063

61-
def replace_deopt(
62-
out: CWriter,
63-
tkn: Token,
64-
tkn_iter: Iterator[Token],
65-
uop: Uop,
66-
unused: Stack,
67-
inst: Instruction | None,
68-
) -> None:
69-
out.emit_at("DEOPT_IF", tkn)
70-
out.emit(next(tkn_iter))
71-
emit_to(out, tkn_iter, "RPAREN")
72-
next(tkn_iter) # Semi colon
73-
out.emit(", ")
74-
assert inst is not None
75-
assert inst.family is not None
76-
out.emit(inst.family.name)
77-
out.emit(");\n")
78-
64+
class Emitter:
7965

80-
def replace_error(
81-
out: CWriter,
82-
tkn: Token,
83-
tkn_iter: Iterator[Token],
84-
uop: Uop,
85-
stack: Stack,
86-
inst: Instruction | None,
87-
) -> None:
88-
out.emit_at("if ", tkn)
89-
out.emit(next(tkn_iter))
90-
emit_to(out, tkn_iter, "COMMA")
91-
label = next(tkn_iter).text
92-
next(tkn_iter) # RPAREN
93-
next(tkn_iter) # Semi colon
94-
out.emit(") ")
95-
c_offset = stack.peek_offset()
96-
try:
97-
offset = -int(c_offset)
98-
except ValueError:
99-
offset = -1
100-
if offset > 0:
101-
out.emit(f"goto pop_{offset}_")
102-
out.emit(label)
103-
out.emit(";\n")
104-
elif offset == 0:
105-
out.emit("goto ")
106-
out.emit(label)
107-
out.emit(";\n")
108-
else:
109-
out.emit("{\n")
110-
stack.flush_locally(out)
111-
out.emit("goto ")
112-
out.emit(label)
113-
out.emit(";\n")
114-
out.emit("}\n")
66+
out: CWriter
67+
_replacers: dict[str, ReplacementFunctionType]
11568

69+
def __init__(self, out: CWriter):
70+
self._replacers = {
71+
"EXIT_IF": self.exit_if,
72+
"DEOPT_IF": self.deopt_if,
73+
"ERROR_IF": self.error_if,
74+
"ERROR_NO_POP": self.error_no_pop,
75+
"DECREF_INPUTS": self.decref_inputs,
76+
"CHECK_EVAL_BREAKER": self.check_eval_breaker,
77+
"SYNC_SP": self.sync_sp,
78+
}
79+
self.out = out
11680

117-
def replace_error_no_pop(
118-
out: CWriter,
119-
tkn: Token,
120-
tkn_iter: Iterator[Token],
121-
uop: Uop,
122-
stack: Stack,
123-
inst: Instruction | None,
124-
) -> None:
125-
next(tkn_iter) # LPAREN
126-
next(tkn_iter) # RPAREN
127-
next(tkn_iter) # Semi colon
128-
out.emit_at("goto error;", tkn)
81+
def deopt_if(
82+
self,
83+
tkn: Token,
84+
tkn_iter: Iterator[Token],
85+
uop: Uop,
86+
unused: Stack,
87+
inst: Instruction | None,
88+
) -> None:
89+
self.out.emit_at("DEOPT_IF", tkn)
90+
self.out.emit(next(tkn_iter))
91+
emit_to(self.out, tkn_iter, "RPAREN")
92+
next(tkn_iter) # Semi colon
93+
self.out.emit(", ")
94+
assert inst is not None
95+
assert inst.family is not None
96+
self.out.emit(inst.family.name)
97+
self.out.emit(");\n")
12998

99+
exit_if = deopt_if
130100

131-
def replace_decrefs(
132-
out: CWriter,
133-
tkn: Token,
134-
tkn_iter: Iterator[Token],
135-
uop: Uop,
136-
stack: Stack,
137-
inst: Instruction | None,
138-
) -> None:
139-
next(tkn_iter)
140-
next(tkn_iter)
141-
next(tkn_iter)
142-
out.emit_at("", tkn)
143-
for var in uop.stack.inputs:
144-
if var.name == "unused" or var.name == "null" or var.peek:
145-
continue
146-
if var.size:
147-
out.emit(f"for (int _i = {var.size}; --_i >= 0;) {{\n")
148-
out.emit(f"PyStackRef_CLOSE({var.name}[_i]);\n")
149-
out.emit("}\n")
150-
elif var.condition:
151-
if var.condition == "1":
152-
out.emit(f"PyStackRef_CLOSE({var.name});\n")
153-
elif var.condition != "0":
154-
out.emit(f"PyStackRef_XCLOSE({var.name});\n")
101+
def error_if(
102+
self,
103+
tkn: Token,
104+
tkn_iter: Iterator[Token],
105+
uop: Uop,
106+
stack: Stack,
107+
inst: Instruction | None,
108+
) -> None:
109+
self.out.emit_at("if ", tkn)
110+
self.out.emit(next(tkn_iter))
111+
emit_to(self.out, tkn_iter, "COMMA")
112+
label = next(tkn_iter).text
113+
next(tkn_iter) # RPAREN
114+
next(tkn_iter) # Semi colon
115+
self.out.emit(") ")
116+
c_offset = stack.peek_offset()
117+
try:
118+
offset = -int(c_offset)
119+
except ValueError:
120+
offset = -1
121+
if offset > 0:
122+
self.out.emit(f"goto pop_{offset}_")
123+
self.out.emit(label)
124+
self.out.emit(";\n")
125+
elif offset == 0:
126+
self.out.emit("goto ")
127+
self.out.emit(label)
128+
self.out.emit(";\n")
155129
else:
156-
out.emit(f"PyStackRef_CLOSE({var.name});\n")
130+
self.out.emit("{\n")
131+
stack.flush_locally(self.out)
132+
self.out.emit("goto ")
133+
self.out.emit(label)
134+
self.out.emit(";\n")
135+
self.out.emit("}\n")
157136

137+
def error_no_pop(
138+
self,
139+
tkn: Token,
140+
tkn_iter: Iterator[Token],
141+
uop: Uop,
142+
stack: Stack,
143+
inst: Instruction | None,
144+
) -> None:
145+
next(tkn_iter) # LPAREN
146+
next(tkn_iter) # RPAREN
147+
next(tkn_iter) # Semi colon
148+
self.out.emit_at("goto error;", tkn)
158149

159-
def replace_sync_sp(
160-
out: CWriter,
161-
tkn: Token,
162-
tkn_iter: Iterator[Token],
163-
uop: Uop,
164-
stack: Stack,
165-
inst: Instruction | None,
166-
) -> None:
167-
next(tkn_iter)
168-
next(tkn_iter)
169-
next(tkn_iter)
170-
stack.flush(out)
171-
150+
def decref_inputs(
151+
self,
152+
tkn: Token,
153+
tkn_iter: Iterator[Token],
154+
uop: Uop,
155+
stack: Stack,
156+
inst: Instruction | None,
157+
) -> None:
158+
next(tkn_iter)
159+
next(tkn_iter)
160+
next(tkn_iter)
161+
self.out.emit_at("", tkn)
162+
for var in uop.stack.inputs:
163+
if var.name == "unused" or var.name == "null" or var.peek:
164+
continue
165+
if var.size:
166+
self.out.emit(f"for (int _i = {var.size}; --_i >= 0;) {{\n")
167+
self.out.emit(f"PyStackRef_CLOSE({var.name}[_i]);\n")
168+
self.out.emit("}\n")
169+
elif var.condition:
170+
if var.condition == "1":
171+
self.out.emit(f"PyStackRef_CLOSE({var.name});\n")
172+
elif var.condition != "0":
173+
self.out.emit(f"PyStackRef_XCLOSE({var.name});\n")
174+
else:
175+
self.out.emit(f"PyStackRef_CLOSE({var.name});\n")
172176

173-
def replace_check_eval_breaker(
174-
out: CWriter,
175-
tkn: Token,
176-
tkn_iter: Iterator[Token],
177-
uop: Uop,
178-
stack: Stack,
179-
inst: Instruction | None,
180-
) -> None:
181-
next(tkn_iter)
182-
next(tkn_iter)
183-
next(tkn_iter)
184-
if not uop.properties.ends_with_eval_breaker:
185-
out.emit_at("CHECK_EVAL_BREAKER();", tkn)
186177

178+
def sync_sp(
179+
self,
180+
tkn: Token,
181+
tkn_iter: Iterator[Token],
182+
uop: Uop,
183+
stack: Stack,
184+
inst: Instruction | None,
185+
) -> None:
186+
next(tkn_iter)
187+
next(tkn_iter)
188+
next(tkn_iter)
189+
stack.flush(self.out)
187190

188-
REPLACEMENT_FUNCTIONS = {
189-
"EXIT_IF": replace_deopt,
190-
"DEOPT_IF": replace_deopt,
191-
"ERROR_IF": replace_error,
192-
"ERROR_NO_POP": replace_error_no_pop,
193-
"DECREF_INPUTS": replace_decrefs,
194-
"CHECK_EVAL_BREAKER": replace_check_eval_breaker,
195-
"SYNC_SP": replace_sync_sp,
196-
}
197-
198-
ReplacementFunctionType = Callable[
199-
[CWriter, Token, Iterator[Token], Uop, Stack, Instruction | None], None
200-
]
201191

192+
def check_eval_breaker(
193+
self,
194+
tkn: Token,
195+
tkn_iter: Iterator[Token],
196+
uop: Uop,
197+
stack: Stack,
198+
inst: Instruction | None,
199+
) -> None:
200+
next(tkn_iter)
201+
next(tkn_iter)
202+
next(tkn_iter)
203+
if not uop.properties.ends_with_eval_breaker:
204+
self.out.emit_at("CHECK_EVAL_BREAKER();", tkn)
202205

203-
def emit_tokens(
204-
out: CWriter,
205-
uop: Uop,
206-
stack: Stack,
207-
inst: Instruction | None,
208-
replacement_functions: Mapping[
209-
str, ReplacementFunctionType
210-
] = REPLACEMENT_FUNCTIONS,
211-
) -> None:
212-
tkns = uop.body[1:-1]
213-
if not tkns:
214-
return
215-
tkn_iter = iter(tkns)
216-
out.start_line()
217-
for tkn in tkn_iter:
218-
if tkn.kind == "IDENTIFIER" and tkn.text in replacement_functions:
219-
replacement_functions[tkn.text](out, tkn, tkn_iter, uop, stack, inst)
220-
else:
221-
out.emit(tkn)
206+
def emit_tokens(
207+
self,
208+
uop: Uop,
209+
stack: Stack,
210+
inst: Instruction | None,
211+
) -> None:
212+
tkns = uop.body[1:-1]
213+
if not tkns:
214+
return
215+
tkn_iter = iter(tkns)
216+
self.out.start_line()
217+
for tkn in tkn_iter:
218+
if tkn.kind == "IDENTIFIER" and tkn.text in self._replacers:
219+
self._replacers[tkn.text](tkn, tkn_iter, uop, stack, inst)
220+
else:
221+
self.out.emit(tkn)
222222

223+
def emit(self, txt: str | Token) -> None:
224+
self.out.emit(txt)
223225

224226
def cflags(p: Properties) -> str:
225227
flags: list[str] = []

Tools/cases_generator/optimizer_generator.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,7 @@
1717
DEFAULT_INPUT,
1818
ROOT,
1919
write_header,
20-
emit_tokens,
21-
replace_sync_sp,
20+
Emitter,
2221
)
2322
from cwriter import CWriter
2423
from typing import TextIO, Iterator
@@ -89,6 +88,10 @@ def emit_default(out: CWriter, uop: Uop) -> None:
8988
else:
9089
out.emit(f"{var.name} = sym_new_not_null(ctx);\n")
9190

91+
class OptimizerEmitter(Emitter):
92+
93+
pass
94+
9295

9396
def write_uop(
9497
override: Uop | None,
@@ -126,11 +129,8 @@ def write_uop(
126129
cast = f"uint{cache.size*16}_t"
127130
out.emit(f"{type}{cache.name} = ({cast})this_instr->operand;\n")
128131
if override:
129-
replacement_funcs = {
130-
"DECREF_INPUTS": decref_inputs,
131-
"SYNC_SP": replace_sync_sp,
132-
}
133-
emit_tokens(out, override, stack, None, replacement_funcs)
132+
emitter = OptimizerEmitter(out)
133+
emitter.emit_tokens(override, stack, None)
134134
else:
135135
emit_default(out, uop)
136136

0 commit comments

Comments
 (0)