1 //===----------------------- LSUnit.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 /// A Load-Store Unit for the llvm-mca tool. 12 /// 13 //===----------------------------------------------------------------------===// 14 15 #include "llvm/MCA/HardwareUnits/LSUnit.h" 16 #include "llvm/MCA/Instruction.h" 17 #include "llvm/Support/Debug.h" 18 #include "llvm/Support/raw_ostream.h" 19 20 #define DEBUG_TYPE "llvm-mca" 21 22 namespace llvm { 23 namespace mca { 24 25 LSUnit::LSUnit(const MCSchedModel &SM, unsigned LQ, unsigned SQ, 26 bool AssumeNoAlias) 27 : LQ_Size(LQ), SQ_Size(SQ), NoAlias(AssumeNoAlias) { 28 if (SM.hasExtraProcessorInfo()) { 29 const MCExtraProcessorInfo &EPI = SM.getExtraProcessorInfo(); 30 if (!LQ_Size && EPI.LoadQueueID) { 31 const MCProcResourceDesc &LdQDesc = *SM.getProcResource(EPI.LoadQueueID); 32 LQ_Size = LdQDesc.BufferSize; 33 } 34 35 if (!SQ_Size && EPI.StoreQueueID) { 36 const MCProcResourceDesc &StQDesc = *SM.getProcResource(EPI.StoreQueueID); 37 SQ_Size = StQDesc.BufferSize; 38 } 39 } 40 } 41 42 #ifndef NDEBUG 43 void LSUnit::dump() const { 44 dbgs() << "[LSUnit] LQ_Size = " << LQ_Size << '\n'; 45 dbgs() << "[LSUnit] SQ_Size = " << SQ_Size << '\n'; 46 dbgs() << "[LSUnit] NextLQSlotIdx = " << LoadQueue.size() << '\n'; 47 dbgs() << "[LSUnit] NextSQSlotIdx = " << StoreQueue.size() << '\n'; 48 } 49 #endif 50 51 void LSUnit::assignLQSlot(unsigned Index) { 52 assert(!isLQFull()); 53 assert(LoadQueue.count(Index) == 0); 54 55 LLVM_DEBUG(dbgs() << "[LSUnit] - AssignLQSlot <Idx=" << Index 56 << ",slot=" << LoadQueue.size() << ">\n"); 57 LoadQueue.insert(Index); 58 } 59 60 void LSUnit::assignSQSlot(unsigned Index) { 61 assert(!isSQFull()); 62 assert(StoreQueue.count(Index) == 0); 63 64 LLVM_DEBUG(dbgs() << "[LSUnit] - AssignSQSlot <Idx=" << Index 65 << ",slot=" << StoreQueue.size() << ">\n"); 66 StoreQueue.insert(Index); 67 } 68 69 void LSUnit::dispatch(const InstRef &IR) { 70 const InstrDesc &Desc = IR.getInstruction()->getDesc(); 71 unsigned IsMemBarrier = Desc.HasSideEffects; 72 assert((Desc.MayLoad || Desc.MayStore) && "Not a memory operation!"); 73 74 const unsigned Index = IR.getSourceIndex(); 75 if (Desc.MayLoad) { 76 if (IsMemBarrier) 77 LoadBarriers.insert(Index); 78 assignLQSlot(Index); 79 } 80 81 if (Desc.MayStore) { 82 if (IsMemBarrier) 83 StoreBarriers.insert(Index); 84 assignSQSlot(Index); 85 } 86 } 87 88 LSUnit::Status LSUnit::isAvailable(const InstRef &IR) const { 89 const InstrDesc &Desc = IR.getInstruction()->getDesc(); 90 if (Desc.MayLoad && isLQFull()) 91 return LSUnit::LSU_LQUEUE_FULL; 92 if (Desc.MayStore && isSQFull()) 93 return LSUnit::LSU_SQUEUE_FULL; 94 return LSUnit::LSU_AVAILABLE; 95 } 96 97 bool LSUnit::isReady(const InstRef &IR) const { 98 const InstrDesc &Desc = IR.getInstruction()->getDesc(); 99 const unsigned Index = IR.getSourceIndex(); 100 bool IsALoad = Desc.MayLoad; 101 bool IsAStore = Desc.MayStore; 102 assert((IsALoad || IsAStore) && "Not a memory operation!"); 103 assert((!IsALoad || LoadQueue.count(Index) == 1) && "Load not in queue!"); 104 assert((!IsAStore || StoreQueue.count(Index) == 1) && "Store not in queue!"); 105 106 if (IsALoad && !LoadBarriers.empty()) { 107 unsigned LoadBarrierIndex = *LoadBarriers.begin(); 108 // A younger load cannot pass a older load barrier. 109 if (Index > LoadBarrierIndex) 110 return false; 111 // A load barrier cannot pass a older load. 112 if (Index == LoadBarrierIndex && Index != *LoadQueue.begin()) 113 return false; 114 } 115 116 if (IsAStore && !StoreBarriers.empty()) { 117 unsigned StoreBarrierIndex = *StoreBarriers.begin(); 118 // A younger store cannot pass a older store barrier. 119 if (Index > StoreBarrierIndex) 120 return false; 121 // A store barrier cannot pass a older store. 122 if (Index == StoreBarrierIndex && Index != *StoreQueue.begin()) 123 return false; 124 } 125 126 // A load may not pass a previous store unless flag 'NoAlias' is set. 127 // A load may pass a previous load. 128 if (NoAlias && IsALoad) 129 return true; 130 131 if (StoreQueue.size()) { 132 // A load may not pass a previous store. 133 // A store may not pass a previous store. 134 if (Index > *StoreQueue.begin()) 135 return false; 136 } 137 138 // Okay, we are older than the oldest store in the queue. 139 // If there are no pending loads, then we can say for sure that this 140 // instruction is ready. 141 if (isLQEmpty()) 142 return true; 143 144 // Check if there are no older loads. 145 if (Index <= *LoadQueue.begin()) 146 return true; 147 148 // There is at least one younger load. 149 // 150 // A store may not pass a previous load. 151 // A load may pass a previous load. 152 return !IsAStore; 153 } 154 155 void LSUnit::onInstructionExecuted(const InstRef &IR) { 156 const InstrDesc &Desc = IR.getInstruction()->getDesc(); 157 const unsigned Index = IR.getSourceIndex(); 158 bool IsALoad = Desc.MayLoad; 159 bool IsAStore = Desc.MayStore; 160 161 if (IsALoad) { 162 if (LoadQueue.erase(Index)) { 163 LLVM_DEBUG(dbgs() << "[LSUnit]: Instruction idx=" << Index 164 << " has been removed from the load queue.\n"); 165 } 166 if (!LoadBarriers.empty() && Index == *LoadBarriers.begin()) { 167 LLVM_DEBUG( 168 dbgs() << "[LSUnit]: Instruction idx=" << Index 169 << " has been removed from the set of load barriers.\n"); 170 LoadBarriers.erase(Index); 171 } 172 } 173 174 if (IsAStore) { 175 if (StoreQueue.erase(Index)) { 176 LLVM_DEBUG(dbgs() << "[LSUnit]: Instruction idx=" << Index 177 << " has been removed from the store queue.\n"); 178 } 179 180 if (!StoreBarriers.empty() && Index == *StoreBarriers.begin()) { 181 LLVM_DEBUG( 182 dbgs() << "[LSUnit]: Instruction idx=" << Index 183 << " has been removed from the set of store barriers.\n"); 184 StoreBarriers.erase(Index); 185 } 186 } 187 } 188 189 } // namespace mca 190 } // namespace llvm 191