1 //===--------------------- Instruction.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 // 10 // This file defines abstractions used by the Pipeline to model register reads, 11 // register writes and instructions. 12 // 13 //===----------------------------------------------------------------------===// 14 15 #include "Instruction.h" 16 #include "llvm/Support/Debug.h" 17 #include "llvm/Support/raw_ostream.h" 18 19 namespace mca { 20 21 using namespace llvm; 22 23 void ReadState::writeStartEvent(unsigned Cycles) { 24 assert(DependentWrites); 25 assert(CyclesLeft == UNKNOWN_CYCLES); 26 27 // This read may be dependent on more than one write. This typically occurs 28 // when a definition is the result of multiple writes where at least one 29 // write does a partial register update. 30 // The HW is forced to do some extra bookkeeping to track of all the 31 // dependent writes, and implement a merging scheme for the partial writes. 32 --DependentWrites; 33 TotalCycles = std::max(TotalCycles, Cycles); 34 35 if (!DependentWrites) { 36 CyclesLeft = TotalCycles; 37 IsReady = !CyclesLeft; 38 } 39 } 40 41 void WriteState::onInstructionIssued() { 42 assert(CyclesLeft == UNKNOWN_CYCLES); 43 // Update the number of cycles left based on the WriteDescriptor info. 44 CyclesLeft = getLatency(); 45 46 // Now that the time left before write-back is known, notify 47 // all the users. 48 for (const std::pair<ReadState *, int> &User : Users) { 49 ReadState *RS = User.first; 50 unsigned ReadCycles = std::max(0, CyclesLeft - User.second); 51 RS->writeStartEvent(ReadCycles); 52 } 53 } 54 55 void WriteState::addUser(ReadState *User, int ReadAdvance) { 56 // If CyclesLeft is different than -1, then we don't need to 57 // update the list of users. We can just notify the user with 58 // the actual number of cycles left (which may be zero). 59 if (CyclesLeft != UNKNOWN_CYCLES) { 60 unsigned ReadCycles = std::max(0, CyclesLeft - ReadAdvance); 61 User->writeStartEvent(ReadCycles); 62 return; 63 } 64 65 std::pair<ReadState *, int> NewPair(User, ReadAdvance); 66 Users.insert(NewPair); 67 } 68 69 void WriteState::cycleEvent() { 70 // Note: CyclesLeft can be a negative number. It is an error to 71 // make it an unsigned quantity because users of this write may 72 // specify a negative ReadAdvance. 73 if (CyclesLeft != UNKNOWN_CYCLES) 74 CyclesLeft--; 75 } 76 77 void ReadState::cycleEvent() { 78 // Update the total number of cycles. 79 if (DependentWrites && TotalCycles) { 80 --TotalCycles; 81 return; 82 } 83 84 // Bail out immediately if we don't know how many cycles are left. 85 if (CyclesLeft == UNKNOWN_CYCLES) 86 return; 87 88 if (CyclesLeft) { 89 --CyclesLeft; 90 IsReady = !CyclesLeft; 91 } 92 } 93 94 #ifndef NDEBUG 95 void WriteState::dump() const { 96 dbgs() << "{ OpIdx=" << WD.OpIndex << ", Lat=" << getLatency() << ", RegID " 97 << getRegisterID() << ", Cycles Left=" << getCyclesLeft() << " }"; 98 } 99 100 void WriteRef::dump() const { 101 dbgs() << "IID=" << getSourceIndex() << ' '; 102 if (isValid()) 103 getWriteState()->dump(); 104 else 105 dbgs() << "(null)"; 106 } 107 #endif 108 109 void Instruction::dispatch(unsigned RCUToken) { 110 assert(Stage == IS_INVALID); 111 Stage = IS_AVAILABLE; 112 RCUTokenID = RCUToken; 113 114 // Check if input operands are already available. 115 update(); 116 } 117 118 void Instruction::execute() { 119 assert(Stage == IS_READY); 120 Stage = IS_EXECUTING; 121 122 // Set the cycles left before the write-back stage. 123 CyclesLeft = Desc.MaxLatency; 124 125 for (UniqueDef &Def : Defs) 126 Def->onInstructionIssued(); 127 128 // Transition to the "executed" stage if this is a zero-latency instruction. 129 if (!CyclesLeft) 130 Stage = IS_EXECUTED; 131 } 132 133 void Instruction::update() { 134 assert(isDispatched() && "Unexpected instruction stage found!"); 135 136 if (!llvm::all_of(Uses, [](const UniqueUse &Use) { return Use->isReady(); })) 137 return; 138 139 // A partial register write cannot complete before a dependent write. 140 auto IsDefReady = [&](const UniqueDef &Def) { 141 if (const WriteState *Write = Def->getDependentWrite()) { 142 int WriteLatency = Write->getCyclesLeft(); 143 if (WriteLatency == UNKNOWN_CYCLES) 144 return false; 145 return static_cast<unsigned>(WriteLatency) < Desc.MaxLatency; 146 } 147 return true; 148 }; 149 150 if (llvm::all_of(Defs, IsDefReady)) 151 Stage = IS_READY; 152 } 153 154 void Instruction::cycleEvent() { 155 if (isReady()) 156 return; 157 158 if (isDispatched()) { 159 for (UniqueUse &Use : Uses) 160 Use->cycleEvent(); 161 162 update(); 163 return; 164 } 165 166 assert(isExecuting() && "Instruction not in-flight?"); 167 assert(CyclesLeft && "Instruction already executed?"); 168 for (UniqueDef &Def : Defs) 169 Def->cycleEvent(); 170 CyclesLeft--; 171 if (!CyclesLeft) 172 Stage = IS_EXECUTED; 173 } 174 175 const unsigned WriteRef::INVALID_IID = std::numeric_limits<unsigned>::max(); 176 177 } // namespace mca 178