gh-105229: Remove syntactic support for super-instructions (#105703)

It will not be used again.
This commit is contained in:
Guido van Rossum 2023-06-12 10:47:08 -07:00 committed by GitHub
parent 4f7d3b602d
commit b9e7dc797d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 38 additions and 143 deletions

View File

@ -390,7 +390,7 @@ class Instruction:
names_to_skip = self.unmoved_names | frozenset({UNUSED, "null"}) names_to_skip = self.unmoved_names | frozenset({UNUSED, "null"})
offset = 0 offset = 0
context = self.block.context context = self.block.context
assert context != None assert context is not None and context.owner is not None
filename = context.owner.filename filename = context.owner.filename
for line in self.block_text: for line in self.block_text:
out.set_lineno(self.block_line + offset, filename) out.set_lineno(self.block_line + offset, filename)
@ -464,28 +464,14 @@ class Component:
@dataclasses.dataclass @dataclasses.dataclass
class SuperOrMacroInstruction: class MacroInstruction:
"""Common fields for super- and macro instructions.""" """A macro instruction."""
name: str name: str
stack: list[StackEffect] stack: list[StackEffect]
initial_sp: int initial_sp: int
final_sp: int final_sp: int
instr_fmt: str instr_fmt: str
@dataclasses.dataclass
class SuperInstruction(SuperOrMacroInstruction):
"""A super-instruction."""
super: parser.Super
parts: list[Component]
@dataclasses.dataclass
class MacroInstruction(SuperOrMacroInstruction):
"""A macro instruction."""
macro: parser.Macro macro: parser.Macro
parts: list[Component | parser.CacheEffect] parts: list[Component | parser.CacheEffect]
predicted: bool = False predicted: bool = False
@ -505,7 +491,7 @@ class OverriddenInstructionPlaceHolder:
name: str name: str
AnyInstruction = Instruction | SuperInstruction | MacroInstruction AnyInstruction = Instruction | MacroInstruction
INSTR_FMT_PREFIX = "INSTR_FMT_" INSTR_FMT_PREFIX = "INSTR_FMT_"
@ -538,12 +524,9 @@ class Analyzer:
self.errors += 1 self.errors += 1
everything: list[ everything: list[
parser.InstDef | parser.Super | parser.Macro | parser.InstDef | parser.Macro | parser.Pseudo | OverriddenInstructionPlaceHolder
parser.Pseudo | OverriddenInstructionPlaceHolder
] ]
instrs: dict[str, Instruction] # Includes ops instrs: dict[str, Instruction] # Includes ops
supers: dict[str, parser.Super]
super_instrs: dict[str, SuperInstruction]
macros: dict[str, parser.Macro] macros: dict[str, parser.Macro]
macro_instrs: dict[str, MacroInstruction] macro_instrs: dict[str, MacroInstruction]
families: dict[str, parser.Family] families: dict[str, parser.Family]
@ -558,7 +541,6 @@ class Analyzer:
self.everything = [] self.everything = []
self.instrs = {} self.instrs = {}
self.supers = {}
self.macros = {} self.macros = {}
self.families = {} self.families = {}
self.pseudos = {} self.pseudos = {}
@ -571,7 +553,7 @@ class Analyzer:
files = " + ".join(self.input_filenames) files = " + ".join(self.input_filenames)
print( print(
f"Read {len(self.instrs)} instructions/ops, " f"Read {len(self.instrs)} instructions/ops, "
f"{len(self.supers)} supers, {len(self.macros)} macros, " f"{len(self.macros)} macros, {len(self.pseudos)} pseudos, "
f"and {len(self.families)} families from {files}", f"and {len(self.families)} families from {files}",
file=sys.stderr, file=sys.stderr,
) )
@ -605,7 +587,7 @@ class Analyzer:
# Parse from start # Parse from start
psr.setpos(start) psr.setpos(start)
thing: parser.InstDef | parser.Super | parser.Macro | parser.Family | None thing: parser.InstDef | parser.Macro | parser.Family | None
thing_first_token = psr.peek() thing_first_token = psr.peek()
while thing := psr.definition(): while thing := psr.definition():
match thing: match thing:
@ -627,9 +609,6 @@ class Analyzer:
self.instrs[name] = Instruction(thing) self.instrs[name] = Instruction(thing)
instrs_idx[name] = len(self.everything) instrs_idx[name] = len(self.everything)
self.everything.append(thing) self.everything.append(thing)
case parser.Super(name):
self.supers[name] = thing
self.everything.append(thing)
case parser.Macro(name): case parser.Macro(name):
self.macros[name] = thing self.macros[name] = thing
self.everything.append(thing) self.everything.append(thing)
@ -648,7 +627,7 @@ class Analyzer:
Raises SystemExit if there is an error. Raises SystemExit if there is an error.
""" """
self.analyze_supers_and_macros_and_pseudos() self.analyze_macros_and_pseudos()
self.find_predictions() self.find_predictions()
self.map_families() self.map_families()
self.check_families() self.check_families()
@ -656,7 +635,7 @@ class Analyzer:
def find_predictions(self) -> None: def find_predictions(self) -> None:
"""Find the instructions that need PREDICTED() labels.""" """Find the instructions that need PREDICTED() labels."""
for instr in self.instrs.values(): for instr in self.instrs.values():
targets = set() targets: set[str] = set()
for line in instr.block_text: for line in instr.block_text:
if m := re.match(RE_PREDICTED, line): if m := re.match(RE_PREDICTED, line):
targets.add(m.group(1)) targets.add(m.group(1))
@ -760,33 +739,15 @@ class Analyzer:
assert False, f"Unknown instruction {name!r}" assert False, f"Unknown instruction {name!r}"
return cache, input, output return cache, input, output
def analyze_supers_and_macros_and_pseudos(self) -> None: def analyze_macros_and_pseudos(self) -> None:
"""Analyze each super-, macro- and pseudo- instruction.""" """Analyze each super- and macro instruction."""
self.super_instrs = {}
self.macro_instrs = {} self.macro_instrs = {}
self.pseudo_instrs = {} self.pseudo_instrs = {}
for name, super in self.supers.items():
self.super_instrs[name] = self.analyze_super(super)
for name, macro in self.macros.items(): for name, macro in self.macros.items():
self.macro_instrs[name] = self.analyze_macro(macro) self.macro_instrs[name] = self.analyze_macro(macro)
for name, pseudo in self.pseudos.items(): for name, pseudo in self.pseudos.items():
self.pseudo_instrs[name] = self.analyze_pseudo(pseudo) self.pseudo_instrs[name] = self.analyze_pseudo(pseudo)
def analyze_super(self, super: parser.Super) -> SuperInstruction:
components = self.check_super_components(super)
stack, initial_sp = self.stack_analysis(components)
sp = initial_sp
parts: list[Component] = []
format = ""
for instr in components:
part, sp = self.analyze_instruction(instr, stack, sp)
parts.append(part)
format += instr.instr_fmt
final_sp = sp
return SuperInstruction(
super.name, stack, initial_sp, final_sp, format, super, parts
)
def analyze_macro(self, macro: parser.Macro) -> MacroInstruction: def analyze_macro(self, macro: parser.Macro) -> MacroInstruction:
components = self.check_macro_components(macro) components = self.check_macro_components(macro)
stack, initial_sp = self.stack_analysis(components) stack, initial_sp = self.stack_analysis(components)
@ -836,15 +797,6 @@ class Analyzer:
sp += 1 sp += 1
return Component(instr, input_mapping, output_mapping), sp return Component(instr, input_mapping, output_mapping), sp
def check_super_components(self, super: parser.Super) -> list[Instruction]:
components: list[Instruction] = []
for op in super.ops:
if op.name not in self.instrs:
self.error(f"Unknown instruction {op.name!r}", super)
else:
components.append(self.instrs[op.name])
return components
def check_macro_components( def check_macro_components(
self, macro: parser.Macro self, macro: parser.Macro
) -> list[InstructionOrCacheEffect]: ) -> list[InstructionOrCacheEffect]:
@ -864,7 +816,7 @@ class Analyzer:
def stack_analysis( def stack_analysis(
self, components: typing.Iterable[InstructionOrCacheEffect] self, components: typing.Iterable[InstructionOrCacheEffect]
) -> tuple[list[StackEffect], int]: ) -> tuple[list[StackEffect], int]:
"""Analyze a super-instruction or macro. """Analyze a macro.
Ignore cache effects. Ignore cache effects.
@ -880,8 +832,8 @@ class Analyzer:
# TODO: Eventually this will be needed, at least for macros. # TODO: Eventually this will be needed, at least for macros.
self.error( self.error(
f"Instruction {instr.name!r} has variable-sized stack effect, " f"Instruction {instr.name!r} has variable-sized stack effect, "
"which are not supported in super- or macro instructions", "which are not supported in macro instructions",
instr.inst, # TODO: Pass name+location of super/macro instr.inst, # TODO: Pass name+location of macro
) )
current -= len(instr.input_effects) current -= len(instr.input_effects)
lowest = min(lowest, current) lowest = min(lowest, current)
@ -901,7 +853,7 @@ class Analyzer:
return stack, -lowest return stack, -lowest
def get_stack_effect_info( def get_stack_effect_info(
self, thing: parser.InstDef | parser.Super | parser.Macro | parser.Pseudo self, thing: parser.InstDef | parser.Macro | parser.Pseudo
) -> tuple[AnyInstruction | None, str, str]: ) -> tuple[AnyInstruction | None, str, str]:
def effect_str(effects: list[StackEffect]) -> str: def effect_str(effects: list[StackEffect]) -> str:
if getattr(thing, "kind", None) == "legacy": if getattr(thing, "kind", None) == "legacy":
@ -922,15 +874,6 @@ class Analyzer:
instr = None instr = None
popped = "" popped = ""
pushed = "" pushed = ""
case parser.Super():
instr = self.super_instrs[thing.name]
# TODO: Same as for Macro below, if needed.
popped = "+".join(
effect_str(comp.instr.input_effects) for comp in instr.parts
)
pushed = "+".join(
effect_str(comp.instr.output_effects) for comp in instr.parts
)
case parser.Macro(): case parser.Macro():
instr = self.macro_instrs[thing.name] instr = self.macro_instrs[thing.name]
parts = [comp for comp in instr.parts if isinstance(comp, Component)] parts = [comp for comp in instr.parts if isinstance(comp, Component)]
@ -1032,8 +975,6 @@ class Analyzer:
continue continue
case parser.InstDef(): case parser.InstDef():
format = self.instrs[thing.name].instr_fmt format = self.instrs[thing.name].instr_fmt
case parser.Super():
format = self.super_instrs[thing.name].instr_fmt
case parser.Macro(): case parser.Macro():
format = self.macro_instrs[thing.name].instr_fmt format = self.macro_instrs[thing.name].instr_fmt
case parser.Pseudo(): case parser.Pseudo():
@ -1092,8 +1033,6 @@ class Analyzer:
case parser.InstDef(): case parser.InstDef():
if thing.kind != "op": if thing.kind != "op":
self.write_metadata_for_inst(self.instrs[thing.name]) self.write_metadata_for_inst(self.instrs[thing.name])
case parser.Super():
self.write_metadata_for_super(self.super_instrs[thing.name])
case parser.Macro(): case parser.Macro():
self.write_metadata_for_macro(self.macro_instrs[thing.name]) self.write_metadata_for_macro(self.macro_instrs[thing.name])
case parser.Pseudo(): case parser.Pseudo():
@ -1118,12 +1057,6 @@ class Analyzer:
f" [{instr.name}] = {{ true, {INSTR_FMT_PREFIX}{instr.instr_fmt} }}," f" [{instr.name}] = {{ true, {INSTR_FMT_PREFIX}{instr.instr_fmt} }},"
) )
def write_metadata_for_super(self, sup: SuperInstruction) -> None:
"""Write metadata for a super-instruction."""
self.out.emit(
f" [{sup.name}] = {{ true, {INSTR_FMT_PREFIX}{sup.instr_fmt} }},"
)
def write_metadata_for_macro(self, mac: MacroInstruction) -> None: def write_metadata_for_macro(self, mac: MacroInstruction) -> None:
"""Write metadata for a macro-instruction.""" """Write metadata for a macro-instruction."""
self.out.emit( self.out.emit(
@ -1149,7 +1082,6 @@ class Analyzer:
# Write and count instructions of all kinds # Write and count instructions of all kinds
n_instrs = 0 n_instrs = 0
n_supers = 0
n_macros = 0 n_macros = 0
n_pseudos = 0 n_pseudos = 0
for thing in self.everything: for thing in self.everything:
@ -1160,9 +1092,6 @@ class Analyzer:
if thing.kind != "op": if thing.kind != "op":
n_instrs += 1 n_instrs += 1
self.write_instr(self.instrs[thing.name]) self.write_instr(self.instrs[thing.name])
case parser.Super():
n_supers += 1
self.write_super(self.super_instrs[thing.name])
case parser.Macro(): case parser.Macro():
n_macros += 1 n_macros += 1
self.write_macro(self.macro_instrs[thing.name]) self.write_macro(self.macro_instrs[thing.name])
@ -1172,8 +1101,8 @@ class Analyzer:
typing.assert_never(thing) typing.assert_never(thing)
print( print(
f"Wrote {n_instrs} instructions, {n_supers} supers, {n_macros}" f"Wrote {n_instrs} instructions, {n_macros} macros, "
f" macros and {n_pseudos} pseudos to {self.output_filename}", f"and {n_pseudos} pseudos to {self.output_filename}",
file=sys.stderr, file=sys.stderr,
) )
@ -1197,23 +1126,10 @@ class Analyzer:
self.out.emit("CHECK_EVAL_BREAKER();") self.out.emit("CHECK_EVAL_BREAKER();")
self.out.emit(f"DISPATCH();") self.out.emit(f"DISPATCH();")
def write_super(self, sup: SuperInstruction) -> None:
"""Write code for a super-instruction."""
with self.wrap_super_or_macro(sup):
first = True
for comp in sup.parts:
if not first:
self.out.emit("oparg = (next_instr++)->op.arg;")
# self.out.emit("next_instr += OPSIZE(opcode) - 1;")
first = False
comp.write_body(self.out, 0)
if comp.instr.cache_offset:
self.out.emit(f"next_instr += {comp.instr.cache_offset};")
def write_macro(self, mac: MacroInstruction) -> None: def write_macro(self, mac: MacroInstruction) -> None:
"""Write code for a macro instruction.""" """Write code for a macro instruction."""
last_instr: Instruction | None = None last_instr: Instruction | None = None
with self.wrap_super_or_macro(mac): with self.wrap_macro(mac):
cache_adjust = 0 cache_adjust = 0
for part in mac.parts: for part in mac.parts:
match part: match part:
@ -1239,30 +1155,29 @@ class Analyzer:
) )
@contextlib.contextmanager @contextlib.contextmanager
def wrap_super_or_macro(self, up: SuperOrMacroInstruction): def wrap_macro(self, mac: MacroInstruction):
"""Shared boilerplate for super- and macro instructions.""" """Boilerplate for macro instructions."""
# TODO: Somewhere (where?) make it so that if one instruction # TODO: Somewhere (where?) make it so that if one instruction
# has an output that is input to another, and the variable names # has an output that is input to another, and the variable names
# and types match and don't conflict with other instructions, # and types match and don't conflict with other instructions,
# that variable is declared with the right name and type in the # that variable is declared with the right name and type in the
# outer block, rather than trusting the compiler to optimize it. # outer block, rather than trusting the compiler to optimize it.
self.out.emit("") self.out.emit("")
with self.out.block(f"TARGET({up.name})"): with self.out.block(f"TARGET({mac.name})"):
match up: if mac.predicted:
case MacroInstruction(predicted=True, name=name): self.out.emit(f"PREDICTED({mac.name});")
self.out.emit(f"PREDICTED({name});") for i, var in reversed(list(enumerate(mac.stack))):
for i, var in reversed(list(enumerate(up.stack))):
src = None src = None
if i < up.initial_sp: if i < mac.initial_sp:
src = StackEffect(f"stack_pointer[-{up.initial_sp - i}]", "") src = StackEffect(f"stack_pointer[-{mac.initial_sp - i}]", "")
self.out.declare(var, src) self.out.declare(var, src)
yield yield
# TODO: Use slices of up.stack instead of numeric values # TODO: Use slices of mac.stack instead of numeric values
self.out.stack_adjust(up.final_sp - up.initial_sp, [], []) self.out.stack_adjust(mac.final_sp - mac.initial_sp, [], [])
for i, var in enumerate(reversed(up.stack[: up.final_sp]), 1): for i, var in enumerate(reversed(mac.stack[: mac.final_sp]), 1):
dst = StackEffect(f"stack_pointer[-{i}]", "") dst = StackEffect(f"stack_pointer[-{i}]", "")
self.out.assign(dst, var) self.out.assign(dst, var)

