xref: /freebsd/contrib/llvm-project/llvm/lib/Target/Hexagon/HexagonHazardRecognizer.cpp (revision 81ad626541db97eb356e2c1d4a20eb2a26a766ab)
10b57cec5SDimitry Andric //===-- HexagonHazardRecognizer.cpp - Hexagon Post RA Hazard Recognizer ---===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file defines the hazard recognizer for scheduling on Hexagon.
100b57cec5SDimitry Andric // Use a DFA based hazard recognizer.
110b57cec5SDimitry Andric //
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric 
140b57cec5SDimitry Andric #include "HexagonHazardRecognizer.h"
150b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunction.h"
160b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstr.h"
170b57cec5SDimitry Andric #include "llvm/CodeGen/MachineOperand.h"
180b57cec5SDimitry Andric #include "llvm/CodeGen/ScheduleDAG.h"
190b57cec5SDimitry Andric #include "llvm/Support/Debug.h"
200b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
210b57cec5SDimitry Andric #include <cassert>
220b57cec5SDimitry Andric 
230b57cec5SDimitry Andric using namespace llvm;
240b57cec5SDimitry Andric 
250b57cec5SDimitry Andric #define DEBUG_TYPE "post-RA-sched"
260b57cec5SDimitry Andric 
Reset()270b57cec5SDimitry Andric void HexagonHazardRecognizer::Reset() {
280b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "Reset hazard recognizer\n");
290b57cec5SDimitry Andric   Resources->clearResources();
300b57cec5SDimitry Andric   PacketNum = 0;
310b57cec5SDimitry Andric   UsesDotCur = nullptr;
320b57cec5SDimitry Andric   DotCurPNum = -1;
330b57cec5SDimitry Andric   UsesLoad = false;
340b57cec5SDimitry Andric   PrefVectorStoreNew = nullptr;
350b57cec5SDimitry Andric   RegDefs.clear();
360b57cec5SDimitry Andric }
370b57cec5SDimitry Andric 
380b57cec5SDimitry Andric ScheduleHazardRecognizer::HazardType
getHazardType(SUnit * SU,int stalls)390b57cec5SDimitry Andric HexagonHazardRecognizer::getHazardType(SUnit *SU, int stalls) {
400b57cec5SDimitry Andric   MachineInstr *MI = SU->getInstr();
410b57cec5SDimitry Andric   if (!MI || TII->isZeroCost(MI->getOpcode()))
420b57cec5SDimitry Andric     return NoHazard;
430b57cec5SDimitry Andric 
440b57cec5SDimitry Andric   if (!Resources->canReserveResources(*MI)) {
450b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "*** Hazard in cycle " << PacketNum << ", " << *MI);
460b57cec5SDimitry Andric     HazardType RetVal = Hazard;
4704eeddc0SDimitry Andric     if (isNewStore(*MI)) {
480b57cec5SDimitry Andric       // The .new store version uses different resources so check if it
490b57cec5SDimitry Andric       // causes a hazard.
500b57cec5SDimitry Andric       MachineFunction *MF = MI->getParent()->getParent();
510b57cec5SDimitry Andric       MachineInstr *NewMI =
520b57cec5SDimitry Andric         MF->CreateMachineInstr(TII->get(TII->getDotNewOp(*MI)),
530b57cec5SDimitry Andric                                MI->getDebugLoc());
540b57cec5SDimitry Andric       if (Resources->canReserveResources(*NewMI))
550b57cec5SDimitry Andric         RetVal = NoHazard;
560b57cec5SDimitry Andric       LLVM_DEBUG(dbgs() << "*** Try .new version? " << (RetVal == NoHazard)
570b57cec5SDimitry Andric                         << "\n");
580eae32dcSDimitry Andric       MF->deleteMachineInstr(NewMI);
590b57cec5SDimitry Andric     }
600b57cec5SDimitry Andric     return RetVal;
610b57cec5SDimitry Andric   }
620b57cec5SDimitry Andric 
630b57cec5SDimitry Andric   if (SU == UsesDotCur && DotCurPNum != (int)PacketNum) {
640b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "*** .cur Hazard in cycle " << PacketNum << ", "
650b57cec5SDimitry Andric                       << *MI);
660b57cec5SDimitry Andric     return Hazard;
670b57cec5SDimitry Andric   }
680b57cec5SDimitry Andric 
690b57cec5SDimitry Andric   return NoHazard;
700b57cec5SDimitry Andric }
710b57cec5SDimitry Andric 
AdvanceCycle()720b57cec5SDimitry Andric void HexagonHazardRecognizer::AdvanceCycle() {
730b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "Advance cycle, clear state\n");
740b57cec5SDimitry Andric   Resources->clearResources();
750b57cec5SDimitry Andric   if (DotCurPNum != -1 && DotCurPNum != (int)PacketNum) {
760b57cec5SDimitry Andric     UsesDotCur = nullptr;
770b57cec5SDimitry Andric     DotCurPNum = -1;
780b57cec5SDimitry Andric   }
790b57cec5SDimitry Andric   UsesLoad = false;
800b57cec5SDimitry Andric   PrefVectorStoreNew = nullptr;
810b57cec5SDimitry Andric   PacketNum++;
820b57cec5SDimitry Andric   RegDefs.clear();
830b57cec5SDimitry Andric }
840b57cec5SDimitry Andric 
850b57cec5SDimitry Andric /// Handle the cases when we prefer one instruction over another. Case 1 - we
860b57cec5SDimitry Andric /// prefer not to generate multiple loads in the packet to avoid a potential
870b57cec5SDimitry Andric /// bank conflict. Case 2 - if a packet contains a dot cur instruction, then we
880b57cec5SDimitry Andric /// prefer the instruction that can use the dot cur result. However, if the use
890b57cec5SDimitry Andric /// is not scheduled in the same packet, then prefer other instructions in the
900b57cec5SDimitry Andric /// subsequent packet. Case 3 - we prefer a vector store that can be converted
910b57cec5SDimitry Andric /// to a .new store. The packetizer will not generate the .new store if the
920b57cec5SDimitry Andric /// store doesn't have resources to fit in the packet (but the .new store may
930b57cec5SDimitry Andric /// have resources). We attempt to schedule the store as soon as possible to
940b57cec5SDimitry Andric /// help packetize the two instructions together.
ShouldPreferAnother(SUnit * SU)950b57cec5SDimitry Andric bool HexagonHazardRecognizer::ShouldPreferAnother(SUnit *SU) {
960b57cec5SDimitry Andric   if (PrefVectorStoreNew != nullptr && PrefVectorStoreNew != SU)
970b57cec5SDimitry Andric     return true;
980b57cec5SDimitry Andric   if (UsesLoad && SU->isInstr() && SU->getInstr()->mayLoad())
990b57cec5SDimitry Andric     return true;
1000b57cec5SDimitry Andric   return UsesDotCur && ((SU == UsesDotCur) ^ (DotCurPNum == (int)PacketNum));
1010b57cec5SDimitry Andric }
1020b57cec5SDimitry Andric 
10304eeddc0SDimitry Andric /// Return true if the instruction would be converted to a new value store when
10404eeddc0SDimitry Andric /// packetized.
isNewStore(MachineInstr & MI)10504eeddc0SDimitry Andric bool HexagonHazardRecognizer::isNewStore(MachineInstr &MI) {
10604eeddc0SDimitry Andric   if (!TII->mayBeNewStore(MI))
10704eeddc0SDimitry Andric     return false;
10804eeddc0SDimitry Andric   MachineOperand &MO = MI.getOperand(MI.getNumOperands() - 1);
109*81ad6265SDimitry Andric   return MO.isReg() && RegDefs.contains(MO.getReg());
11004eeddc0SDimitry Andric }
11104eeddc0SDimitry Andric 
EmitInstruction(SUnit * SU)1120b57cec5SDimitry Andric void HexagonHazardRecognizer::EmitInstruction(SUnit *SU) {
1130b57cec5SDimitry Andric   MachineInstr *MI = SU->getInstr();
1140b57cec5SDimitry Andric   if (!MI)
1150b57cec5SDimitry Andric     return;
1160b57cec5SDimitry Andric 
1170b57cec5SDimitry Andric   // Keep the set of definitions for each packet, which is used to determine
1180b57cec5SDimitry Andric   // if a .new can be used.
1190b57cec5SDimitry Andric   for (const MachineOperand &MO : MI->operands())
1200b57cec5SDimitry Andric     if (MO.isReg() && MO.isDef() && !MO.isImplicit())
1210b57cec5SDimitry Andric       RegDefs.insert(MO.getReg());
1220b57cec5SDimitry Andric 
1230b57cec5SDimitry Andric   if (TII->isZeroCost(MI->getOpcode()))
1240b57cec5SDimitry Andric     return;
1250b57cec5SDimitry Andric 
12604eeddc0SDimitry Andric   if (!Resources->canReserveResources(*MI) || isNewStore(*MI)) {
1270b57cec5SDimitry Andric     // It must be a .new store since other instructions must be able to be
1280b57cec5SDimitry Andric     // reserved at this point.
1290b57cec5SDimitry Andric     assert(TII->mayBeNewStore(*MI) && "Expecting .new store");
1300b57cec5SDimitry Andric     MachineFunction *MF = MI->getParent()->getParent();
1310b57cec5SDimitry Andric     MachineInstr *NewMI =
1320b57cec5SDimitry Andric         MF->CreateMachineInstr(TII->get(TII->getDotNewOp(*MI)),
1330b57cec5SDimitry Andric                                MI->getDebugLoc());
13404eeddc0SDimitry Andric     if (Resources->canReserveResources(*NewMI))
1350b57cec5SDimitry Andric       Resources->reserveResources(*NewMI);
1360b57cec5SDimitry Andric     else
1370b57cec5SDimitry Andric       Resources->reserveResources(*MI);
13804eeddc0SDimitry Andric     MF->deleteMachineInstr(NewMI);
13904eeddc0SDimitry Andric   } else
14004eeddc0SDimitry Andric     Resources->reserveResources(*MI);
1410b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << " Add instruction " << *MI);
1420b57cec5SDimitry Andric 
1430b57cec5SDimitry Andric   // When scheduling a dot cur instruction, check if there is an instruction
1440b57cec5SDimitry Andric   // that can use the dot cur in the same packet. If so, we'll attempt to
1450b57cec5SDimitry Andric   // schedule it before other instructions. We only do this if the load has a
1460b57cec5SDimitry Andric   // single zero-latency use.
1470b57cec5SDimitry Andric   if (TII->mayBeCurLoad(*MI))
1480b57cec5SDimitry Andric     for (auto &S : SU->Succs)
1490b57cec5SDimitry Andric       if (S.isAssignedRegDep() && S.getLatency() == 0 &&
1500b57cec5SDimitry Andric           S.getSUnit()->NumPredsLeft == 1) {
1510b57cec5SDimitry Andric         UsesDotCur = S.getSUnit();
1520b57cec5SDimitry Andric         DotCurPNum = PacketNum;
1530b57cec5SDimitry Andric         break;
1540b57cec5SDimitry Andric       }
1550b57cec5SDimitry Andric   if (SU == UsesDotCur) {
1560b57cec5SDimitry Andric     UsesDotCur = nullptr;
1570b57cec5SDimitry Andric     DotCurPNum = -1;
1580b57cec5SDimitry Andric   }
1590b57cec5SDimitry Andric 
1600b57cec5SDimitry Andric   UsesLoad = MI->mayLoad();
1610b57cec5SDimitry Andric 
1620b57cec5SDimitry Andric   if (TII->isHVXVec(*MI) && !MI->mayLoad() && !MI->mayStore())
1630b57cec5SDimitry Andric     for (auto &S : SU->Succs)
1640b57cec5SDimitry Andric       if (S.isAssignedRegDep() && S.getLatency() == 0 &&
1650b57cec5SDimitry Andric           TII->mayBeNewStore(*S.getSUnit()->getInstr()) &&
1660b57cec5SDimitry Andric           Resources->canReserveResources(*S.getSUnit()->getInstr())) {
1670b57cec5SDimitry Andric         PrefVectorStoreNew = S.getSUnit();
1680b57cec5SDimitry Andric         break;
1690b57cec5SDimitry Andric       }
1700b57cec5SDimitry Andric }
171