xref: /freebsd/contrib/llvm-project/llvm/lib/Target/AMDGPU/GCNHazardRecognizer.h (revision 81ad626541db97eb356e2c1d4a20eb2a26a766ab)
10b57cec5SDimitry Andric //===-- GCNHazardRecognizers.h - GCN Hazard Recognizers ---------*- C++ -*-===//
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 hazard recognizers for scheduling on GCN processors.
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric 
130b57cec5SDimitry Andric #ifndef LLVM_LIB_TARGET_AMDGPUHAZARDRECOGNIZERS_H
140b57cec5SDimitry Andric #define LLVM_LIB_TARGET_AMDGPUHAZARDRECOGNIZERS_H
150b57cec5SDimitry Andric 
160b57cec5SDimitry Andric #include "llvm/ADT/BitVector.h"
170b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h"
180b57cec5SDimitry Andric #include "llvm/CodeGen/ScheduleHazardRecognizer.h"
190b57cec5SDimitry Andric #include "llvm/CodeGen/TargetSchedule.h"
200b57cec5SDimitry Andric #include <list>
210b57cec5SDimitry Andric 
220b57cec5SDimitry Andric namespace llvm {
230b57cec5SDimitry Andric 
240b57cec5SDimitry Andric class MachineFunction;
250b57cec5SDimitry Andric class MachineInstr;
260b57cec5SDimitry Andric class MachineOperand;
270b57cec5SDimitry Andric class MachineRegisterInfo;
280b57cec5SDimitry Andric class SIInstrInfo;
290b57cec5SDimitry Andric class SIRegisterInfo;
300b57cec5SDimitry Andric class GCNSubtarget;
310b57cec5SDimitry Andric 
320b57cec5SDimitry Andric class GCNHazardRecognizer final : public ScheduleHazardRecognizer {
330b57cec5SDimitry Andric public:
34fe6060f1SDimitry Andric   typedef function_ref<bool(const MachineInstr &)> IsHazardFn;
350b57cec5SDimitry Andric 
360b57cec5SDimitry Andric private:
370b57cec5SDimitry Andric   // Distinguish if we are called from scheduler or hazard recognizer
380b57cec5SDimitry Andric   bool IsHazardRecognizerMode;
390b57cec5SDimitry Andric 
400b57cec5SDimitry Andric   // This variable stores the instruction that has been emitted this cycle. It
410b57cec5SDimitry Andric   // will be added to EmittedInstrs, when AdvanceCycle() or RecedeCycle() is
420b57cec5SDimitry Andric   // called.
430b57cec5SDimitry Andric   MachineInstr *CurrCycleInstr;
440b57cec5SDimitry Andric   std::list<MachineInstr*> EmittedInstrs;
450b57cec5SDimitry Andric   const MachineFunction &MF;
460b57cec5SDimitry Andric   const GCNSubtarget &ST;
470b57cec5SDimitry Andric   const SIInstrInfo &TII;
480b57cec5SDimitry Andric   const SIRegisterInfo &TRI;
490b57cec5SDimitry Andric   TargetSchedModel TSchedModel;
50fe6060f1SDimitry Andric   bool RunLdsBranchVmemWARHazardFixup;
510b57cec5SDimitry Andric 
520b57cec5SDimitry Andric   /// RegUnits of uses in the current soft memory clause.
530b57cec5SDimitry Andric   BitVector ClauseUses;
540b57cec5SDimitry Andric 
550b57cec5SDimitry Andric   /// RegUnits of defs in the current soft memory clause.
560b57cec5SDimitry Andric   BitVector ClauseDefs;
570b57cec5SDimitry Andric 
580b57cec5SDimitry Andric   void resetClause() {
590b57cec5SDimitry Andric     ClauseUses.reset();
600b57cec5SDimitry Andric     ClauseDefs.reset();
610b57cec5SDimitry Andric   }
620b57cec5SDimitry Andric 
630b57cec5SDimitry Andric   void addClauseInst(const MachineInstr &MI);
640b57cec5SDimitry Andric 
65*81ad6265SDimitry Andric   /// \returns the number of wait states before another MFMA instruction can be
66*81ad6265SDimitry Andric   /// issued after \p MI.
67*81ad6265SDimitry Andric   unsigned getMFMAPipelineWaitStates(const MachineInstr &MI) const;
68*81ad6265SDimitry Andric 
690b57cec5SDimitry Andric   // Advance over a MachineInstr bundle. Look for hazards in the bundled
700b57cec5SDimitry Andric   // instructions.
710b57cec5SDimitry Andric   void processBundle();
720b57cec5SDimitry Andric 
730b57cec5SDimitry Andric   int getWaitStatesSince(IsHazardFn IsHazard, int Limit);
740b57cec5SDimitry Andric   int getWaitStatesSinceDef(unsigned Reg, IsHazardFn IsHazardDef, int Limit);
750b57cec5SDimitry Andric   int getWaitStatesSinceSetReg(IsHazardFn IsHazard, int Limit);
760b57cec5SDimitry Andric 
770b57cec5SDimitry Andric   int checkSoftClauseHazards(MachineInstr *SMEM);
780b57cec5SDimitry Andric   int checkSMRDHazards(MachineInstr *SMRD);
790b57cec5SDimitry Andric   int checkVMEMHazards(MachineInstr* VMEM);
800b57cec5SDimitry Andric   int checkDPPHazards(MachineInstr *DPP);
810b57cec5SDimitry Andric   int checkDivFMasHazards(MachineInstr *DivFMas);
820b57cec5SDimitry Andric   int checkGetRegHazards(MachineInstr *GetRegInstr);
830b57cec5SDimitry Andric   int checkSetRegHazards(MachineInstr *SetRegInstr);
840b57cec5SDimitry Andric   int createsVALUHazard(const MachineInstr &MI);
850b57cec5SDimitry Andric   int checkVALUHazards(MachineInstr *VALU);
860b57cec5SDimitry Andric   int checkVALUHazardsHelper(const MachineOperand &Def, const MachineRegisterInfo &MRI);
870b57cec5SDimitry Andric   int checkRWLaneHazards(MachineInstr *RWLane);
880b57cec5SDimitry Andric   int checkRFEHazards(MachineInstr *RFE);
890b57cec5SDimitry Andric   int checkInlineAsmHazards(MachineInstr *IA);
900b57cec5SDimitry Andric   int checkReadM0Hazards(MachineInstr *SMovRel);
910b57cec5SDimitry Andric   int checkNSAtoVMEMHazard(MachineInstr *MI);
920b57cec5SDimitry Andric   int checkFPAtomicToDenormModeHazard(MachineInstr *MI);
930b57cec5SDimitry Andric   void fixHazards(MachineInstr *MI);
940b57cec5SDimitry Andric   bool fixVcmpxPermlaneHazards(MachineInstr *MI);
950b57cec5SDimitry Andric   bool fixVMEMtoScalarWriteHazards(MachineInstr *MI);
960b57cec5SDimitry Andric   bool fixSMEMtoVectorWriteHazards(MachineInstr *MI);
970b57cec5SDimitry Andric   bool fixVcmpxExecWARHazard(MachineInstr *MI);
980b57cec5SDimitry Andric   bool fixLdsBranchVmemWARHazard(MachineInstr *MI);
99*81ad6265SDimitry Andric   bool fixLdsDirectVALUHazard(MachineInstr *MI);
100*81ad6265SDimitry Andric   bool fixLdsDirectVMEMHazard(MachineInstr *MI);
101*81ad6265SDimitry Andric   bool fixVALUPartialForwardingHazard(MachineInstr *MI);
102*81ad6265SDimitry Andric   bool fixVALUTransUseHazard(MachineInstr *MI);
103*81ad6265SDimitry Andric   bool fixWMMAHazards(MachineInstr *MI);
1040b57cec5SDimitry Andric 
1050b57cec5SDimitry Andric   int checkMAIHazards(MachineInstr *MI);
106fe6060f1SDimitry Andric   int checkMAIHazards908(MachineInstr *MI);
107fe6060f1SDimitry Andric   int checkMAIHazards90A(MachineInstr *MI);
108*81ad6265SDimitry Andric   /// Pad the latency between neighboring MFMA instructions with s_nops. The
109*81ad6265SDimitry Andric   /// percentage of wait states to fill with s_nops is specified by the command
110*81ad6265SDimitry Andric   /// line option '-amdgpu-mfma-padding-ratio'.
111*81ad6265SDimitry Andric   ///
112*81ad6265SDimitry Andric   /// For example, with '-amdgpu-mfma-padding-ratio=100':
113*81ad6265SDimitry Andric   ///
114*81ad6265SDimitry Andric   /// 2 pass MFMA instructions have a latency of 2 wait states. Therefore, a
115*81ad6265SDimitry Andric   /// 'S_NOP 1' will be added between sequential MFMA instructions.
116*81ad6265SDimitry Andric   ///
117*81ad6265SDimitry Andric   /// V_MFMA_F32_4X4X1F32
118*81ad6265SDimitry Andric   /// V_MFMA_F32_4X4X1F32
119*81ad6265SDimitry Andric   ///-->
120*81ad6265SDimitry Andric   /// V_MFMA_F32_4X4X1F32
121*81ad6265SDimitry Andric   /// S_NOP 1
122*81ad6265SDimitry Andric   /// V_MFMA_F32_4X4X1F32
123*81ad6265SDimitry Andric   int checkMFMAPadding(MachineInstr *MI);
124fe6060f1SDimitry Andric   int checkMAIVALUHazards(MachineInstr *MI);
1250b57cec5SDimitry Andric   int checkMAILdStHazards(MachineInstr *MI);
1260b57cec5SDimitry Andric 
1270b57cec5SDimitry Andric public:
1280b57cec5SDimitry Andric   GCNHazardRecognizer(const MachineFunction &MF);
1290b57cec5SDimitry Andric   // We can only issue one instruction per cycle.
1300b57cec5SDimitry Andric   bool atIssueLimit() const override { return true; }
1310b57cec5SDimitry Andric   void EmitInstruction(SUnit *SU) override;
1320b57cec5SDimitry Andric   void EmitInstruction(MachineInstr *MI) override;
1330b57cec5SDimitry Andric   HazardType getHazardType(SUnit *SU, int Stalls) override;
1340b57cec5SDimitry Andric   void EmitNoop() override;
1350b57cec5SDimitry Andric   unsigned PreEmitNoops(MachineInstr *) override;
1360b57cec5SDimitry Andric   unsigned PreEmitNoopsCommon(MachineInstr *);
1370b57cec5SDimitry Andric   void AdvanceCycle() override;
1380b57cec5SDimitry Andric   void RecedeCycle() override;
139e8d8bef9SDimitry Andric   bool ShouldPreferAnother(SUnit *SU) override;
140e8d8bef9SDimitry Andric   void Reset() override;
1410b57cec5SDimitry Andric };
1420b57cec5SDimitry Andric 
1430b57cec5SDimitry Andric } // end namespace llvm
1440b57cec5SDimitry Andric 
1450b57cec5SDimitry Andric #endif //LLVM_LIB_TARGET_AMDGPUHAZARDRECOGNIZERS_H
146