View File

@ -118,12 +118,6 @@ class InstDef(Node):
block: Block block: Block
@dataclass
class Super(Node):
name: str
ops: list[OpName]
@dataclass @dataclass
class Macro(Node): class Macro(Node):
name: str name: str
@ -144,11 +138,9 @@ class Pseudo(Node):
class Parser(PLexer): class Parser(PLexer):
@contextual @contextual
def definition(self) -> InstDef | Super | Macro | Family | Pseudo | None: def definition(self) -> InstDef | Macro | Pseudo | Family | None:
if inst := self.inst_def(): if inst := self.inst_def():
return inst return inst
if super := self.super_def():
return super
if macro := self.macro_def(): if macro := self.macro_def():
return macro return macro
if family := self.family_def(): if family := self.family_def():
@ -287,25 +279,13 @@ class Parser(PLexer):
return None return None
return Expression(lx.to_text(tokens).strip()) return Expression(lx.to_text(tokens).strip())
@contextual # def ops(self) -> list[OpName] | None:
def super_def(self) -> Super | None: # if op := self.op():
if (tkn := self.expect(lx.IDENTIFIER)) and tkn.text == "super": # ops = [op]
if self.expect(lx.LPAREN): # while self.expect(lx.PLUS):
if tkn := self.expect(lx.IDENTIFIER): # if op := self.op():
if self.expect(lx.RPAREN): # ops.append(op)
if self.expect(lx.EQUALS): # return ops
if ops := self.ops():
self.require(lx.SEMI)
res = Super(tkn.text, ops)
return res
def ops(self) -> list[OpName] | None:
if op := self.op():
ops = [op]
while self.expect(lx.PLUS):
if op := self.op():
ops.append(op)
return ops
@contextual @contextual
def op(self) -> OpName | None: def op(self) -> OpName | None:
@ -432,7 +412,7 @@ if __name__ == "__main__":
src = sys.argv[2] src = sys.argv[2]
filename = "<string>" filename = "<string>"
else: else:
with open(filename) as f: with open(filename, "r") as f:
src = f.read() src = f.read()
srclines = src.splitlines() srclines = src.splitlines()
begin = srclines.index("// BEGIN BYTECODES //") begin = srclines.index("// BEGIN BYTECODES //")