@@ -536,6 +536,115 @@ def stack_analysis(
536
536
stack = [f"_tmp_{ i + 1 } " for i in range (highest - lowest )]
537
537
return stack , - lowest
538
538
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
+
539
648
def write_instructions (self ) -> None :
540
649
"""Write instructions to output file."""
541
650
with open (self .output_filename , "w" ) as f :
0 commit comments