Skip to content

Commit 507c80a

Browse files
Use replacer
1 parent 3896775 commit 507c80a

File tree

3 files changed

+87
-117
lines changed

3 files changed

+87
-117
lines changed

Python/optimizer_cases.c.h

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

Tools/cases_generator/analyzer.py

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -520,12 +520,6 @@ def variable_used(node: parser.CodeDef, name: str) -> bool:
520520
)
521521

522522

523-
def uop_variable_used(uop: Uop, text: str) -> bool:
524-
return any(
525-
token.kind == "IDENTIFIER" and token.text == text for token in uop.body.tokens()
526-
)
527-
528-
529523
def oparg_used(node: parser.CodeDef) -> bool:
530524
"""Determine whether `oparg` is used in a node."""
531525
return any(

Tools/cases_generator/optimizer_generator.py

Lines changed: 48 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
analysis_error,
1616
CodeSection,
1717
Label,
18-
uop_variable_used,
1918
)
2019
from generators_common import (
2120
DEFAULT_INPUT,
@@ -148,10 +147,12 @@ def emit_default(out: CWriter, uop: Uop, stack: Stack) -> None:
148147

149148
class OptimizerEmitter(Emitter):
150149

151-
def __init__(self, out: CWriter, labels: dict[str, Label]):
150+
def __init__(self, out: CWriter, labels: dict[str, Label], original_uop: Uop, stack: Stack):
152151
super().__init__(out, labels)
153152
self._replacers["REPLACE_OPCODE_IF_EVALUATES_PURE"] = self.replace_opcode_if_evaluates_pure
154153
self.is_abstract = True
154+
self.original_uop = original_uop
155+
self.stack = stack
155156

156157
def emit_save(self, storage: Storage) -> None:
157158
storage.flush(self.out)
@@ -172,14 +173,55 @@ def replace_opcode_if_evaluates_pure(
172173
inst: Instruction | None,
173174
) -> bool:
174175
skip_to(tkn_iter, "SEMI")
176+
emitter = OptimizerConstantEmitter(self.out, {}, self.original_uop, copy.deepcopy(self.stack))
177+
emitter.emit("if (\n")
178+
input_identifiers = replace_opcode_if_evaluates_pure_identifiers(uop)
179+
assert len(input_identifiers) > 0, "Pure operations must have at least 1 input"
180+
for inp in input_identifiers[:-1]:
181+
emitter.emit(f"sym_is_safe_const(ctx, {inp}) &&\n")
182+
emitter.emit(f"sym_is_safe_const(ctx, {input_identifiers[-1]})\n")
183+
emitter.emit(') {\n')
184+
# Declare variables, before they are shadowed.
185+
for inp in self.original_uop.stack.inputs:
186+
if inp.used:
187+
emitter.emit(f"{type_name(inp)}{inp.name}_sym = {inp.name};\n")
188+
# Shadow the symbolic variables with stackrefs.
189+
for inp in self.original_uop.stack.inputs:
190+
if inp.used:
191+
emitter.emit(f"{stackref_type_name(inp)}{inp.name} = sym_get_const_as_stackref(ctx, {inp.name}_sym);\n")
192+
# Rename all output variables to stackref variant.
193+
for outp in self.original_uop.stack.outputs:
194+
assert not outp.is_array(), "Array output StackRefs not supported for pure ops."
195+
emitter.emit(f"_PyStackRef {outp.name}_stackref;\n")
196+
197+
198+
storage = Storage.for_uop(self.stack, self.original_uop, CWriter.null(), check_liveness=False)
199+
# No reference management of outputs needed.
200+
for var in storage.outputs:
201+
var.in_local = True
202+
emitter.emit("/* Start of uop copied from bytecodes for constant evaluation */\n")
203+
emitter.emit_tokens(self.original_uop, storage, inst=None, emit_braces=False)
204+
self.out.start_line()
205+
emitter.emit("/* End of uop copied from bytecodes for constant evaluation */\n")
206+
# Finally, assign back the output stackrefs to symbolics.
207+
for outp in self.original_uop.stack.outputs:
208+
# All new stackrefs are created from new references.
209+
# That's how the stackref contract works.
210+
if not outp.peek:
211+
emitter.emit(f"{outp.name} = sym_new_const_steal(ctx, PyStackRef_AsPyObjectSteal({outp.name}_stackref));\n")
212+
else:
213+
emitter.emit(f"{outp.name} = sym_new_const(ctx, PyStackRef_AsPyObjectBorrow({outp.name}_stackref));\n")
214+
storage.flush(self.out)
215+
emitter.emit("break;\n")
216+
emitter.emit("}\n")
175217
return True
176218

177219
class OptimizerConstantEmitter(OptimizerEmitter):
178-
def __init__(self, out: CWriter, labels: dict[str, Label], uop: Uop):
179-
super().__init__(out, labels)
220+
def __init__(self, out: CWriter, labels: dict[str, Label], original_uop: Uop, stack: Stack):
221+
super().__init__(out, labels, original_uop, stack)
180222
# Replace all outputs to point to their stackref versions.
181223
overrides = {
182-
outp.name: self.emit_stackref_override for outp in uop.stack.outputs
224+
outp.name: self.emit_stackref_override for outp in self.original_uop.stack.outputs
183225
}
184226
self._replacers = {**self._replacers, **overrides}
185227

@@ -214,59 +256,6 @@ def replace_opcode_if_evaluates_pure_identifiers(uop: Uop) -> list[str]:
214256
return idents
215257

216258

217-
def write_uop_pure_evaluation_region_header(
218-
uop: Uop,
219-
override: Uop,
220-
out: CWriter,
221-
stack: Stack,
222-
) -> None:
223-
emitter = OptimizerConstantEmitter(out, {}, uop)
224-
emitter.emit("if (\n")
225-
input_identifiers = replace_opcode_if_evaluates_pure_identifiers(override)
226-
assert len(input_identifiers) > 0, "Pure operations must have at least 1 input"
227-
for inp in input_identifiers[:-1]:
228-
emitter.emit(f"sym_is_safe_const(ctx, {inp}) &&\n")
229-
emitter.emit(f"sym_is_safe_const(ctx, {input_identifiers[-1]})\n")
230-
emitter.emit(') {\n')
231-
# Declare variables, before they are shadowed.
232-
for inp in uop.stack.inputs:
233-
if inp.used:
234-
emitter.emit(f"{type_name(inp)}{inp.name}_sym = {inp.name};\n")
235-
# Shadow the symbolic variables with stackrefs.
236-
for inp in uop.stack.inputs:
237-
if inp.used:
238-
emitter.emit(f"{stackref_type_name(inp)}{inp.name} = sym_get_const_as_stackref(ctx, {inp.name}_sym);\n")
239-
# Rename all output variables to stackref variant.
240-
for outp in uop.stack.outputs:
241-
assert not outp.is_array(), "Array output StackRefs not supported for pure ops."
242-
emitter.emit(f"_PyStackRef {outp.name}_stackref;\n")
243-
stack = copy.deepcopy(stack)
244-
245-
storage = Storage.for_uop(stack, uop, CWriter.null(), check_liveness=False)
246-
# No reference management of outputs needed.
247-
for var in storage.outputs:
248-
var.in_local = True
249-
emitter.emit("/* Start of uop copied from bytecodes for constant evaluation */\n")
250-
emitter.emit_tokens(uop, storage, inst=None, emit_braces=False)
251-
out.start_line()
252-
emitter.emit("/* End of uop copied from bytecodes for constant evaluation */\n")
253-
# Finally, assign back the output stackrefs to symbolics.
254-
for outp in uop.stack.outputs:
255-
# All new stackrefs are created from new references.
256-
# That's how the stackref contract works.
257-
if not outp.peek:
258-
emitter.emit(f"{outp.name} = sym_new_const_steal(ctx, PyStackRef_AsPyObjectSteal({outp.name}_stackref));\n")
259-
else:
260-
emitter.emit(f"{outp.name} = sym_new_const(ctx, PyStackRef_AsPyObjectBorrow({outp.name}_stackref));\n")
261-
storage.flush(out)
262-
emitter.emit("}\n")
263-
emitter.emit("else {\n")
264-
265-
def write_uop_pure_evaluation_region_footer(
266-
out: CWriter,
267-
) -> None:
268-
out.emit("}\n")
269-
270259
def write_uop(
271260
override: Uop | None,
272261
uop: Uop,
@@ -299,16 +288,11 @@ def write_uop(
299288
# No reference management of inputs needed.
300289
for var in storage.inputs: # type: ignore[possibly-undefined]
301290
var.in_local = False
302-
replace_opcode_if_evaluates_pure = uop_variable_used(override, "REPLACE_OPCODE_IF_EVALUATES_PURE")
303-
if replace_opcode_if_evaluates_pure:
304-
write_uop_pure_evaluation_region_header(uop, override, out, stack)
305291
out.start_line()
306-
emitter = OptimizerEmitter(out, {})
292+
emitter = OptimizerEmitter(out, {}, uop, copy.deepcopy(stack))
307293
_, storage = emitter.emit_tokens(override, storage, inst=None, emit_braces=False)
308294
storage.flush(out)
309295
out.start_line()
310-
if replace_opcode_if_evaluates_pure:
311-
write_uop_pure_evaluation_region_footer(out)
312296
else:
313297
emit_default(out, uop, stack)
314298
out.start_line()

0 commit comments

Comments
 (0)