mirror of
https://github.com/python/cpython.git
synced 2025-10-15 11:22:18 +00:00
GH-120024: Refactor code generators to uses classes for emitting code. (GH-122730)
This commit is contained in:
parent
ce0d66c8d2
commit
fbfab4f88c
4 changed files with 281 additions and 283 deletions
|
@ -57,169 +57,171 @@ def emit_to(out: CWriter, tkn_iter: Iterator[Token], end: str) -> None:
|
||||||
parens -= 1
|
parens -= 1
|
||||||
out.emit(tkn)
|
out.emit(tkn)
|
||||||
|
|
||||||
|
|
||||||
def replace_deopt(
|
|
||||||
out: CWriter,
|
|
||||||
tkn: Token,
|
|
||||||
tkn_iter: Iterator[Token],
|
|
||||||
uop: Uop,
|
|
||||||
unused: Stack,
|
|
||||||
inst: Instruction | None,
|
|
||||||
) -> None:
|
|
||||||
out.emit_at("DEOPT_IF", tkn)
|
|
||||||
out.emit(next(tkn_iter))
|
|
||||||
emit_to(out, tkn_iter, "RPAREN")
|
|
||||||
next(tkn_iter) # Semi colon
|
|
||||||
out.emit(", ")
|
|
||||||
assert inst is not None
|
|
||||||
assert inst.family is not None
|
|
||||||
out.emit(inst.family.name)
|
|
||||||
out.emit(");\n")
|
|
||||||
|
|
||||||
|
|
||||||
def replace_error(
|
|
||||||
out: CWriter,
|
|
||||||
tkn: Token,
|
|
||||||
tkn_iter: Iterator[Token],
|
|
||||||
uop: Uop,
|
|
||||||
stack: Stack,
|
|
||||||
inst: Instruction | None,
|
|
||||||
) -> None:
|
|
||||||
out.emit_at("if ", tkn)
|
|
||||||
out.emit(next(tkn_iter))
|
|
||||||
emit_to(out, tkn_iter, "COMMA")
|
|
||||||
label = next(tkn_iter).text
|
|
||||||
next(tkn_iter) # RPAREN
|
|
||||||
next(tkn_iter) # Semi colon
|
|
||||||
out.emit(") ")
|
|
||||||
c_offset = stack.peek_offset()
|
|
||||||
try:
|
|
||||||
offset = -int(c_offset)
|
|
||||||
except ValueError:
|
|
||||||
offset = -1
|
|
||||||
if offset > 0:
|
|
||||||
out.emit(f"goto pop_{offset}_")
|
|
||||||
out.emit(label)
|
|
||||||
out.emit(";\n")
|
|
||||||
elif offset == 0:
|
|
||||||
out.emit("goto ")
|
|
||||||
out.emit(label)
|
|
||||||
out.emit(";\n")
|
|
||||||
else:
|
|
||||||
out.emit("{\n")
|
|
||||||
stack.flush_locally(out)
|
|
||||||
out.emit("goto ")
|
|
||||||
out.emit(label)
|
|
||||||
out.emit(";\n")
|
|
||||||
out.emit("}\n")
|
|
||||||
|
|
||||||
|
|
||||||
def replace_error_no_pop(
|
|
||||||
out: CWriter,
|
|
||||||
tkn: Token,
|
|
||||||
tkn_iter: Iterator[Token],
|
|
||||||
uop: Uop,
|
|
||||||
stack: Stack,
|
|
||||||
inst: Instruction | None,
|
|
||||||
) -> None:
|
|
||||||
next(tkn_iter) # LPAREN
|
|
||||||
next(tkn_iter) # RPAREN
|
|
||||||
next(tkn_iter) # Semi colon
|
|
||||||
out.emit_at("goto error;", tkn)
|
|
||||||
|
|
||||||
|
|
||||||
def replace_decrefs(
|
|
||||||
out: CWriter,
|
|
||||||
tkn: Token,
|
|
||||||
tkn_iter: Iterator[Token],
|
|
||||||
uop: Uop,
|
|
||||||
stack: Stack,
|
|
||||||
inst: Instruction | None,
|
|
||||||
) -> None:
|
|
||||||
next(tkn_iter)
|
|
||||||
next(tkn_iter)
|
|
||||||
next(tkn_iter)
|
|
||||||
out.emit_at("", tkn)
|
|
||||||
for var in uop.stack.inputs:
|
|
||||||
if var.name == "unused" or var.name == "null" or var.peek:
|
|
||||||
continue
|
|
||||||
if var.size:
|
|
||||||
out.emit(f"for (int _i = {var.size}; --_i >= 0;) {{\n")
|
|
||||||
out.emit(f"PyStackRef_CLOSE({var.name}[_i]);\n")
|
|
||||||
out.emit("}\n")
|
|
||||||
elif var.condition:
|
|
||||||
if var.condition == "1":
|
|
||||||
out.emit(f"PyStackRef_CLOSE({var.name});\n")
|
|
||||||
elif var.condition != "0":
|
|
||||||
out.emit(f"PyStackRef_XCLOSE({var.name});\n")
|
|
||||||
else:
|
|
||||||
out.emit(f"PyStackRef_CLOSE({var.name});\n")
|
|
||||||
|
|
||||||
|
|
||||||
def replace_sync_sp(
|
|
||||||
out: CWriter,
|
|
||||||
tkn: Token,
|
|
||||||
tkn_iter: Iterator[Token],
|
|
||||||
uop: Uop,
|
|
||||||
stack: Stack,
|
|
||||||
inst: Instruction | None,
|
|
||||||
) -> None:
|
|
||||||
next(tkn_iter)
|
|
||||||
next(tkn_iter)
|
|
||||||
next(tkn_iter)
|
|
||||||
stack.flush(out)
|
|
||||||
|
|
||||||
|
|
||||||
def replace_check_eval_breaker(
|
|
||||||
out: CWriter,
|
|
||||||
tkn: Token,
|
|
||||||
tkn_iter: Iterator[Token],
|
|
||||||
uop: Uop,
|
|
||||||
stack: Stack,
|
|
||||||
inst: Instruction | None,
|
|
||||||
) -> None:
|
|
||||||
next(tkn_iter)
|
|
||||||
next(tkn_iter)
|
|
||||||
next(tkn_iter)
|
|
||||||
if not uop.properties.ends_with_eval_breaker:
|
|
||||||
out.emit_at("CHECK_EVAL_BREAKER();", tkn)
|
|
||||||
|
|
||||||
|
|
||||||
REPLACEMENT_FUNCTIONS = {
|
|
||||||
"EXIT_IF": replace_deopt,
|
|
||||||
"DEOPT_IF": replace_deopt,
|
|
||||||
"ERROR_IF": replace_error,
|
|
||||||
"ERROR_NO_POP": replace_error_no_pop,
|
|
||||||
"DECREF_INPUTS": replace_decrefs,
|
|
||||||
"CHECK_EVAL_BREAKER": replace_check_eval_breaker,
|
|
||||||
"SYNC_SP": replace_sync_sp,
|
|
||||||
}
|
|
||||||
|
|
||||||
ReplacementFunctionType = Callable[
|
ReplacementFunctionType = Callable[
|
||||||
[CWriter, Token, Iterator[Token], Uop, Stack, Instruction | None], None
|
[Token, Iterator[Token], Uop, Stack, Instruction | None], None
|
||||||
]
|
]
|
||||||
|
|
||||||
|
class Emitter:
|
||||||
|
|
||||||
def emit_tokens(
|
out: CWriter
|
||||||
out: CWriter,
|
_replacers: dict[str, ReplacementFunctionType]
|
||||||
uop: Uop,
|
|
||||||
stack: Stack,
|
def __init__(self, out: CWriter):
|
||||||
inst: Instruction | None,
|
self._replacers = {
|
||||||
replacement_functions: Mapping[
|
"EXIT_IF": self.exit_if,
|
||||||
str, ReplacementFunctionType
|
"DEOPT_IF": self.deopt_if,
|
||||||
] = REPLACEMENT_FUNCTIONS,
|
"ERROR_IF": self.error_if,
|
||||||
) -> None:
|
"ERROR_NO_POP": self.error_no_pop,
|
||||||
tkns = uop.body[1:-1]
|
"DECREF_INPUTS": self.decref_inputs,
|
||||||
if not tkns:
|
"CHECK_EVAL_BREAKER": self.check_eval_breaker,
|
||||||
return
|
"SYNC_SP": self.sync_sp,
|
||||||
tkn_iter = iter(tkns)
|
}
|
||||||
out.start_line()
|
self.out = out
|
||||||
for tkn in tkn_iter:
|
|
||||||
if tkn.kind == "IDENTIFIER" and tkn.text in replacement_functions:
|
def deopt_if(
|
||||||
replacement_functions[tkn.text](out, tkn, tkn_iter, uop, stack, inst)
|
self,
|
||||||
|
tkn: Token,
|
||||||
|
tkn_iter: Iterator[Token],
|
||||||
|
uop: Uop,
|
||||||
|
unused: Stack,
|
||||||
|
inst: Instruction | None,
|
||||||
|
) -> None:
|
||||||
|
self.out.emit_at("DEOPT_IF", tkn)
|
||||||
|
self.out.emit(next(tkn_iter))
|
||||||
|
emit_to(self.out, tkn_iter, "RPAREN")
|
||||||
|
next(tkn_iter) # Semi colon
|
||||||
|
self.out.emit(", ")
|
||||||
|
assert inst is not None
|
||||||
|
assert inst.family is not None
|
||||||
|
self.out.emit(inst.family.name)
|
||||||
|
self.out.emit(");\n")
|
||||||
|
|
||||||
|
exit_if = deopt_if
|
||||||
|
|
||||||
|
def error_if(
|
||||||
|
self,
|
||||||
|
tkn: Token,
|
||||||
|
tkn_iter: Iterator[Token],
|
||||||
|
uop: Uop,
|
||||||
|
stack: Stack,
|
||||||
|
inst: Instruction | None,
|
||||||
|
) -> None:
|
||||||
|
self.out.emit_at("if ", tkn)
|
||||||
|
self.out.emit(next(tkn_iter))
|
||||||
|
emit_to(self.out, tkn_iter, "COMMA")
|
||||||
|
label = next(tkn_iter).text
|
||||||
|
next(tkn_iter) # RPAREN
|
||||||
|
next(tkn_iter) # Semi colon
|
||||||
|
self.out.emit(") ")
|
||||||
|
c_offset = stack.peek_offset()
|
||||||
|
try:
|
||||||
|
offset = -int(c_offset)
|
||||||
|
except ValueError:
|
||||||
|
offset = -1
|
||||||
|
if offset > 0:
|
||||||
|
self.out.emit(f"goto pop_{offset}_")
|
||||||
|
self.out.emit(label)
|
||||||
|
self.out.emit(";\n")
|
||||||
|
elif offset == 0:
|
||||||
|
self.out.emit("goto ")
|
||||||
|
self.out.emit(label)
|
||||||
|
self.out.emit(";\n")
|
||||||
else:
|
else:
|
||||||
out.emit(tkn)
|
self.out.emit("{\n")
|
||||||
|
stack.flush_locally(self.out)
|
||||||
|
self.out.emit("goto ")
|
||||||
|
self.out.emit(label)
|
||||||
|
self.out.emit(";\n")
|
||||||
|
self.out.emit("}\n")
|
||||||
|
|
||||||
|
def error_no_pop(
|
||||||
|
self,
|
||||||
|
tkn: Token,
|
||||||
|
tkn_iter: Iterator[Token],
|
||||||
|
uop: Uop,
|
||||||
|
stack: Stack,
|
||||||
|
inst: Instruction | None,
|
||||||
|
) -> None:
|
||||||
|
next(tkn_iter) # LPAREN
|
||||||
|
next(tkn_iter) # RPAREN
|
||||||
|
next(tkn_iter) # Semi colon
|
||||||
|
self.out.emit_at("goto error;", tkn)
|
||||||
|
|
||||||
|
def decref_inputs(
|
||||||
|
self,
|
||||||
|
tkn: Token,
|
||||||
|
tkn_iter: Iterator[Token],
|
||||||
|
uop: Uop,
|
||||||
|
stack: Stack,
|
||||||
|
inst: Instruction | None,
|
||||||
|
) -> None:
|
||||||
|
next(tkn_iter)
|
||||||
|
next(tkn_iter)
|
||||||
|
next(tkn_iter)
|
||||||
|
self.out.emit_at("", tkn)
|
||||||
|
for var in uop.stack.inputs:
|
||||||
|
if var.name == "unused" or var.name == "null" or var.peek:
|
||||||
|
continue
|
||||||
|
if var.size:
|
||||||
|
self.out.emit(f"for (int _i = {var.size}; --_i >= 0;) {{\n")
|
||||||
|
self.out.emit(f"PyStackRef_CLOSE({var.name}[_i]);\n")
|
||||||
|
self.out.emit("}\n")
|
||||||
|
elif var.condition:
|
||||||
|
if var.condition == "1":
|
||||||
|
self.out.emit(f"PyStackRef_CLOSE({var.name});\n")
|
||||||
|
elif var.condition != "0":
|
||||||
|
self.out.emit(f"PyStackRef_XCLOSE({var.name});\n")
|
||||||
|
else:
|
||||||
|
self.out.emit(f"PyStackRef_CLOSE({var.name});\n")
|
||||||
|
|
||||||
|
|
||||||
|
def sync_sp(
|
||||||
|
self,
|
||||||
|
tkn: Token,
|
||||||
|
tkn_iter: Iterator[Token],
|
||||||
|
uop: Uop,
|
||||||
|
stack: Stack,
|
||||||
|
inst: Instruction | None,
|
||||||
|
) -> None:
|
||||||
|
next(tkn_iter)
|
||||||
|
next(tkn_iter)
|
||||||
|
next(tkn_iter)
|
||||||
|
stack.flush(self.out)
|
||||||
|
|
||||||
|
|
||||||
|
def check_eval_breaker(
|
||||||
|
self,
|
||||||
|
tkn: Token,
|
||||||
|
tkn_iter: Iterator[Token],
|
||||||
|
uop: Uop,
|
||||||
|
stack: Stack,
|
||||||
|
inst: Instruction | None,
|
||||||
|
) -> None:
|
||||||
|
next(tkn_iter)
|
||||||
|
next(tkn_iter)
|
||||||
|
next(tkn_iter)
|
||||||
|
if not uop.properties.ends_with_eval_breaker:
|
||||||
|
self.out.emit_at("CHECK_EVAL_BREAKER();", tkn)
|
||||||
|
|
||||||
|
def emit_tokens(
|
||||||
|
self,
|
||||||
|
uop: Uop,
|
||||||
|
stack: Stack,
|
||||||
|
inst: Instruction | None,
|
||||||
|
) -> None:
|
||||||
|
tkns = uop.body[1:-1]
|
||||||
|
if not tkns:
|
||||||
|
return
|
||||||
|
tkn_iter = iter(tkns)
|
||||||
|
self.out.start_line()
|
||||||
|
for tkn in tkn_iter:
|
||||||
|
if tkn.kind == "IDENTIFIER" and tkn.text in self._replacers:
|
||||||
|
self._replacers[tkn.text](tkn, tkn_iter, uop, stack, inst)
|
||||||
|
else:
|
||||||
|
self.out.emit(tkn)
|
||||||
|
|
||||||
|
def emit(self, txt: str | Token) -> None:
|
||||||
|
self.out.emit(txt)
|
||||||
|
|
||||||
def cflags(p: Properties) -> str:
|
def cflags(p: Properties) -> str:
|
||||||
flags: list[str] = []
|
flags: list[str] = []
|
||||||
|
|
|
@ -17,8 +17,7 @@ from generators_common import (
|
||||||
DEFAULT_INPUT,
|
DEFAULT_INPUT,
|
||||||
ROOT,
|
ROOT,
|
||||||
write_header,
|
write_header,
|
||||||
emit_tokens,
|
Emitter,
|
||||||
replace_sync_sp,
|
|
||||||
)
|
)
|
||||||
from cwriter import CWriter
|
from cwriter import CWriter
|
||||||
from typing import TextIO, Iterator
|
from typing import TextIO, Iterator
|
||||||
|
@ -89,6 +88,10 @@ def emit_default(out: CWriter, uop: Uop) -> None:
|
||||||
else:
|
else:
|
||||||
out.emit(f"{var.name} = sym_new_not_null(ctx);\n")
|
out.emit(f"{var.name} = sym_new_not_null(ctx);\n")
|
||||||
|
|
||||||
|
class OptimizerEmitter(Emitter):
|
||||||
|
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
def write_uop(
|
def write_uop(
|
||||||
override: Uop | None,
|
override: Uop | None,
|
||||||
|
@ -126,11 +129,8 @@ def write_uop(
|
||||||
cast = f"uint{cache.size*16}_t"
|
cast = f"uint{cache.size*16}_t"
|
||||||
out.emit(f"{type}{cache.name} = ({cast})this_instr->operand;\n")
|
out.emit(f"{type}{cache.name} = ({cast})this_instr->operand;\n")
|
||||||
if override:
|
if override:
|
||||||
replacement_funcs = {
|
emitter = OptimizerEmitter(out)
|
||||||
"DECREF_INPUTS": decref_inputs,
|
emitter.emit_tokens(override, stack, None)
|
||||||
"SYNC_SP": replace_sync_sp,
|
|
||||||
}
|
|
||||||
emit_tokens(out, override, stack, None, replacement_funcs)
|
|
||||||
else:
|
else:
|
||||||
emit_default(out, uop)
|
emit_default(out, uop)
|
||||||
|
|
||||||
|
|
|
@ -20,8 +20,8 @@ from generators_common import (
|
||||||
DEFAULT_INPUT,
|
DEFAULT_INPUT,
|
||||||
ROOT,
|
ROOT,
|
||||||
write_header,
|
write_header,
|
||||||
emit_tokens,
|
|
||||||
type_and_null,
|
type_and_null,
|
||||||
|
Emitter,
|
||||||
)
|
)
|
||||||
from cwriter import CWriter
|
from cwriter import CWriter
|
||||||
from typing import TextIO
|
from typing import TextIO
|
||||||
|
@ -62,26 +62,26 @@ def declare_variables(inst: Instruction, out: CWriter) -> None:
|
||||||
declare_variable(var, out)
|
declare_variable(var, out)
|
||||||
|
|
||||||
def write_uop(
|
def write_uop(
|
||||||
uop: Part, out: CWriter, offset: int, stack: Stack, inst: Instruction, braces: bool
|
uop: Part, emitter: Emitter, offset: int, stack: Stack, inst: Instruction, braces: bool
|
||||||
) -> int:
|
) -> int:
|
||||||
# out.emit(stack.as_comment() + "\n")
|
# out.emit(stack.as_comment() + "\n")
|
||||||
if isinstance(uop, Skip):
|
if isinstance(uop, Skip):
|
||||||
entries = "entries" if uop.size > 1 else "entry"
|
entries = "entries" if uop.size > 1 else "entry"
|
||||||
out.emit(f"/* Skip {uop.size} cache {entries} */\n")
|
emitter.emit(f"/* Skip {uop.size} cache {entries} */\n")
|
||||||
return offset + uop.size
|
return offset + uop.size
|
||||||
if isinstance(uop, Flush):
|
if isinstance(uop, Flush):
|
||||||
out.emit(f"// flush\n")
|
emitter.emit(f"// flush\n")
|
||||||
stack.flush(out)
|
stack.flush(emitter.out)
|
||||||
return offset
|
return offset
|
||||||
try:
|
try:
|
||||||
locals: dict[str, Local] = {}
|
locals: dict[str, Local] = {}
|
||||||
out.start_line()
|
emitter.out.start_line()
|
||||||
if braces:
|
if braces:
|
||||||
out.emit(f"// {uop.name}\n")
|
emitter.out.emit(f"// {uop.name}\n")
|
||||||
peeks: list[Local] = []
|
peeks: list[Local] = []
|
||||||
for var in reversed(uop.stack.inputs):
|
for var in reversed(uop.stack.inputs):
|
||||||
code, local = stack.pop(var)
|
code, local = stack.pop(var)
|
||||||
out.emit(code)
|
emitter.emit(code)
|
||||||
if var.peek:
|
if var.peek:
|
||||||
peeks.append(local)
|
peeks.append(local)
|
||||||
if local.defined:
|
if local.defined:
|
||||||
|
@ -91,8 +91,8 @@ def write_uop(
|
||||||
while peeks:
|
while peeks:
|
||||||
stack.push(peeks.pop())
|
stack.push(peeks.pop())
|
||||||
if braces:
|
if braces:
|
||||||
out.emit("{\n")
|
emitter.emit("{\n")
|
||||||
out.emit(stack.define_output_arrays(uop.stack.outputs))
|
emitter.out.emit(stack.define_output_arrays(uop.stack.outputs))
|
||||||
|
|
||||||
for cache in uop.caches:
|
for cache in uop.caches:
|
||||||
if cache.name != "unused":
|
if cache.name != "unused":
|
||||||
|
@ -102,13 +102,13 @@ def write_uop(
|
||||||
else:
|
else:
|
||||||
type = f"uint{cache.size*16}_t "
|
type = f"uint{cache.size*16}_t "
|
||||||
reader = f"read_u{cache.size*16}"
|
reader = f"read_u{cache.size*16}"
|
||||||
out.emit(
|
emitter.emit(
|
||||||
f"{type}{cache.name} = {reader}(&this_instr[{offset}].cache);\n"
|
f"{type}{cache.name} = {reader}(&this_instr[{offset}].cache);\n"
|
||||||
)
|
)
|
||||||
if inst.family is None:
|
if inst.family is None:
|
||||||
out.emit(f"(void){cache.name};\n")
|
emitter.emit(f"(void){cache.name};\n")
|
||||||
offset += cache.size
|
offset += cache.size
|
||||||
emit_tokens(out, uop, stack, inst)
|
emitter.emit_tokens(uop, stack, inst)
|
||||||
for i, var in enumerate(uop.stack.outputs):
|
for i, var in enumerate(uop.stack.outputs):
|
||||||
if not var.peek:
|
if not var.peek:
|
||||||
if var.name in locals:
|
if var.name in locals:
|
||||||
|
@ -117,11 +117,11 @@ def write_uop(
|
||||||
local = Local.unused(var)
|
local = Local.unused(var)
|
||||||
else:
|
else:
|
||||||
local = Local.local(var)
|
local = Local.local(var)
|
||||||
out.emit(stack.push(local))
|
emitter.emit(stack.push(local))
|
||||||
if braces:
|
if braces:
|
||||||
out.start_line()
|
emitter.out.start_line()
|
||||||
out.emit("}\n")
|
emitter.emit("}\n")
|
||||||
# out.emit(stack.as_comment() + "\n")
|
# emitter.emit(stack.as_comment() + "\n")
|
||||||
return offset
|
return offset
|
||||||
except StackError as ex:
|
except StackError as ex:
|
||||||
raise analysis_error(ex.args[0], uop.body[0])
|
raise analysis_error(ex.args[0], uop.body[0])
|
||||||
|
@ -152,6 +152,7 @@ def generate_tier1(
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
out = CWriter(outfile, 2, lines)
|
out = CWriter(outfile, 2, lines)
|
||||||
|
emitter = Emitter(out)
|
||||||
out.emit("\n")
|
out.emit("\n")
|
||||||
for name, inst in sorted(analysis.instructions.items()):
|
for name, inst in sorted(analysis.instructions.items()):
|
||||||
needs_this = uses_this(inst)
|
needs_this = uses_this(inst)
|
||||||
|
@ -183,7 +184,7 @@ def generate_tier1(
|
||||||
for part in inst.parts:
|
for part in inst.parts:
|
||||||
# Only emit braces if more than one uop
|
# Only emit braces if more than one uop
|
||||||
insert_braces = len([p for p in inst.parts if isinstance(p, Uop)]) > 1
|
insert_braces = len([p for p in inst.parts if isinstance(p, Uop)]) > 1
|
||||||
offset = write_uop(part, out, offset, stack, inst, insert_braces)
|
offset = write_uop(part, emitter, offset, stack, inst, insert_braces)
|
||||||
out.start_line()
|
out.start_line()
|
||||||
if not inst.parts[-1].properties.always_exits:
|
if not inst.parts[-1].properties.always_exits:
|
||||||
stack.flush(out)
|
stack.flush(out)
|
||||||
|
|
|
@ -16,11 +16,10 @@ from analyzer import (
|
||||||
from generators_common import (
|
from generators_common import (
|
||||||
DEFAULT_INPUT,
|
DEFAULT_INPUT,
|
||||||
ROOT,
|
ROOT,
|
||||||
write_header,
|
|
||||||
emit_tokens,
|
|
||||||
emit_to,
|
emit_to,
|
||||||
REPLACEMENT_FUNCTIONS,
|
write_header,
|
||||||
type_and_null,
|
type_and_null,
|
||||||
|
Emitter
|
||||||
)
|
)
|
||||||
from cwriter import CWriter
|
from cwriter import CWriter
|
||||||
from typing import TextIO, Iterator
|
from typing import TextIO, Iterator
|
||||||
|
@ -61,117 +60,112 @@ def declare_variables(uop: Uop, out: CWriter) -> None:
|
||||||
for var in uop.stack.outputs:
|
for var in uop.stack.outputs:
|
||||||
declare_variable(var, uop, required, out)
|
declare_variable(var, uop, required, out)
|
||||||
|
|
||||||
def tier2_replace_error(
|
|
||||||
out: CWriter,
|
|
||||||
tkn: Token,
|
|
||||||
tkn_iter: Iterator[Token],
|
|
||||||
uop: Uop,
|
|
||||||
stack: Stack,
|
|
||||||
inst: Instruction | None,
|
|
||||||
) -> None:
|
|
||||||
out.emit_at("if ", tkn)
|
|
||||||
out.emit(next(tkn_iter))
|
|
||||||
emit_to(out, tkn_iter, "COMMA")
|
|
||||||
label = next(tkn_iter).text
|
|
||||||
next(tkn_iter) # RPAREN
|
|
||||||
next(tkn_iter) # Semi colon
|
|
||||||
out.emit(") JUMP_TO_ERROR();\n")
|
|
||||||
|
|
||||||
|
class Tier2Emitter(Emitter):
|
||||||
|
|
||||||
def tier2_replace_error_no_pop(
|
def __init__(self, out: CWriter):
|
||||||
out: CWriter,
|
super().__init__(out)
|
||||||
tkn: Token,
|
self._replacers["oparg"] = self.oparg
|
||||||
tkn_iter: Iterator[Token],
|
|
||||||
uop: Uop,
|
|
||||||
stack: Stack,
|
|
||||||
inst: Instruction | None,
|
|
||||||
) -> None:
|
|
||||||
next(tkn_iter) # LPAREN
|
|
||||||
next(tkn_iter) # RPAREN
|
|
||||||
next(tkn_iter) # Semi colon
|
|
||||||
out.emit_at("JUMP_TO_ERROR();", tkn)
|
|
||||||
|
|
||||||
def tier2_replace_deopt(
|
def error_if(
|
||||||
out: CWriter,
|
self,
|
||||||
tkn: Token,
|
tkn: Token,
|
||||||
tkn_iter: Iterator[Token],
|
tkn_iter: Iterator[Token],
|
||||||
uop: Uop,
|
uop: Uop,
|
||||||
unused: Stack,
|
stack: Stack,
|
||||||
inst: Instruction | None,
|
inst: Instruction | None,
|
||||||
) -> None:
|
) -> None:
|
||||||
out.emit_at("if ", tkn)
|
self.out.emit_at("if ", tkn)
|
||||||
out.emit(next(tkn_iter))
|
self.emit(next(tkn_iter))
|
||||||
emit_to(out, tkn_iter, "RPAREN")
|
emit_to(self.out, tkn_iter, "COMMA")
|
||||||
next(tkn_iter) # Semi colon
|
label = next(tkn_iter).text
|
||||||
out.emit(") {\n")
|
next(tkn_iter) # RPAREN
|
||||||
out.emit("UOP_STAT_INC(uopcode, miss);\n")
|
next(tkn_iter) # Semi colon
|
||||||
out.emit("JUMP_TO_JUMP_TARGET();\n");
|
self.emit(") JUMP_TO_ERROR();\n")
|
||||||
out.emit("}\n")
|
|
||||||
|
|
||||||
|
def error_no_pop(
|
||||||
|
self,
|
||||||
|
tkn: Token,
|
||||||
|
tkn_iter: Iterator[Token],
|
||||||
|
uop: Uop,
|
||||||
|
stack: Stack,
|
||||||
|
inst: Instruction | None,
|
||||||
|
) -> None:
|
||||||
|
next(tkn_iter) # LPAREN
|
||||||
|
next(tkn_iter) # RPAREN
|
||||||
|
next(tkn_iter) # Semi colon
|
||||||
|
self.out.emit_at("JUMP_TO_ERROR();", tkn)
|
||||||
|
|
||||||
def tier2_replace_exit_if(
|
def deopt_if(
|
||||||
out: CWriter,
|
self,
|
||||||
tkn: Token,
|
tkn: Token,
|
||||||
tkn_iter: Iterator[Token],
|
tkn_iter: Iterator[Token],
|
||||||
uop: Uop,
|
uop: Uop,
|
||||||
unused: Stack,
|
unused: Stack,
|
||||||
inst: Instruction | None,
|
inst: Instruction | None,
|
||||||
) -> None:
|
) -> None:
|
||||||
out.emit_at("if ", tkn)
|
self.out.emit_at("if ", tkn)
|
||||||
out.emit(next(tkn_iter))
|
self.emit(next(tkn_iter))
|
||||||
emit_to(out, tkn_iter, "RPAREN")
|
emit_to(self.out, tkn_iter, "RPAREN")
|
||||||
next(tkn_iter) # Semi colon
|
next(tkn_iter) # Semi colon
|
||||||
out.emit(") {\n")
|
self.emit(") {\n")
|
||||||
out.emit("UOP_STAT_INC(uopcode, miss);\n")
|
self.emit("UOP_STAT_INC(uopcode, miss);\n")
|
||||||
out.emit("JUMP_TO_JUMP_TARGET();\n")
|
self.emit("JUMP_TO_JUMP_TARGET();\n");
|
||||||
out.emit("}\n")
|
self.emit("}\n")
|
||||||
|
|
||||||
|
def exit_if( # type: ignore[override]
|
||||||
|
self,
|
||||||
|
tkn: Token,
|
||||||
|
tkn_iter: Iterator[Token],
|
||||||
|
uop: Uop,
|
||||||
|
unused: Stack,
|
||||||
|
inst: Instruction | None,
|
||||||
|
) -> None:
|
||||||
|
self.out.emit_at("if ", tkn)
|
||||||
|
self.emit(next(tkn_iter))
|
||||||
|
emit_to(self.out, tkn_iter, "RPAREN")
|
||||||
|
next(tkn_iter) # Semi colon
|
||||||
|
self.emit(") {\n")
|
||||||
|
self.emit("UOP_STAT_INC(uopcode, miss);\n")
|
||||||
|
self.emit("JUMP_TO_JUMP_TARGET();\n")
|
||||||
|
self.emit("}\n")
|
||||||
|
|
||||||
def tier2_replace_oparg(
|
def oparg(
|
||||||
out: CWriter,
|
self,
|
||||||
tkn: Token,
|
tkn: Token,
|
||||||
tkn_iter: Iterator[Token],
|
tkn_iter: Iterator[Token],
|
||||||
uop: Uop,
|
uop: Uop,
|
||||||
unused: Stack,
|
unused: Stack,
|
||||||
inst: Instruction | None,
|
inst: Instruction | None,
|
||||||
) -> None:
|
) -> None:
|
||||||
if not uop.name.endswith("_0") and not uop.name.endswith("_1"):
|
if not uop.name.endswith("_0") and not uop.name.endswith("_1"):
|
||||||
out.emit(tkn)
|
self.emit(tkn)
|
||||||
return
|
return
|
||||||
amp = next(tkn_iter)
|
amp = next(tkn_iter)
|
||||||
if amp.text != "&":
|
if amp.text != "&":
|
||||||
out.emit(tkn)
|
self.emit(tkn)
|
||||||
out.emit(amp)
|
self.emit(amp)
|
||||||
return
|
return
|
||||||
one = next(tkn_iter)
|
one = next(tkn_iter)
|
||||||
assert one.text == "1"
|
assert one.text == "1"
|
||||||
out.emit_at(uop.name[-1], tkn)
|
self.out.emit_at(uop.name[-1], tkn)
|
||||||
|
|
||||||
|
def write_uop(uop: Uop, emitter: Emitter, stack: Stack) -> None:
|
||||||
TIER2_REPLACEMENT_FUNCTIONS = REPLACEMENT_FUNCTIONS.copy()
|
|
||||||
TIER2_REPLACEMENT_FUNCTIONS["ERROR_IF"] = tier2_replace_error
|
|
||||||
TIER2_REPLACEMENT_FUNCTIONS["ERROR_NO_POP"] = tier2_replace_error_no_pop
|
|
||||||
TIER2_REPLACEMENT_FUNCTIONS["DEOPT_IF"] = tier2_replace_deopt
|
|
||||||
TIER2_REPLACEMENT_FUNCTIONS["oparg"] = tier2_replace_oparg
|
|
||||||
TIER2_REPLACEMENT_FUNCTIONS["EXIT_IF"] = tier2_replace_exit_if
|
|
||||||
|
|
||||||
|
|
||||||
def write_uop(uop: Uop, out: CWriter, stack: Stack) -> None:
|
|
||||||
locals: dict[str, Local] = {}
|
locals: dict[str, Local] = {}
|
||||||
try:
|
try:
|
||||||
out.start_line()
|
emitter.out.start_line()
|
||||||
if uop.properties.oparg:
|
if uop.properties.oparg:
|
||||||
out.emit("oparg = CURRENT_OPARG();\n")
|
emitter.emit("oparg = CURRENT_OPARG();\n")
|
||||||
assert uop.properties.const_oparg < 0
|
assert uop.properties.const_oparg < 0
|
||||||
elif uop.properties.const_oparg >= 0:
|
elif uop.properties.const_oparg >= 0:
|
||||||
out.emit(f"oparg = {uop.properties.const_oparg};\n")
|
emitter.emit(f"oparg = {uop.properties.const_oparg};\n")
|
||||||
out.emit(f"assert(oparg == CURRENT_OPARG());\n")
|
emitter.emit(f"assert(oparg == CURRENT_OPARG());\n")
|
||||||
for var in reversed(uop.stack.inputs):
|
for var in reversed(uop.stack.inputs):
|
||||||
code, local = stack.pop(var)
|
code, local = stack.pop(var)
|
||||||
out.emit(code)
|
emitter.emit(code)
|
||||||
if local.defined:
|
if local.defined:
|
||||||
locals[local.name] = local
|
locals[local.name] = local
|
||||||
out.emit(stack.define_output_arrays(uop.stack.outputs))
|
emitter.emit(stack.define_output_arrays(uop.stack.outputs))
|
||||||
for cache in uop.caches:
|
for cache in uop.caches:
|
||||||
if cache.name != "unused":
|
if cache.name != "unused":
|
||||||
if cache.size == 4:
|
if cache.size == 4:
|
||||||
|
@ -179,14 +173,14 @@ def write_uop(uop: Uop, out: CWriter, stack: Stack) -> None:
|
||||||
else:
|
else:
|
||||||
type = f"uint{cache.size*16}_t "
|
type = f"uint{cache.size*16}_t "
|
||||||
cast = f"uint{cache.size*16}_t"
|
cast = f"uint{cache.size*16}_t"
|
||||||
out.emit(f"{type}{cache.name} = ({cast})CURRENT_OPERAND();\n")
|
emitter.emit(f"{type}{cache.name} = ({cast})CURRENT_OPERAND();\n")
|
||||||
emit_tokens(out, uop, stack, None, TIER2_REPLACEMENT_FUNCTIONS)
|
emitter.emit_tokens(uop, stack, None)
|
||||||
for i, var in enumerate(uop.stack.outputs):
|
for i, var in enumerate(uop.stack.outputs):
|
||||||
if var.name in locals:
|
if var.name in locals:
|
||||||
local = locals[var.name]
|
local = locals[var.name]
|
||||||
else:
|
else:
|
||||||
local = Local.local(var)
|
local = Local.local(var)
|
||||||
out.emit(stack.push(local))
|
emitter.emit(stack.push(local))
|
||||||
except StackError as ex:
|
except StackError as ex:
|
||||||
raise analysis_error(ex.args[0], uop.body[0]) from None
|
raise analysis_error(ex.args[0], uop.body[0]) from None
|
||||||
|
|
||||||
|
@ -207,6 +201,7 @@ def generate_tier2(
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
out = CWriter(outfile, 2, lines)
|
out = CWriter(outfile, 2, lines)
|
||||||
|
emitter = Tier2Emitter(out)
|
||||||
out.emit("\n")
|
out.emit("\n")
|
||||||
for name, uop in analysis.uops.items():
|
for name, uop in analysis.uops.items():
|
||||||
if uop.properties.tier == 1:
|
if uop.properties.tier == 1:
|
||||||
|
@ -223,7 +218,7 @@ def generate_tier2(
|
||||||
out.emit(f"case {uop.name}: {{\n")
|
out.emit(f"case {uop.name}: {{\n")
|
||||||
declare_variables(uop, out)
|
declare_variables(uop, out)
|
||||||
stack = Stack()
|
stack = Stack()
|
||||||
write_uop(uop, out, stack)
|
write_uop(uop, emitter, stack)
|
||||||
out.start_line()
|
out.start_line()
|
||||||
if not uop.properties.always_exits:
|
if not uop.properties.always_exits:
|
||||||
stack.flush(out)
|
stack.flush(out)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue