Skip to content

Commit 1e2fecb

Browse files
committed
Allow super-instructions from ops
It seems this is harmless and possibly useful.
1 parent c41863b commit 1e2fecb

File tree

1 file changed

+109
-0
lines changed

1 file changed

+109
-0
lines changed

Tools/cases_generator/generate_cases.py

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -536,6 +536,115 @@ def stack_analysis(
536536
stack = [f"_tmp_{i+1}" for i in range(highest - lowest)]
537537
return stack, -lowest
538538

539+
def analyze_super(self, supe: parser.Super) -> SuperInstruction:
540+
components = self.check_super_components(supe)
541+
stack, initial_sp = self.stack_analysis(components)
542+
sp = initial_sp
543+
parts: list[Component] = []
544+
for component in components:
545+
match component:
546+
case parser.CacheEffect() as ceffect:
547+
parts.append(ceffect)
548+
case Instruction() as instr:
549+
input_mapping = {}
550+
for ieffect in reversed(instr.input_effects):
551+
sp -= 1
552+
if ieffect.name != "unused":
553+
input_mapping[stack[sp]] = ieffect
554+
output_mapping = {}
555+
for oeffect in instr.output_effects:
556+
if oeffect.name != "unused":
557+
output_mapping[stack[sp]] = oeffect
558+
sp += 1
559+
parts.append(Component(instr, input_mapping, output_mapping))
560+
case _:
561+
typing.assert_never(component)
562+
final_sp = sp
563+
return SuperInstruction(supe, stack, initial_sp, final_sp, parts)
564+
565+
# TODO: Rename 'supe: parser.Macro' to 'macro: parser.Macro' everywhere
566+
def analyze_macro(self, supe: parser.Macro) -> MacroInstruction:
567+
components = self.check_macro_components(supe)
568+
stack, initial_sp = self.stack_analysis(components)
569+
sp = initial_sp
570+
parts: list[Component | parser.CacheEffect] = []
571+
for component in components:
572+
match component:
573+
case parser.CacheEffect() as ceffect:
574+
parts.append(ceffect)
575+
case Instruction() as instr:
576+
input_mapping = {}
577+
for ieffect in reversed(instr.input_effects):
578+
sp -= 1
579+
if ieffect.name != "unused":
580+
input_mapping[stack[sp]] = ieffect
581+
output_mapping = {}
582+
for oeffect in instr.output_effects:
583+
if oeffect.name != "unused":
584+
output_mapping[stack[sp]] = oeffect
585+
sp += 1
586+
parts.append(Component(instr, input_mapping, output_mapping))
587+
case _:
588+
typing.assert_never(component)
589+
final_sp = sp
590+
return MacroInstruction(supe, stack, initial_sp, final_sp, parts)
591+
592+
def check_super_components(self, supe: parser.Super) -> list[Instruction]:
593+
components: list[Instruction] = []
594+
if not supe.ops:
595+
self.error(f"Super-instruction has no operands", supe)
596+
for op in supe.ops:
597+
if op.name not in self.instrs:
598+
self.error(f"Unknown instruction {op.name!r}", supe)
599+
else:
600+
components.append(self.instrs[op.name])
601+
return components
602+
603+
def check_macro_components(
604+
self, supe: parser.Macro
605+
) -> list[InstructionOrCacheEffect]:
606+
components: list[InstructionOrCacheEffect] = []
607+
if not supe.uops:
608+
self.error(f"Macro instruction has no operands", supe)
609+
for uop in supe.uops:
610+
match uop:
611+
case parser.OpName(name):
612+
if name not in self.instrs:
613+
self.error(f"Unknown instruction {name!r}", supe)
614+
components.append(self.instrs[name])
615+
case parser.CacheEffect():
616+
components.append(uop)
617+
case _:
618+
typing.assert_never(uop)
619+
return components
620+
621+
def stack_analysis(
622+
self, components: typing.Iterable[InstructionOrCacheEffect]
623+
) -> tuple[list[str], int]:
624+
"""Analyze a super-instruction or macro.
625+
626+
Print an error if there's a cache effect (which we don't support yet).
627+
628+
Return the list of variable names and the initial stack pointer.
629+
"""
630+
lowest = current = highest = 0
631+
for thing in components:
632+
match thing:
633+
case Instruction() as instr:
634+
current -= len(instr.input_effects)
635+
lowest = min(lowest, current)
636+
current += len(instr.output_effects)
637+
highest = max(highest, current)
638+
case parser.CacheEffect():
639+
pass
640+
case _:
641+
typing.assert_never(thing)
642+
# At this point, 'current' is the net stack effect,
643+
# and 'lowest' and 'highest' are the extremes.
644+
# Note that 'lowest' may be negative.
645+
stack = [f"_tmp_{i+1}" for i in range(highest - lowest)]
646+
return stack, -lowest
647+
539648
def write_instructions(self) -> None:
540649
"""Write instructions to output file."""
541650
with open(self.output_filename, "w") as f:

0 commit comments

Comments
 (0)