xref: /freebsd-src/contrib/llvm-project/llvm/lib/MCA/Instruction.cpp (revision 81ad626541db97eb356e2c1d4a20eb2a26a766ab)
10b57cec5SDimitry Andric //===--------------------- Instruction.cpp ----------------------*- 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 abstractions used by the Pipeline to model register reads,
100b57cec5SDimitry Andric // register writes and instructions.
110b57cec5SDimitry Andric //
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric 
140b57cec5SDimitry Andric #include "llvm/MCA/Instruction.h"
150b57cec5SDimitry Andric #include "llvm/Support/Debug.h"
160b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
170b57cec5SDimitry Andric 
180b57cec5SDimitry Andric namespace llvm {
190b57cec5SDimitry Andric namespace mca {
200b57cec5SDimitry Andric 
writeStartEvent(unsigned IID,MCPhysReg RegID,unsigned Cycles)218bcb0991SDimitry Andric void WriteState::writeStartEvent(unsigned IID, MCPhysReg RegID,
220b57cec5SDimitry Andric                                  unsigned Cycles) {
230b57cec5SDimitry Andric   CRD.IID = IID;
240b57cec5SDimitry Andric   CRD.RegID = RegID;
250b57cec5SDimitry Andric   CRD.Cycles = Cycles;
260b57cec5SDimitry Andric   DependentWriteCyclesLeft = Cycles;
270b57cec5SDimitry Andric   DependentWrite = nullptr;
280b57cec5SDimitry Andric }
290b57cec5SDimitry Andric 
writeStartEvent(unsigned IID,MCPhysReg RegID,unsigned Cycles)30fe6060f1SDimitry Andric void ReadState::writeStartEvent(unsigned IID, MCPhysReg RegID,
31fe6060f1SDimitry Andric                                 unsigned Cycles) {
320b57cec5SDimitry Andric   assert(DependentWrites);
330b57cec5SDimitry Andric   assert(CyclesLeft == UNKNOWN_CYCLES);
340b57cec5SDimitry Andric 
350b57cec5SDimitry Andric   // This read may be dependent on more than one write. This typically occurs
360b57cec5SDimitry Andric   // when a definition is the result of multiple writes where at least one
370b57cec5SDimitry Andric   // write does a partial register update.
380b57cec5SDimitry Andric   // The HW is forced to do some extra bookkeeping to track of all the
390b57cec5SDimitry Andric   // dependent writes, and implement a merging scheme for the partial writes.
400b57cec5SDimitry Andric   --DependentWrites;
410b57cec5SDimitry Andric   if (TotalCycles < Cycles) {
420b57cec5SDimitry Andric     CRD.IID = IID;
430b57cec5SDimitry Andric     CRD.RegID = RegID;
440b57cec5SDimitry Andric     CRD.Cycles = Cycles;
450b57cec5SDimitry Andric     TotalCycles = Cycles;
460b57cec5SDimitry Andric   }
470b57cec5SDimitry Andric 
480b57cec5SDimitry Andric   if (!DependentWrites) {
490b57cec5SDimitry Andric     CyclesLeft = TotalCycles;
500b57cec5SDimitry Andric     IsReady = !CyclesLeft;
510b57cec5SDimitry Andric   }
520b57cec5SDimitry Andric }
530b57cec5SDimitry Andric 
onInstructionIssued(unsigned IID)540b57cec5SDimitry Andric void WriteState::onInstructionIssued(unsigned IID) {
550b57cec5SDimitry Andric   assert(CyclesLeft == UNKNOWN_CYCLES);
560b57cec5SDimitry Andric   // Update the number of cycles left based on the WriteDescriptor info.
570b57cec5SDimitry Andric   CyclesLeft = getLatency();
580b57cec5SDimitry Andric 
590b57cec5SDimitry Andric   // Now that the time left before write-back is known, notify
600b57cec5SDimitry Andric   // all the users.
610b57cec5SDimitry Andric   for (const std::pair<ReadState *, int> &User : Users) {
620b57cec5SDimitry Andric     ReadState *RS = User.first;
630b57cec5SDimitry Andric     unsigned ReadCycles = std::max(0, CyclesLeft - User.second);
640b57cec5SDimitry Andric     RS->writeStartEvent(IID, RegisterID, ReadCycles);
650b57cec5SDimitry Andric   }
660b57cec5SDimitry Andric 
670b57cec5SDimitry Andric   // Notify any writes that are in a false dependency with this write.
680b57cec5SDimitry Andric   if (PartialWrite)
690b57cec5SDimitry Andric     PartialWrite->writeStartEvent(IID, RegisterID, CyclesLeft);
700b57cec5SDimitry Andric }
710b57cec5SDimitry Andric 
addUser(unsigned IID,ReadState * User,int ReadAdvance)720b57cec5SDimitry Andric void WriteState::addUser(unsigned IID, ReadState *User, int ReadAdvance) {
730b57cec5SDimitry Andric   // If CyclesLeft is different than -1, then we don't need to
740b57cec5SDimitry Andric   // update the list of users. We can just notify the user with
750b57cec5SDimitry Andric   // the actual number of cycles left (which may be zero).
760b57cec5SDimitry Andric   if (CyclesLeft != UNKNOWN_CYCLES) {
770b57cec5SDimitry Andric     unsigned ReadCycles = std::max(0, CyclesLeft - ReadAdvance);
780b57cec5SDimitry Andric     User->writeStartEvent(IID, RegisterID, ReadCycles);
790b57cec5SDimitry Andric     return;
800b57cec5SDimitry Andric   }
810b57cec5SDimitry Andric 
820b57cec5SDimitry Andric   Users.emplace_back(User, ReadAdvance);
830b57cec5SDimitry Andric }
840b57cec5SDimitry Andric 
addUser(unsigned IID,WriteState * User)850b57cec5SDimitry Andric void WriteState::addUser(unsigned IID, WriteState *User) {
860b57cec5SDimitry Andric   if (CyclesLeft != UNKNOWN_CYCLES) {
870b57cec5SDimitry Andric     User->writeStartEvent(IID, RegisterID, std::max(0, CyclesLeft));
880b57cec5SDimitry Andric     return;
890b57cec5SDimitry Andric   }
900b57cec5SDimitry Andric 
910b57cec5SDimitry Andric   assert(!PartialWrite && "PartialWrite already set!");
920b57cec5SDimitry Andric   PartialWrite = User;
930b57cec5SDimitry Andric   User->setDependentWrite(this);
940b57cec5SDimitry Andric }
950b57cec5SDimitry Andric 
cycleEvent()960b57cec5SDimitry Andric void WriteState::cycleEvent() {
970b57cec5SDimitry Andric   // Note: CyclesLeft can be a negative number. It is an error to
980b57cec5SDimitry Andric   // make it an unsigned quantity because users of this write may
990b57cec5SDimitry Andric   // specify a negative ReadAdvance.
1000b57cec5SDimitry Andric   if (CyclesLeft != UNKNOWN_CYCLES)
1010b57cec5SDimitry Andric     CyclesLeft--;
1020b57cec5SDimitry Andric 
1030b57cec5SDimitry Andric   if (DependentWriteCyclesLeft)
1040b57cec5SDimitry Andric     DependentWriteCyclesLeft--;
1050b57cec5SDimitry Andric }
1060b57cec5SDimitry Andric 
cycleEvent()1070b57cec5SDimitry Andric void ReadState::cycleEvent() {
1080b57cec5SDimitry Andric   // Update the total number of cycles.
1090b57cec5SDimitry Andric   if (DependentWrites && TotalCycles) {
1100b57cec5SDimitry Andric     --TotalCycles;
1110b57cec5SDimitry Andric     return;
1120b57cec5SDimitry Andric   }
1130b57cec5SDimitry Andric 
1140b57cec5SDimitry Andric   // Bail out immediately if we don't know how many cycles are left.
1150b57cec5SDimitry Andric   if (CyclesLeft == UNKNOWN_CYCLES)
1160b57cec5SDimitry Andric     return;
1170b57cec5SDimitry Andric 
1180b57cec5SDimitry Andric   if (CyclesLeft) {
1190b57cec5SDimitry Andric     --CyclesLeft;
1200b57cec5SDimitry Andric     IsReady = !CyclesLeft;
1210b57cec5SDimitry Andric   }
1220b57cec5SDimitry Andric }
1230b57cec5SDimitry Andric 
1240b57cec5SDimitry Andric #ifndef NDEBUG
dump() const1250b57cec5SDimitry Andric void WriteState::dump() const {
1260b57cec5SDimitry Andric   dbgs() << "{ OpIdx=" << WD->OpIndex << ", Lat=" << getLatency() << ", RegID "
1270b57cec5SDimitry Andric          << getRegisterID() << ", Cycles Left=" << getCyclesLeft() << " }";
1280b57cec5SDimitry Andric }
1290b57cec5SDimitry Andric #endif
1300b57cec5SDimitry Andric 
computeCriticalRegDep()1310b57cec5SDimitry Andric const CriticalDependency &Instruction::computeCriticalRegDep() {
1320b57cec5SDimitry Andric   if (CriticalRegDep.Cycles)
1330b57cec5SDimitry Andric     return CriticalRegDep;
1340b57cec5SDimitry Andric 
1350b57cec5SDimitry Andric   unsigned MaxLatency = 0;
1360b57cec5SDimitry Andric   for (const WriteState &WS : getDefs()) {
1370b57cec5SDimitry Andric     const CriticalDependency &WriteCRD = WS.getCriticalRegDep();
1380b57cec5SDimitry Andric     if (WriteCRD.Cycles > MaxLatency)
1390b57cec5SDimitry Andric       CriticalRegDep = WriteCRD;
1400b57cec5SDimitry Andric   }
1410b57cec5SDimitry Andric 
1420b57cec5SDimitry Andric   for (const ReadState &RS : getUses()) {
1430b57cec5SDimitry Andric     const CriticalDependency &ReadCRD = RS.getCriticalRegDep();
1440b57cec5SDimitry Andric     if (ReadCRD.Cycles > MaxLatency)
1450b57cec5SDimitry Andric       CriticalRegDep = ReadCRD;
1460b57cec5SDimitry Andric   }
1470b57cec5SDimitry Andric 
1480b57cec5SDimitry Andric   return CriticalRegDep;
1490b57cec5SDimitry Andric }
1500b57cec5SDimitry Andric 
reset()151*81ad6265SDimitry Andric void Instruction::reset() {
152*81ad6265SDimitry Andric   // Note that this won't clear read/write descriptors
153*81ad6265SDimitry Andric   // or other non-trivial fields
154*81ad6265SDimitry Andric   Stage = IS_INVALID;
155*81ad6265SDimitry Andric   CyclesLeft = UNKNOWN_CYCLES;
156*81ad6265SDimitry Andric   clearOptimizableMove();
157*81ad6265SDimitry Andric   RCUTokenID = 0;
158*81ad6265SDimitry Andric   LSUTokenID = 0;
159*81ad6265SDimitry Andric   CriticalResourceMask = 0;
160*81ad6265SDimitry Andric   IsEliminated = false;
161*81ad6265SDimitry Andric }
162*81ad6265SDimitry Andric 
dispatch(unsigned RCUToken)1630b57cec5SDimitry Andric void Instruction::dispatch(unsigned RCUToken) {
1640b57cec5SDimitry Andric   assert(Stage == IS_INVALID);
1650b57cec5SDimitry Andric   Stage = IS_DISPATCHED;
1660b57cec5SDimitry Andric   RCUTokenID = RCUToken;
1670b57cec5SDimitry Andric 
1680b57cec5SDimitry Andric   // Check if input operands are already available.
1690b57cec5SDimitry Andric   if (updateDispatched())
1700b57cec5SDimitry Andric     updatePending();
1710b57cec5SDimitry Andric }
1720b57cec5SDimitry Andric 
execute(unsigned IID)1730b57cec5SDimitry Andric void Instruction::execute(unsigned IID) {
1740b57cec5SDimitry Andric   assert(Stage == IS_READY);
1750b57cec5SDimitry Andric   Stage = IS_EXECUTING;
1760b57cec5SDimitry Andric 
1770b57cec5SDimitry Andric   // Set the cycles left before the write-back stage.
1780b57cec5SDimitry Andric   CyclesLeft = getLatency();
1790b57cec5SDimitry Andric 
1800b57cec5SDimitry Andric   for (WriteState &WS : getDefs())
1810b57cec5SDimitry Andric     WS.onInstructionIssued(IID);
1820b57cec5SDimitry Andric 
1830b57cec5SDimitry Andric   // Transition to the "executed" stage if this is a zero-latency instruction.
1840b57cec5SDimitry Andric   if (!CyclesLeft)
1850b57cec5SDimitry Andric     Stage = IS_EXECUTED;
1860b57cec5SDimitry Andric }
1870b57cec5SDimitry Andric 
forceExecuted()1880b57cec5SDimitry Andric void Instruction::forceExecuted() {
1890b57cec5SDimitry Andric   assert(Stage == IS_READY && "Invalid internal state!");
1900b57cec5SDimitry Andric   CyclesLeft = 0;
1910b57cec5SDimitry Andric   Stage = IS_EXECUTED;
1920b57cec5SDimitry Andric }
1930b57cec5SDimitry Andric 
updatePending()1940b57cec5SDimitry Andric bool Instruction::updatePending() {
1950b57cec5SDimitry Andric   assert(isPending() && "Unexpected instruction stage found!");
1960b57cec5SDimitry Andric 
1970b57cec5SDimitry Andric   if (!all_of(getUses(), [](const ReadState &Use) { return Use.isReady(); }))
1980b57cec5SDimitry Andric     return false;
1990b57cec5SDimitry Andric 
2000b57cec5SDimitry Andric   // A partial register write cannot complete before a dependent write.
2010b57cec5SDimitry Andric   if (!all_of(getDefs(), [](const WriteState &Def) { return Def.isReady(); }))
2020b57cec5SDimitry Andric     return false;
2030b57cec5SDimitry Andric 
2040b57cec5SDimitry Andric   Stage = IS_READY;
2050b57cec5SDimitry Andric   return true;
2060b57cec5SDimitry Andric }
2070b57cec5SDimitry Andric 
updateDispatched()2080b57cec5SDimitry Andric bool Instruction::updateDispatched() {
2090b57cec5SDimitry Andric   assert(isDispatched() && "Unexpected instruction stage found!");
2100b57cec5SDimitry Andric 
2110b57cec5SDimitry Andric   if (!all_of(getUses(), [](const ReadState &Use) {
2120b57cec5SDimitry Andric         return Use.isPending() || Use.isReady();
2130b57cec5SDimitry Andric       }))
2140b57cec5SDimitry Andric     return false;
2150b57cec5SDimitry Andric 
2160b57cec5SDimitry Andric   // A partial register write cannot complete before a dependent write.
2170b57cec5SDimitry Andric   if (!all_of(getDefs(),
2180b57cec5SDimitry Andric               [](const WriteState &Def) { return !Def.getDependentWrite(); }))
2190b57cec5SDimitry Andric     return false;
2200b57cec5SDimitry Andric 
2210b57cec5SDimitry Andric   Stage = IS_PENDING;
2220b57cec5SDimitry Andric   return true;
2230b57cec5SDimitry Andric }
2240b57cec5SDimitry Andric 
update()2250b57cec5SDimitry Andric void Instruction::update() {
2260b57cec5SDimitry Andric   if (isDispatched())
2270b57cec5SDimitry Andric     updateDispatched();
2280b57cec5SDimitry Andric   if (isPending())
2290b57cec5SDimitry Andric     updatePending();
2300b57cec5SDimitry Andric }
2310b57cec5SDimitry Andric 
cycleEvent()2320b57cec5SDimitry Andric void Instruction::cycleEvent() {
2330b57cec5SDimitry Andric   if (isReady())
2340b57cec5SDimitry Andric     return;
2350b57cec5SDimitry Andric 
2360b57cec5SDimitry Andric   if (isDispatched() || isPending()) {
2370b57cec5SDimitry Andric     for (ReadState &Use : getUses())
2380b57cec5SDimitry Andric       Use.cycleEvent();
2390b57cec5SDimitry Andric 
2400b57cec5SDimitry Andric     for (WriteState &Def : getDefs())
2410b57cec5SDimitry Andric       Def.cycleEvent();
2420b57cec5SDimitry Andric 
2430b57cec5SDimitry Andric     update();
2440b57cec5SDimitry Andric     return;
2450b57cec5SDimitry Andric   }
2460b57cec5SDimitry Andric 
2470b57cec5SDimitry Andric   assert(isExecuting() && "Instruction not in-flight?");
2480b57cec5SDimitry Andric   assert(CyclesLeft && "Instruction already executed?");
2490b57cec5SDimitry Andric   for (WriteState &Def : getDefs())
2500b57cec5SDimitry Andric     Def.cycleEvent();
2510b57cec5SDimitry Andric   CyclesLeft--;
2520b57cec5SDimitry Andric   if (!CyclesLeft)
2530b57cec5SDimitry Andric     Stage = IS_EXECUTED;
2540b57cec5SDimitry Andric }
2550b57cec5SDimitry Andric 
2560b57cec5SDimitry Andric } // namespace mca
2570b57cec5SDimitry Andric } // namespace llvm
258