]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/lib/MCA/Stages/DispatchStage.cpp
MFC r345703:
[FreeBSD/FreeBSD.git] / contrib / llvm / lib / MCA / Stages / DispatchStage.cpp
1 //===--------------------- DispatchStage.cpp --------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 /// \file
10 ///
11 /// This file models the dispatch component of an instruction pipeline.
12 ///
13 /// The DispatchStage is responsible for updating instruction dependencies
14 /// and communicating to the simulated instruction scheduler that an instruction
15 /// is ready to be scheduled for execution.
16 ///
17 //===----------------------------------------------------------------------===//
18
19 #include "llvm/MCA/Stages/DispatchStage.h"
20 #include "llvm/MCA/HWEventListener.h"
21 #include "llvm/MCA/HardwareUnits/Scheduler.h"
22 #include "llvm/Support/Debug.h"
23
24 #define DEBUG_TYPE "llvm-mca"
25
26 namespace llvm {
27 namespace mca {
28
29 void DispatchStage::notifyInstructionDispatched(const InstRef &IR,
30                                                 ArrayRef<unsigned> UsedRegs,
31                                                 unsigned UOps) const {
32   LLVM_DEBUG(dbgs() << "[E] Instruction Dispatched: #" << IR << '\n');
33   notifyEvent<HWInstructionEvent>(
34       HWInstructionDispatchedEvent(IR, UsedRegs, UOps));
35 }
36
37 bool DispatchStage::checkPRF(const InstRef &IR) const {
38   SmallVector<unsigned, 4> RegDefs;
39   for (const WriteState &RegDef : IR.getInstruction()->getDefs())
40     RegDefs.emplace_back(RegDef.getRegisterID());
41
42   const unsigned RegisterMask = PRF.isAvailable(RegDefs);
43   // A mask with all zeroes means: register files are available.
44   if (RegisterMask) {
45     notifyEvent<HWStallEvent>(
46         HWStallEvent(HWStallEvent::RegisterFileStall, IR));
47     return false;
48   }
49
50   return true;
51 }
52
53 bool DispatchStage::checkRCU(const InstRef &IR) const {
54   const unsigned NumMicroOps = IR.getInstruction()->getDesc().NumMicroOps;
55   if (RCU.isAvailable(NumMicroOps))
56     return true;
57   notifyEvent<HWStallEvent>(
58       HWStallEvent(HWStallEvent::RetireControlUnitStall, IR));
59   return false;
60 }
61
62 bool DispatchStage::canDispatch(const InstRef &IR) const {
63   return checkRCU(IR) && checkPRF(IR) && checkNextStage(IR);
64 }
65
66 void DispatchStage::updateRAWDependencies(ReadState &RS,
67                                           const MCSubtargetInfo &STI) {
68   SmallVector<WriteRef, 4> DependentWrites;
69
70   // Collect all the dependent writes, and update RS internal state.
71   PRF.addRegisterRead(RS, DependentWrites);
72
73   // We know that this read depends on all the writes in DependentWrites.
74   // For each write, check if we have ReadAdvance information, and use it
75   // to figure out in how many cycles this read becomes available.
76   const ReadDescriptor &RD = RS.getDescriptor();
77   const MCSchedModel &SM = STI.getSchedModel();
78   const MCSchedClassDesc *SC = SM.getSchedClassDesc(RD.SchedClassID);
79   for (WriteRef &WR : DependentWrites) {
80     WriteState &WS = *WR.getWriteState();
81     unsigned WriteResID = WS.getWriteResourceID();
82     int ReadAdvance = STI.getReadAdvanceCycles(SC, RD.UseIndex, WriteResID);
83     WS.addUser(&RS, ReadAdvance);
84   }
85 }
86
87 Error DispatchStage::dispatch(InstRef IR) {
88   assert(!CarryOver && "Cannot dispatch another instruction!");
89   Instruction &IS = *IR.getInstruction();
90   const InstrDesc &Desc = IS.getDesc();
91   const unsigned NumMicroOps = Desc.NumMicroOps;
92   if (NumMicroOps > DispatchWidth) {
93     assert(AvailableEntries == DispatchWidth);
94     AvailableEntries = 0;
95     CarryOver = NumMicroOps - DispatchWidth;
96     CarriedOver = IR;
97   } else {
98     assert(AvailableEntries >= NumMicroOps);
99     AvailableEntries -= NumMicroOps;
100   }
101
102   // Check if this instructions ends the dispatch group.
103   if (Desc.EndGroup)
104     AvailableEntries = 0;
105
106   // Check if this is an optimizable reg-reg move.
107   bool IsEliminated = false;
108   if (IS.isOptimizableMove()) {
109     assert(IS.getDefs().size() == 1 && "Expected a single input!");
110     assert(IS.getUses().size() == 1 && "Expected a single output!");
111     IsEliminated = PRF.tryEliminateMove(IS.getDefs()[0], IS.getUses()[0]);
112   }
113
114   // A dependency-breaking instruction doesn't have to wait on the register
115   // input operands, and it is often optimized at register renaming stage.
116   // Update RAW dependencies if this instruction is not a dependency-breaking
117   // instruction. A dependency-breaking instruction is a zero-latency
118   // instruction that doesn't consume hardware resources.
119   // An example of dependency-breaking instruction on X86 is a zero-idiom XOR.
120   //
121   // We also don't update data dependencies for instructions that have been
122   // eliminated at register renaming stage.
123   if (!IsEliminated) {
124     for (ReadState &RS : IS.getUses())
125       updateRAWDependencies(RS, STI);
126   }
127
128   // By default, a dependency-breaking zero-idiom is expected to be optimized
129   // at register renaming stage. That means, no physical register is allocated
130   // to the instruction.
131   SmallVector<unsigned, 4> RegisterFiles(PRF.getNumRegisterFiles());
132   for (WriteState &WS : IS.getDefs())
133     PRF.addRegisterWrite(WriteRef(IR.getSourceIndex(), &WS), RegisterFiles);
134
135   // Reserve slots in the RCU, and notify the instruction that it has been
136   // dispatched to the schedulers for execution.
137   IS.dispatch(RCU.reserveSlot(IR, NumMicroOps));
138
139   // Notify listeners of the "instruction dispatched" event,
140   // and move IR to the next stage.
141   notifyInstructionDispatched(IR, RegisterFiles,
142                               std::min(DispatchWidth, NumMicroOps));
143   return moveToTheNextStage(IR);
144 }
145
146 Error DispatchStage::cycleStart() {
147   PRF.cycleStart();
148
149   if (!CarryOver) {
150     AvailableEntries = DispatchWidth;
151     return ErrorSuccess();
152   }
153
154   AvailableEntries = CarryOver >= DispatchWidth ? 0 : DispatchWidth - CarryOver;
155   unsigned DispatchedOpcodes = DispatchWidth - AvailableEntries;
156   CarryOver -= DispatchedOpcodes;
157   assert(CarriedOver && "Invalid dispatched instruction");
158
159   SmallVector<unsigned, 8> RegisterFiles(PRF.getNumRegisterFiles(), 0U);
160   notifyInstructionDispatched(CarriedOver, RegisterFiles, DispatchedOpcodes);
161   if (!CarryOver)
162     CarriedOver = InstRef();
163   return ErrorSuccess();
164 }
165
166 bool DispatchStage::isAvailable(const InstRef &IR) const {
167   const InstrDesc &Desc = IR.getInstruction()->getDesc();
168   unsigned Required = std::min(Desc.NumMicroOps, DispatchWidth);
169   if (Required > AvailableEntries)
170     return false;
171
172   if (Desc.BeginGroup && AvailableEntries != DispatchWidth)
173     return false;
174
175   // The dispatch logic doesn't internally buffer instructions.  It only accepts
176   // instructions that can be successfully moved to the next stage during this
177   // same cycle.
178   return canDispatch(IR);
179 }
180
181 Error DispatchStage::execute(InstRef &IR) {
182   assert(canDispatch(IR) && "Cannot dispatch another instruction!");
183   return dispatch(IR);
184 }
185
186 #ifndef NDEBUG
187 void DispatchStage::dump() const {
188   PRF.dump();
189   RCU.dump();
190 }
191 #endif
192 } // namespace mca
193 } // namespace llvm