@@ -94,6 +94,13 @@ static cl::opt<bool> PreSchedFollowsSkipPipeliner(
94
94
" aie-presched-follows-skip-pipeliner" , cl::init(true ),
95
95
cl::desc(" Don't run the prescheduler if the pipeliner is skipped" ));
96
96
97
+ // / This option enables instruction mutuation to shift a multislot instruction
98
+ // / in event of a slot conflict.
99
+ static cl::opt<bool > InstructionMutation (
100
+ " aie-instruction-mutation" , cl::init(true ),
101
+ cl::desc(" Allow instruction mutation to shift a multislot "
102
+ " instruction in event of a slot conflict" ));
103
+
97
104
namespace {
98
105
// A sentinel value to represent an unknown SUnit.
99
106
const constexpr unsigned UnknownSUNum = ~0 ;
@@ -643,6 +650,168 @@ bool AIEPostRASchedStrategy::isFreeSU(const SUnit &SU) const {
643
650
SU.NodeNum < FirstBotFixedSU.value_or (NumUpperBound);
644
651
}
645
652
653
+ static bool checkSlotConflict (const unsigned OpCodeA, const unsigned OpCodeB,
654
+ const AIEBaseMCFormats &Formats) {
655
+
656
+ const MCSlotKind SlotKindA = Formats.getSlotKind (OpCodeA);
657
+ const MCSlotKind SlotKindB = Formats.getSlotKind (OpCodeB);
658
+ const MCSlotKind UnknownSlot = MCSlotKind ();
659
+
660
+ if (SlotKindA == UnknownSlot || SlotKindB == UnknownSlot)
661
+ return false ;
662
+
663
+ const auto *SlotInfoA = Formats.getSlotInfo (SlotKindA);
664
+ const auto *SlotInfoB = Formats.getSlotInfo (SlotKindB);
665
+
666
+ return SlotInfoA->getSlotSet () & SlotInfoB->getSlotSet ();
667
+ }
668
+
669
+ // Check if moving a scheduled multi-slot instruction to a different slot allows
670
+ // us to schedule SU in the same DeltaCycle. If a multi-slot instruction
671
+ // candidate is identified, it is preserved in a map so that when SU is
672
+ // scheduled, the candidate is first moved to a new slot and then the SU is
673
+ // emitted.
674
+ bool AIEPostRASchedStrategy::canShiftSlot (SUnit &SU, SchedBoundary &Zone,
675
+ const int DeltaCycle) {
676
+
677
+ if (!InstructionMutation)
678
+ return false ;
679
+
680
+ const ScheduleDAGMI &DAG = *Zone.DAG ;
681
+ const AIEBaseInstrInfo &TII = *getTII (DAG);
682
+ const AIEBaseMCFormats &Formats = *TII.getFormatInterface ();
683
+ AIEHazardRecognizer &HR = *getAIEHazardRecognizer (Zone);
684
+ MachineInstr *NewMI = SU.getInstr ();
685
+ std::vector<MachineInstr *> ScheduledMultiSlotInsts;
686
+ bool CanShiftSlot = false ;
687
+
688
+ // Find and cache if there are any multi-slot instructions scheduled in the
689
+ // same delta cycle
690
+ for (MachineInstr &MI : DAG) {
691
+ SUnit *ZoneSU = DAG.getSUnit (&MI);
692
+ if (!ZoneSU)
693
+ continue ;
694
+ if (!ZoneSU->isScheduled )
695
+ continue ;
696
+
697
+ const int CurrCycle = Zone.getCurrCycle ();
698
+ if (ZoneSU->BotReadyCycle !=
699
+ static_cast <unsigned int >(CurrCycle - DeltaCycle))
700
+ continue ;
701
+
702
+ // Check for a MultiSlot instruction scheduled in the same DeltaCycle,
703
+ // we focus on multi-slot because they can be scheduled in different
704
+ // slots
705
+ auto AltOpcodes = Formats.getAlternateInstsOpcode (MI.getOpcode ());
706
+ if (!AltOpcodes)
707
+ continue ;
708
+ ScheduledMultiSlotInsts.push_back (&MI);
709
+ }
710
+
711
+ // If there are no multi-slot instructions scheduled in the same DeltaCycle we
712
+ // cannot shift any instruction to a different slot.
713
+ if (ScheduledMultiSlotInsts.empty ())
714
+ return false ;
715
+
716
+ auto DefaultOpcode = std::vector<unsigned int >{SU.getInstr ()->getOpcode ()};
717
+ const std::vector<unsigned int > *NewMIAltOpcodes =
718
+ Formats.getAlternateInstsOpcode (SU.getInstr ()->getOpcode ())
719
+ ? Formats.getAlternateInstsOpcode (SU.getInstr ()->getOpcode ())
720
+ : &DefaultOpcode;
721
+
722
+ for (const unsigned int NewMIAltOpcode : *NewMIAltOpcodes) {
723
+ const MCInstrDesc &NewMIAltDesc = TII.get (NewMIAltOpcode);
724
+ if (!(HR.checkConflict (*NewMI, NewMIAltDesc, DeltaCycle) &
725
+ static_cast <uint32_t >(AIEHazardRecognizer::ConflictType::Format)))
726
+ continue ;
727
+
728
+ for (MachineInstr *MI : ScheduledMultiSlotInsts) {
729
+ SUnit *ZoneSU = DAG.getSUnit (MI);
730
+ const int CurrCycle = Zone.getCurrCycle ();
731
+ auto AltOpcodes = Formats.getAlternateInstsOpcode (MI->getOpcode ());
732
+
733
+ // Check if the scheduled multi-slot instruction has a slot conflict
734
+ // with the new instruction, if so we might have the possiblity to shift
735
+ // the multi-slot and schedule the new instruction.
736
+ if (!checkSlotConflict (HR.getSelectedAltDescs ().getOpcode (MI),
737
+ NewMIAltOpcode, Formats))
738
+ continue ;
739
+
740
+ // Release the multi-slot instruction from the scoreboard to check if
741
+ // any other alternate opcode in presence of the new instruction will
742
+ // not create a hazard.
743
+ HR.releaseFromScoreboard (*HR.getSelectedAltDescs ().getDesc (MI),
744
+ HR.getMemoryBanks (MI), MI->operands (),
745
+ MI->getMF ()->getRegInfo (),
746
+ CurrCycle - ZoneSU->BotReadyCycle );
747
+
748
+ // Check if the new instruction can be scheduled after unscheduling
749
+ // the conflicting multi-slot instruction.
750
+ if (HR.getHazardType (NewMIAltDesc, HR.getMemoryBanks (NewMI),
751
+ NewMI->operands (), NewMI->getMF ()->getRegInfo (),
752
+ DeltaCycle) !=
753
+ ScheduleHazardRecognizer::HazardType::NoHazard) {
754
+ // If the new instruction cannot be scheduled after unscheduling the
755
+ // mulit-slot revert back the state of scoreboard to original state
756
+ // and continue.
757
+
758
+ HR.emitInScoreboard (*HR.getSelectedAltDescs ().getDesc (MI),
759
+ HR.getMemoryBanks (MI), MI->operands (),
760
+ MI->getMF ()->getRegInfo (),
761
+ CurrCycle - ZoneSU->BotReadyCycle );
762
+ continue ;
763
+ }
764
+
765
+ // Emit the new instruction in the scoreboard. This will help us
766
+ // to check if the previously unscheduled multi-slot instruction
767
+ // can be scheduled in the same cycle, with an alternate opcode.
768
+ HR.emitInScoreboard (NewMIAltDesc, HR.getMemoryBanks (NewMI),
769
+ NewMI->operands (), NewMI->getMF ()->getRegInfo (),
770
+ DeltaCycle);
771
+
772
+ // Check if the previously unscheduled multi-slot instruction
773
+ // can be rescheduled in presense of the new instruction in the
774
+ // same cycle, with a different opcode.
775
+ for (const auto AltOpcodeInside : *AltOpcodes) {
776
+ const MCInstrDesc &Desc = TII.get (AltOpcodeInside);
777
+ if (HR.getHazardType (Desc, HR.getMemoryBanks (MI), MI->operands (),
778
+ MI->getMF ()->getRegInfo (), DeltaCycle) ==
779
+ ScheduleHazardRecognizer::HazardType::NoHazard) {
780
+ // Cache the information to mutate the instruction during bumpNode()
781
+ MutateInstruction.insert (
782
+ std::make_pair (NewMI, std::make_pair (MI, &Desc)));
783
+
784
+ // if the new instruction was a multi-slot instruction and it failed
785
+ // the general check for isAvailabeNode() this means we have not set
786
+ // the selected opcode for the instruction. Set the selected opcode
787
+ // for the instruction.
788
+ if (NewMIAltOpcodes->size () > 1 )
789
+ HR.getSelectedAltDescs ().setAlternateDescriptor (NewMI,
790
+ &NewMIAltDesc);
791
+
792
+ CanShiftSlot = true ;
793
+ break ;
794
+ }
795
+ }
796
+
797
+ // Revert back the state of scoreboard to original state.
798
+ HR.releaseFromScoreboard (NewMIAltDesc, HR.getMemoryBanks (NewMI),
799
+ NewMI->operands (), NewMI->getMF ()->getRegInfo (),
800
+ DeltaCycle);
801
+ HR.emitInScoreboard (*HR.getSelectedAltDescs ().getDesc (MI),
802
+ HR.getMemoryBanks (MI), MI->operands (),
803
+ MI->getMF ()->getRegInfo (),
804
+ CurrCycle - ZoneSU->BotReadyCycle );
805
+
806
+ if (CanShiftSlot)
807
+ break ;
808
+ }
809
+ if (CanShiftSlot)
810
+ break ;
811
+ }
812
+ return CanShiftSlot;
813
+ }
814
+
646
815
bool AIEPostRASchedStrategy::isAvailableNode (SUnit &SU, SchedBoundary &Zone,
647
816
bool /* VerifyReadyCycle*/ ) {
648
817
// Note we use signed integers to avoid wrap-around behavior.
@@ -692,7 +861,8 @@ bool AIEPostRASchedStrategy::isAvailableNode(SUnit &SU, SchedBoundary &Zone,
692
861
// ReadyCycle is always greater or equal to the current cycle,
693
862
// so DeltaCycles will always be less or equal to 0.
694
863
if (Zone.checkHazard (&SU, DeltaCycles))
695
- continue ;
864
+ if (!canShiftSlot (SU, Zone, DeltaCycles))
865
+ continue ;
696
866
SU.BotReadyCycle = CurrCycle - DeltaCycles;
697
867
return true ;
698
868
}
@@ -711,10 +881,35 @@ void AIEPostRASchedStrategy::schedNode(SUnit *SU, bool IsTopNode) {
711
881
assert (DeltaCycles <= 0 );
712
882
Top.bumpNode (SU, DeltaCycles);
713
883
} else {
884
+ AIEHazardRecognizer &HR = *getAIEHazardRecognizer (Bot);
714
885
int DeltaCycles = int (Bot.getCurrCycle ()) - int (SU->BotReadyCycle );
715
886
assert (DeltaCycles <= 0 );
887
+
888
+ // Check if an instruction needs to be moved to a different slot for the
889
+ // current SU to be scheduled in the DeltaCycles.
890
+ if (MutateInstruction.find (SU->getInstr ()) != MutateInstruction.end ()) {
891
+ auto &[MI, Desc] = MutateInstruction[SU->getInstr ()];
892
+ HR.releaseFromScoreboard (*HR.getSelectedAltDescs ().getDesc (MI),
893
+ HR.getMemoryBanks (MI), MI->operands (),
894
+ MI->getMF ()->getRegInfo (), DeltaCycles);
895
+ // Update the selected opcode for the instruction, refer
896
+ // AIEPostRASchedStrategy::canShiftSlot()
897
+ HR.getSelectedAltDescs ().setAlternateDescriptor (MI, Desc);
898
+
899
+ assert (HR.getHazardType (*Desc, HR.getMemoryBanks (MI), MI->operands (),
900
+ MI->getMF ()->getRegInfo (), DeltaCycles) ==
901
+ ScheduleHazardRecognizer::HazardType::NoHazard);
902
+ // Reschedule the instruction with the new opcode.
903
+ HR.emitInScoreboard (*Desc, HR.getMemoryBanks (MI), MI->operands (),
904
+ MI->getMF ()->getRegInfo (), DeltaCycles);
905
+ }
906
+
716
907
Bot.bumpNode (SU, DeltaCycles);
717
908
}
909
+ // Clear the MutateInstruction map since after scheduling the instruction the
910
+ // validity of mutation map can no longer be guaranteed.
911
+ MutateInstruction.clear ();
912
+ SU->isScheduled = true ;
718
913
}
719
914
720
915
void AIEPostRASchedStrategy::enterFunction (MachineFunction *MF) {
0 commit comments