diff --git a/llvm/lib/Target/AIE/AIEHazardRecognizer.cpp b/llvm/lib/Target/AIE/AIEHazardRecognizer.cpp index a17aa7ca1f6c..bf3f3ce97369 100644 --- a/llvm/lib/Target/AIE/AIEHazardRecognizer.cpp +++ b/llvm/lib/Target/AIE/AIEHazardRecognizer.cpp @@ -548,7 +548,7 @@ bool AIEHazardRecognizer::onlyFormatHazard( const ResourceScoreboard &TheScoreboard, const MCInstrDesc &Desc, MemoryBankBits MemoryBanks, iterator_range MIOperands, - const MachineRegisterInfo &MRI, int DeltaCycles) { + const MachineRegisterInfo &MRI, int DeltaCycles) const { unsigned const SchedClass = TII->getSchedClass(Desc, MIOperands, MRI); SlotBits SlotSet = @@ -568,7 +568,7 @@ bool AIEHazardRecognizer::onlyFormatHazard( return checkFormatConflict(Scoreboard, DeltaCycles, SlotSet); } -bool AIEHazardRecognizer::onlyFormatHazard(SUnit *SU, int DeltaCycles) { +bool AIEHazardRecognizer::onlyFormatHazard(SUnit *SU, int DeltaCycles) const { MachineInstr *MI = SU->getInstr(); const std::vector *AlternateInsts = TII->getFormatInterface()->getAlternateInstsOpcode(MI->getOpcode()); diff --git a/llvm/lib/Target/AIE/AIEHazardRecognizer.h b/llvm/lib/Target/AIE/AIEHazardRecognizer.h index 20f879f9dbee..fe7c0d3abf3a 100644 --- a/llvm/lib/Target/AIE/AIEHazardRecognizer.h +++ b/llvm/lib/Target/AIE/AIEHazardRecognizer.h @@ -121,7 +121,7 @@ class AIEHazardRecognizer : public ScheduleHazardRecognizer { void RecedeCycle() override; // Check if the instruction only has a format hazard - bool onlyFormatHazard(SUnit *SU, int DeltaCycles); + bool onlyFormatHazard(SUnit *SU, int DeltaCycles) const; /// Check conflict with Other shifted by DeltaCycles into the /// future relative to *this. @@ -195,6 +195,10 @@ class AIEHazardRecognizer : public ScheduleHazardRecognizer { return SelectedAltDescs; } + ResourceScoreboard getScoreboard() const { + return Scoreboard; + } + ScheduleHazardRecognizer::HazardType getHazardType(const ResourceScoreboard &TheScoreboard, const MCInstrDesc &Desc, MemoryBankBits MemoryBanks, @@ -232,7 +236,7 @@ class AIEHazardRecognizer : public ScheduleHazardRecognizer { onlyFormatHazard(const ResourceScoreboard &TheScoreboard, const MCInstrDesc &Desc, MemoryBankBits MemoryBanks, iterator_range MIOperands, - const MachineRegisterInfo &MRI, int DeltaCycles); + const MachineRegisterInfo &MRI, int DeltaCycles) const; static void enterResources(ResourceScoreboard &Scoreboard, const InstrItineraryData *ItinData, diff --git a/llvm/lib/Target/AIE/AIEMachineScheduler.cpp b/llvm/lib/Target/AIE/AIEMachineScheduler.cpp index cda5c78c5c98..f8d8aee7f298 100644 --- a/llvm/lib/Target/AIE/AIEMachineScheduler.cpp +++ b/llvm/lib/Target/AIE/AIEMachineScheduler.cpp @@ -474,6 +474,115 @@ int AIEPostRASchedStrategy::getMaxDeltaCycles(const SchedBoundary &Zone) const { BottomUpDelta.getValue()}); } +static bool checkSlotConflict(const unsigned OpCodeA, const unsigned OpCodeB, + const AIEBaseMCFormats &Formats) { + + MCSlotKind SlotKindA = Formats.getSlotKind(OpCodeA); + MCSlotKind SlotKindB = Formats.getSlotKind(OpCodeB); + + if (SlotKindA != MCSlotKind() && SlotKindB != MCSlotKind()) { + return (Formats.getSlotInfo(SlotKindA)->getSlotSet() & + Formats.getSlotInfo(SlotKindB)->getSlotSet()); + } + return true; +} + +bool AIEPostRASchedStrategy::canShiftSlot(SUnit &SU, SchedBoundary &Zone, + const int DeltaCycle) { + + const AIEBaseMCFormats &Formats = *getTII(*Zone.DAG)->getFormatInterface(); + const AIEHazardRecognizer &HR = *getAIEHazardRecognizer(Zone); + + if (!(!Formats.getAlternateInstsOpcode(SU.getInstr()->getOpcode()) && + HR.onlyFormatHazard(&SU, DeltaCycle))) { + // We are only interested in single slot instructions and instructions that + // have only format hazard. + // TODO : Extend this to SUs that are multi-slot and have only format hazard + return false; + } + for (MachineInstr &MI : *Zone.DAG) { + SUnit *ZoneSU = Zone.DAG->getSUnit(&MI); + if (!ZoneSU) + continue; + if (!ZoneSU->isScheduled) + continue; + + const int CurrCycle = Zone.getCurrCycle(); + if (ZoneSU->BotReadyCycle != (CurrCycle - DeltaCycle)) + continue; + + // Check for a MultiSlot instruction scheduled in the same DeltaCycle, we + // focus on multi-slot because they can be scheduled in different slots + auto AltOpcodes = Formats.getAlternateInstsOpcode(MI.getOpcode()); + if (!AltOpcodes) + continue; + + // Check if the scheduled multi-slot instruction has a slot conflict + // with the new instruction, if so we might have the possiblity to shift + // the multi-slot and schedule the new instruction. + if (!checkSlotConflict(HR.getSelectedAltDescs().getOpcode(&MI), + SU.getInstr()->getOpcode(), Formats)) + continue; + + // Check if there are any alternate opcodes such that it will not lead to + // slot conflict with the new instruction. + for (const auto AltOpcode : *AltOpcodes) { + if (checkSlotConflict(AltOpcode, SU.getInstr()->getOpcode(), Formats)) + continue; + + dbgs() << "NO Slot conflict with a multislot instruction " << AltOpcode + << "\n"; + + // Create a local scoreboard to check if the new instruction can be + // scheduled after moving the conflicting multi-slot instruction to a new + // slot. + ResourceScoreboard LocalScoreboard = HR.getScoreboard(); + + // Release the multi-slot instruction from the scoreboard since a + // alternate opcode is found that will not lead to slot conflict with the + // new instruction. + HR.releaseFromScoreboard( + LocalScoreboard, *HR.getSelectedAltDescs().getDesc(&MI), + HR.getMemoryBanks(&MI), MI.operands(), MI.getMF()->getRegInfo(), + CurrCycle - ZoneSU->BotReadyCycle); + + MachineInstr *NewMI = SU.getInstr(); + // Check if the new instuction can be scheduled after unscheduling + // the conflicting multi-slot instruction. + if (HR.getHazardType(LocalScoreboard, NewMI->getDesc(), + HR.getMemoryBanks(NewMI), NewMI->operands(), + NewMI->getMF()->getRegInfo(), DeltaCycle) != + ScheduleHazardRecognizer::HazardType::NoHazard) + continue; + + dbgs() << "New AltOpcode " << AltOpcode + << " Possible Successfull slot shift for " << *SU.getInstr(); + // Emit the new instruction in the scoreboard. This will help us + // to check if the previously unscheduled multi-slot instruction + // can be scheduled in the same cycle. + HR.emitInScoreboard(LocalScoreboard, NewMI->getDesc(), + HR.getMemoryBanks(NewMI), NewMI->operands(), + NewMI->getMF()->getRegInfo(), DeltaCycle); + + // Check if the previously unscheduled multi-slot instruction + // can be rescheduled in presense of the new instruction in the + // same cycle. + for (const auto AltOpcodeInside : *AltOpcodes) { + if (HR.getHazardType( + LocalScoreboard, getTII(*Zone.DAG)->get(AltOpcodeInside), + HR.getMemoryBanks(&MI), MI.operands(), MI.getMF()->getRegInfo(), + DeltaCycle) == ScheduleHazardRecognizer::HazardType::NoHazard) { + dbgs() << "Slot shift successfull for " << *SU.getInstr(); + return true; + } + } + + dbgs() << "Rescheduling not helped\n"; + } + } + return false; +} + bool AIEPostRASchedStrategy::isAvailableNode(SUnit &SU, SchedBoundary &Zone, bool /*VerifyReadyCycle*/) { // Whether or not the zone is Top or Bot, verify if SU is ready to be @@ -492,7 +601,8 @@ bool AIEPostRASchedStrategy::isAvailableNode(SUnit &SU, SchedBoundary &Zone, // ReadyCycle is always greater or equal to the current cycle, // so DeltaCycles will always be less or equal to 0. if (Zone.checkHazard(&SU, DeltaCycles)) - continue; + if (!canShiftSlot(SU, Zone, DeltaCycles)) + continue; SU.BotReadyCycle = CurrCycle - DeltaCycles; return true; } diff --git a/llvm/lib/Target/AIE/AIEMachineScheduler.h b/llvm/lib/Target/AIE/AIEMachineScheduler.h index ef8bf62b9ad7..c9dbedc31e75 100644 --- a/llvm/lib/Target/AIE/AIEMachineScheduler.h +++ b/llvm/lib/Target/AIE/AIEMachineScheduler.h @@ -50,6 +50,7 @@ class AIEPostRASchedStrategy : public PostGenericScheduler { SUnit *pickNodeAndCycle(bool &IsTopNode, std::optional &BotEmissionCycle) override; + bool canShiftSlot(SUnit &SU, SchedBoundary &Zone, const int DeltaCycle); bool isAvailableNode(SUnit &SU, SchedBoundary &Zone, bool VerifyReadyCycle) override;