@@ -93,6 +93,13 @@ static cl::opt<bool> PreSchedFollowsSkipPipeliner(
93
93
" aie-presched-follows-skip-pipeliner" , cl::init(true ),
94
94
cl::desc(" Don't run the prescheduler if the pipeliner is skipped" ));
95
95
96
+ // / This option enables instruction mutuation to shift a multislot instruction
97
+ // / in event of a slot conflict.
98
+ static cl::opt<bool > InstructionMutation (
99
+ " aie-instruction-mutation" , cl::init(true ),
100
+ cl::desc(" Allow instruction mutation to shift a multislot "
101
+ " instruction in event of a slot conflict" ));
102
+
96
103
namespace {
97
104
// A sentinel value to represent an unknown SUnit.
98
105
const constexpr unsigned UnknownSUNum = ~0 ;
@@ -484,6 +491,164 @@ int AIEPostRASchedStrategy::getMaxDeltaCycles(const SchedBoundary &Zone) const {
484
491
BottomUpDelta.getValue ()});
485
492
}
486
493
494
+ static bool checkSlotConflict (const unsigned OpCodeA, const unsigned OpCodeB,
495
+ const AIEBaseMCFormats &Formats) {
496
+
497
+ const MCSlotKind SlotKindA = Formats.getSlotKind (OpCodeA);
498
+ const MCSlotKind SlotKindB = Formats.getSlotKind (OpCodeB);
499
+ const MCSlotKind UnknownSlot = MCSlotKind ();
500
+
501
+ if (SlotKindA == UnknownSlot || SlotKindB == UnknownSlot)
502
+ return false ;
503
+
504
+ const auto *SlotInfoA = Formats.getSlotInfo (SlotKindA);
505
+ const auto *SlotInfoB = Formats.getSlotInfo (SlotKindB);
506
+
507
+ return SlotInfoA->getSlotSet () & SlotInfoB->getSlotSet ();
508
+ }
509
+
510
+ bool AIEPostRASchedStrategy::canShiftSlot (SUnit &SU, SchedBoundary &Zone,
511
+ const int DeltaCycle) {
512
+
513
+ if (!InstructionMutation)
514
+ return false ;
515
+
516
+ const ScheduleDAGMI &DAG = *Zone.DAG ;
517
+ const AIEBaseInstrInfo &TII = *getTII (DAG);
518
+ const AIEBaseMCFormats &Formats = *TII.getFormatInterface ();
519
+ AIEHazardRecognizer &HR = *getAIEHazardRecognizer (Zone);
520
+ MachineInstr *NewMI = SU.getInstr ();
521
+ std::vector<MachineInstr *> ScheduledMultiSlotInsts;
522
+ bool CanShiftSlot = false ;
523
+
524
+ // Find and cache if there are any multi-slot instructions scheduled in the
525
+ // same delta cycle
526
+ for (MachineInstr &MI : DAG) {
527
+ SUnit *ZoneSU = DAG.getSUnit (&MI);
528
+ if (!ZoneSU)
529
+ continue ;
530
+ if (!ZoneSU->isScheduled )
531
+ continue ;
532
+
533
+ const int CurrCycle = Zone.getCurrCycle ();
534
+ if (ZoneSU->BotReadyCycle !=
535
+ static_cast <unsigned int >(CurrCycle - DeltaCycle))
536
+ continue ;
537
+
538
+ // Check for a MultiSlot instruction scheduled in the same DeltaCycle,
539
+ // we focus on multi-slot because they can be scheduled in different
540
+ // slots
541
+ auto AltOpcodes = Formats.getAlternateInstsOpcode (MI.getOpcode ());
542
+ if (!AltOpcodes)
543
+ continue ;
544
+ ScheduledMultiSlotInsts.push_back (&MI);
545
+ }
546
+
547
+ // If there are no multi-slot instructions scheduled in the same DeltaCycle we
548
+ // cannot shift any instruction to a different slot.
549
+ if (ScheduledMultiSlotInsts.empty ())
550
+ return false ;
551
+
552
+ const std::vector<unsigned int > *NewMIAltOpcodes;
553
+ auto DefaultOpcode = std::vector<unsigned int >{SU.getInstr ()->getOpcode ()};
554
+ NewMIAltOpcodes =
555
+ Formats.getAlternateInstsOpcode (SU.getInstr ()->getOpcode ())
556
+ ? Formats.getAlternateInstsOpcode (SU.getInstr ()->getOpcode ())
557
+ : &DefaultOpcode;
558
+
559
+ for (const unsigned int NewMIAltOpcode : *NewMIAltOpcodes) {
560
+ const MCInstrDesc &NewMIAltDesc = TII.get (NewMIAltOpcode);
561
+ if (!(HR.checkConflict (*NewMI, NewMIAltDesc, DeltaCycle) &
562
+ static_cast <uint32_t >(AIEHazardRecognizer::ConflictType::Format)))
563
+ continue ;
564
+
565
+ for (MachineInstr *MI : ScheduledMultiSlotInsts) {
566
+ SUnit *ZoneSU = DAG.getSUnit (MI);
567
+ const int CurrCycle = Zone.getCurrCycle ();
568
+ auto AltOpcodes = Formats.getAlternateInstsOpcode (MI->getOpcode ());
569
+
570
+ // Check if the scheduled multi-slot instruction has a slot conflict
571
+ // with the new instruction, if so we might have the possiblity to shift
572
+ // the multi-slot and schedule the new instruction.
573
+ if (!checkSlotConflict (HR.getSelectedAltDescs ().getOpcode (MI),
574
+ NewMIAltOpcode, Formats))
575
+ continue ;
576
+
577
+ // Release the multi-slot instruction from the scoreboard to check if
578
+ // any other alternate opcode in presence of the new instruction will
579
+ // not create a hazard.
580
+ HR.releaseFromScoreboard (*HR.getSelectedAltDescs ().getDesc (MI),
581
+ HR.getMemoryBanks (MI), MI->operands (),
582
+ MI->getMF ()->getRegInfo (),
583
+ CurrCycle - ZoneSU->BotReadyCycle );
584
+
585
+ // Check if the new instruction can be scheduled after unscheduling
586
+ // the conflicting multi-slot instruction.
587
+ if (HR.getHazardType (NewMIAltDesc, HR.getMemoryBanks (NewMI),
588
+ NewMI->operands (), NewMI->getMF ()->getRegInfo (),
589
+ DeltaCycle) !=
590
+ ScheduleHazardRecognizer::HazardType::NoHazard) {
591
+ // If the new instruction cannot be scheduled after unscheduling the
592
+ // mulit-slot revert back the state of scoreboard to original state
593
+ // and continue.
594
+
595
+ HR.emitInScoreboard (*HR.getSelectedAltDescs ().getDesc (MI),
596
+ HR.getMemoryBanks (MI), MI->operands (),
597
+ MI->getMF ()->getRegInfo (),
598
+ CurrCycle - ZoneSU->BotReadyCycle );
599
+ continue ;
600
+ }
601
+
602
+ // Emit the new instruction in the scoreboard. This will help us
603
+ // to check if the previously unscheduled multi-slot instruction
604
+ // can be scheduled in the same cycle, with an alternate opcode.
605
+ HR.emitInScoreboard (NewMIAltDesc, HR.getMemoryBanks (NewMI),
606
+ NewMI->operands (), NewMI->getMF ()->getRegInfo (),
607
+ DeltaCycle);
608
+
609
+ // Check if the previously unscheduled multi-slot instruction
610
+ // can be rescheduled in presense of the new instruction in the
611
+ // same cycle, with a different opcode.
612
+ for (const auto AltOpcodeInside : *AltOpcodes) {
613
+ const MCInstrDesc &Desc = TII.get (AltOpcodeInside);
614
+ if (HR.getHazardType (Desc, HR.getMemoryBanks (MI), MI->operands (),
615
+ MI->getMF ()->getRegInfo (), DeltaCycle) ==
616
+ ScheduleHazardRecognizer::HazardType::NoHazard) {
617
+ // Cache the information to mutate the instruction during bumpNode()
618
+ MutateInstruction.insert (
619
+ std::make_pair (NewMI, std::make_pair (MI, &Desc)));
620
+
621
+ // if the new instruction was a multi-slot instruction and it failed
622
+ // the general check for isAvailabeNode() this means we have not set
623
+ // the selected opcode for the instruction. Set the selected opcode
624
+ // for the instruction.
625
+ if (NewMIAltOpcodes->size () > 1 )
626
+ HR.getSelectedAltDescs ().setAlternateDescriptor (NewMI,
627
+ &NewMIAltDesc);
628
+
629
+ CanShiftSlot = true ;
630
+ break ;
631
+ }
632
+ }
633
+
634
+ // Revert back the state of scoreboard to original state.
635
+ HR.releaseFromScoreboard (NewMIAltDesc, HR.getMemoryBanks (NewMI),
636
+ NewMI->operands (), NewMI->getMF ()->getRegInfo (),
637
+ DeltaCycle);
638
+ HR.emitInScoreboard (*HR.getSelectedAltDescs ().getDesc (MI),
639
+ HR.getMemoryBanks (MI), MI->operands (),
640
+ MI->getMF ()->getRegInfo (),
641
+ CurrCycle - ZoneSU->BotReadyCycle );
642
+
643
+ if (CanShiftSlot)
644
+ break ;
645
+ }
646
+ if (CanShiftSlot)
647
+ break ;
648
+ }
649
+ return CanShiftSlot;
650
+ }
651
+
487
652
bool AIEPostRASchedStrategy::isAvailableNode (SUnit &SU, SchedBoundary &Zone,
488
653
bool /* VerifyReadyCycle*/ ) {
489
654
// Whether or not the zone is Top or Bot, verify if SU is ready to be
@@ -502,7 +667,8 @@ bool AIEPostRASchedStrategy::isAvailableNode(SUnit &SU, SchedBoundary &Zone,
502
667
// ReadyCycle is always greater or equal to the current cycle,
503
668
// so DeltaCycles will always be less or equal to 0.
504
669
if (Zone.checkHazard (&SU, DeltaCycles))
505
- continue ;
670
+ if (!canShiftSlot (SU, Zone, DeltaCycles))
671
+ continue ;
506
672
SU.BotReadyCycle = CurrCycle - DeltaCycles;
507
673
return true ;
508
674
}
@@ -519,10 +685,35 @@ void AIEPostRASchedStrategy::schedNode(SUnit *SU, bool IsTopNode) {
519
685
if (IsTopNode) {
520
686
PostGenericScheduler::schedNode (SU, IsTopNode);
521
687
} else {
688
+ AIEHazardRecognizer &HR = *getAIEHazardRecognizer (Bot);
522
689
int DeltaCycles = int (Bot.getCurrCycle ()) - int (SU->BotReadyCycle );
523
690
assert (DeltaCycles <= 0 );
691
+
692
+ // Check if an instruction needs to be moved to a different slot for the
693
+ // current SU to be scheduled in the DeltaCycles.
694
+ if (MutateInstruction.find (SU->getInstr ()) != MutateInstruction.end ()) {
695
+ auto &[MI, Desc] = MutateInstruction[SU->getInstr ()];
696
+ HR.releaseFromScoreboard (*HR.getSelectedAltDescs ().getDesc (MI),
697
+ HR.getMemoryBanks (MI), MI->operands (),
698
+ MI->getMF ()->getRegInfo (), DeltaCycles);
699
+ // Update the selected opcode for the instruction, refer
700
+ // AIEPostRASchedStrategy::canShiftSlot()
701
+ HR.getSelectedAltDescs ().setAlternateDescriptor (MI, Desc);
702
+
703
+ assert (HR.getHazardType (*Desc, HR.getMemoryBanks (MI), MI->operands (),
704
+ MI->getMF ()->getRegInfo (), DeltaCycles) ==
705
+ ScheduleHazardRecognizer::HazardType::NoHazard);
706
+ // Reschedule the instruction with the new opcode.
707
+ HR.emitInScoreboard (*Desc, HR.getMemoryBanks (MI), MI->operands (),
708
+ MI->getMF ()->getRegInfo (), DeltaCycles);
709
+ }
710
+
524
711
Bot.bumpNode (SU, DeltaCycles);
525
712
}
713
+ // Clear the MutateInstruction map since after scheduling the instruction the
714
+ // validity of mutation map can no longer be guaranteed.
715
+ MutateInstruction.clear ();
716
+ SU->isScheduled = true ;
526
717
}
527
718
528
719
void AIEPostRASchedStrategy::enterFunction (MachineFunction *MF) {
0 commit comments